From 8b212c2a7aebe3a9f99b6e09f4d65f6d6e550bb1 Mon Sep 17 00:00:00 2001 From: notify <70358032+Notify-ctrl@users.noreply.github.com> Date: Mon, 4 Apr 2022 19:04:55 +0800 Subject: [PATCH] player:play (#15) * player:play * proceed phase * update readme Co-authored-by: Notify-ctrl --- README.md | 24 ++++++- lua/server/serverplayer.lua | 112 ++++++++++++++++++++++++++++++++ packages/standard/game_rule.lua | 48 +++++++++++++- 3 files changed, 180 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 42bdcf2a..b00e925f 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,28 @@ ___ ## 如何构建 -安装Qt Creator和Qt 5.15.2。必要时自行配置CMake。 +以Debian11为例,首先克隆仓库: + +```shell +$ git clone https://github.com/Notify-ctrl/FreeKill +``` + +然后安装编译软件所必需的软件包: + +```shell +$ sudo apt install qtbase5-dev qtdeclarative5-dev qtmultimedia5-dev qml-module-qtquick2 qml-module-qtquick-controls2 qml-module-qtquick-window2 qml-module-qtquick-layouts qml-module-qtgraphicaleffects cmake swig lua5.4 sqlite3 +``` + +然后编译运行即可。 + +```shell +$ mkdir build && cd build +$ cmake .. && make +$ cp src/FreeKill .. +$ cd .. +$ ./FreeKill +``` + +对于Windows用户,建议安装Qt Creator和Qt 5.15.2。必要时自行配置CMake。 然后下载swig,并为其配置环境变量,即可构建FreeKill。 diff --git a/lua/server/serverplayer.lua b/lua/server/serverplayer.lua index 5627d282..cea10be3 100644 --- a/lua/server/serverplayer.lua +++ b/lua/server/serverplayer.lua @@ -6,6 +6,9 @@ ---@field client_reply string ---@field default_reply string ---@field reply_ready boolean +---@field phases Phase[] +---@field phase_state table[] +---@field phase_index integer local ServerPlayer = Player:subclass("ServerPlayer") function ServerPlayer:initialize(_self) @@ -21,6 +24,7 @@ function ServerPlayer:initialize(_self) self.client_reply = "" self.default_reply = "" self.reply_ready = false + self.phases = {} end ---@return integer @@ -94,4 +98,112 @@ function ServerPlayer:turnOver() self.room.logic:trigger(fk.TurnedOver, self) end +---@param from_phase Phase +---@param to_phase Phase +function ServerPlayer:changePhase(from_phase, to_phase) + local room = self.room + local logic = room.logic + self.phase = Player.PhaseNone + + local phase_change = { + from = from_phase, + to = to_phase + } + + local skip = logic:trigger(fk.EventPhaseChanging, self, phase_change) + if skip and to_phase ~= Player.NotActive then + self.phase = from_phase + return true + end + + self.phase = to_phase + room:notifyProperty(self, self, "phase") + + if #self.phases > 0 then + table.remove(self.phases, 1) + end + + if not logic:trigger(fk.EventPhaseStart, self) then + if self.phase ~= Player.NotActive then + logic:trigger(fk.EventPhaseProceeding, self) + end + end + + if self.phase ~= Player.NotActive then + logic:trigger(fk.EventPhaseEnd, self) + end + + return false +end + +---@param phase_table Phase[] +function ServerPlayer:play(phase_table) + phase_table = phase_table or {} + if #phase_table > 0 then + if not table.contains(phase_table, Player.NotActive) then + table.insert(phase_table, Player.NotActive) + end + else + phase_table = { + Player.RoundStart, Player.Start, + Player.Judge, Player.Draw, Player.Play, Player.Discard, + Player.Finish, Player.NotActive, + } + end + + self.phases = phase_table + self.phase_state = {} + + local phases = self.phases + local phase_state = self.phase_state + local room = self.room + + for i = 1, #phases do + phase_state[i] = { + phase = phases[i], + skipped = false + } + end + + for i = 1, #phases do + if self.dead then + self:changePhase(self.phase, Player.NotActive) + break + end + + self.phase_index = i + local phase_change = { + from = self.phase, + to = phases[i] + } + + local logic = self.room.logic + self.phase = Player.PhaseNone + + local skip = logic:trigger(fk.EventPhaseChanging, self, phase_change) + phases[i] = phase_change.to + phase_state[i].phase = phases[i] + + self.phase = phases[i] + room:notifyProperty(self, self, "phase") + + local cancel_skip = true + if phases[i] ~= Player.NotActive and (phase_state[i].skipped or skip) then + cancel_skip = logic:trigger(fk.EventPhaseSkipping, self) + end + + if (not skip) or (cancel_skip) then + if not logic:trigger(fk.EventPhaseStart, self) then + if self.phase ~= Player.NotActive then + logic:trigger(fk.EventPhaseProceeding, self) + end + end + + if self.phase ~= Player.NotActive then + logic:trigger(fk.EventPhaseEnd, self) + else break end + end + end +end + return ServerPlayer diff --git a/packages/standard/game_rule.lua b/packages/standard/game_rule.lua index 1a9706c6..508fe04c 100644 --- a/packages/standard/game_rule.lua +++ b/packages/standard/game_rule.lua @@ -36,15 +36,57 @@ GameRule = fk.CreateTriggerSkill{ -- TODO: send log player:addMark("Global_TurnCount") - player:setMark("damage_point_round", 0) if not player.faceup then player:setFlag("-Global_FirstRound") player:turnOver() elseif not player.dead then - --player:play() - room:askForSkillInvoke(player, "rule") + player:play() end end, + [fk.EventPhaseProceeding] = function() + switch(player.phase, { + [Player.PhaseNone] = function() + error("You should never proceed PhaseNone") + end, + [Player.RoundStart] = function() + print("Proceeding RoundStart.") + end, + [Player.Start] = function() + print("Proceeding Start.") + end, + [Player.Judge] = function() + print("Proceeding Judge.") + end, + [Player.Draw] = function() + print("Proceeding Draw.") + end, + [Player.Play] = function() + print("Proceeding Play.") + room:askForSkillInvoke(player, "rule") + end, + [Player.Discard] = function() + print("Proceeding Discard.") + end, + [Player.Finish] = function() + print("Proceeding Finish.") + end, + [Player.NotActive] = function() + print("Proceeding NotActive.") + end, + }) + end, + [fk.EventPhaseEnd] = function() + if player.phase == Player.Play then + -- TODO: clear history + end + end, + [fk.EventPhaseChanging] = function() + -- TODO: copy but dont copy all + end, + default = function() + print("game_rule: Event=" .. event) + room:askForSkillInvoke(player, "rule") + end, }) return false end,