diff --git a/lua/core/util.lua b/lua/core/util.lua index 0a27025aae20f0065e4c69fd25003b5a5bd16f8a..6ef869c361c648743eae4fa08ff52c00227d90fb 100644 --- a/lua/core/util.lua +++ b/lua/core/util.lua @@ -730,4 +730,15 @@ function AimGroup:getCancelledTargets(aimGroup) return aimGroup[AimGroup.Cancelled] end +---@param target ServerPlayer +---@param data AimStruct +---@return boolean +function AimGroup:isOnlyTarget(target, data) + if data.tos == nil then return false end + local tos = AimGroup:getAllTargets(data.tos) + return table.contains(tos, target.id) and not table.find(target.room.alive_players, function (p) + return p ~= target and table.contains(tos, p.id) + end) +end + return { TargetGroup, AimGroup, Util } diff --git a/lua/server/event.lua b/lua/server/event.lua index 78fe463aa1f40fd473914034ff67c493db12c8a7..80cc9194bf3bfb42a1f76ee9757c20abe8c84171 100644 --- a/lua/server/event.lua +++ b/lua/server/event.lua @@ -48,6 +48,7 @@ fk.FinishJudge = 27 fk.RoundStart = 28 fk.RoundEnd = 29 +fk.AfterRoundEnd = 85 fk.BeforeTurnOver = 79 fk.TurnedOver = 30 @@ -126,7 +127,7 @@ fk.AfterSkillEffect = 82 -- 83 = PreTurnStart -- 84 = AfterTurnEnd --- 85 = xxx +-- 85 = AfterRoundEnd -- 86 = AfterPhaseEnd fk.AreaAborted = 87 diff --git a/lua/server/events/gameflow.lua b/lua/server/events/gameflow.lua index 3c36e6b15a820ad58f3cd6ce2111483ba1f3e524..e53ee51785ca7edd9ef8734bc3c4f766422583cd 100644 --- a/lua/server/events/gameflow.lua +++ b/lua/server/events/gameflow.lua @@ -101,28 +101,22 @@ local Round = GameEvent:subclass("GameEvent.Round") function Round:action() local room = self.room - local p - local nextTurnOwner - local skipRoundPlus = false - repeat - nextTurnOwner = nil - skipRoundPlus = false - p = room.current - GameEvent.Turn:create(p):exec() + local currentPlayer + + while true do + GameEvent.Turn:create(room.current):exec() if room.game_finished then break end - local changingData = { from = room.current, to = room.current:getNextAlive(true, nil, true), skipRoundPlus = false } + local changingData = { from = room.current, to = room.current.next, skipRoundPlus = false } room.logic:trigger(fk.EventTurnChanging, room.current, changingData, true) - skipRoundPlus = changingData.skipRoundPlus - local nextAlive = room.current:getNextAlive(true, nil, true) - if nextAlive ~= changingData.to and not changingData.to.dead then - room.current = changingData.to - nextTurnOwner = changingData.to + local nextTurnOwner = changingData.to + if room.current.seat > nextTurnOwner.seat and not changingData.skipRoundPlus then + break else - room.current = nextAlive + room.current = nextTurnOwner end - until p.seat >= (nextTurnOwner or p:getNextAlive(true, nil, true)).seat and not skipRoundPlus + end end function Round:main() @@ -153,7 +147,8 @@ function Round:main() logic:trigger(fk.RoundStart, room.current) self:action() - logic:trigger(fk.RoundEnd, p) + logic:trigger(fk.RoundEnd, room.current) + logic:trigger(fk.AfterRoundEnd, room.current) end function Round:clear() @@ -188,7 +183,10 @@ local Turn = GameEvent:subclass("GameEvent.Turn") function Turn:prepare() local room = self.room local logic = room.logic - local player = room.current + local player = self.data[1]---@type ServerPlayer + if self.data[2] == nil then self.data[2] = {} end + local data = self.data[2]---@type TurnStruct + data.reason = data.reason or "game_rule" if player.rest > 0 and player.rest < 999 then room:setPlayerRest(player, player.rest - 1) @@ -208,21 +206,24 @@ function Turn:prepare() return true end - return logic:trigger(fk.BeforeTurnStart, player) + return logic:trigger(fk.BeforeTurnStart, player, data) end function Turn:main() local room = self.room - room.current.phase = Player.PhaseNone - room.logic:trigger(fk.TurnStart, room.current) - room.current.phase = Player.NotActive - room.current:play() + local player = self.data[1]---@type ServerPlayer + local data = self.data[2]---@type TurnStruct + player.phase = Player.PhaseNone + room.logic:trigger(fk.TurnStart, player, data) + player.phase = Player.NotActive + player:play(data.phase_table) end function Turn:clear() local room = self.room + local current = self.data[1]---@type ServerPlayer + local data = self.data[2]---@type TurnStruct - local current = room.current local logic = room.logic if self.interrupted then if current.phase ~= Player.NotActive then @@ -239,8 +240,8 @@ function Turn:clear() end current.phase = Player.PhaseNone - logic:trigger(fk.TurnEnd, current, nil, self.interrupted) - logic:trigger(fk.AfterTurnEnd, current, nil, self.interrupted) + logic:trigger(fk.TurnEnd, current, data, self.interrupted) + logic:trigger(fk.AfterTurnEnd, current, data, self.interrupted) current.phase = Player.NotActive room:setTag("endTurn", false) diff --git a/lua/server/gamelogic.lua b/lua/server/gamelogic.lua index 17f9919f4dffbd781e5695d161b2592eb323e22b..3ee9e5cc7b140e22d6fa0bb10d253d625d85a1dc 100644 --- a/lua/server/gamelogic.lua +++ b/lua/server/gamelogic.lua @@ -269,6 +269,10 @@ function GameLogic:action() while true do execGameEvent(GameEvent.Round) if room.game_finished then break end + local players = table.filter(room.alive_players, function(p) return not p.dead or p.rest > 0 end) + if #players == 0 then room:gameOver("") end + table.sort(players, function(a, b) return a.seat < b.seat end) + room.current = players[1] end end @@ -561,6 +565,7 @@ function GameLogic:getMostRecentEvent(eventType) end --- 如果当前事件刚好是技能生效事件,就返回那个技能名,否则返回空串。 +---@return string|nil function GameLogic:getCurrentSkillName() local skillEvent = self:getCurrentEvent() local ret = nil @@ -596,7 +601,7 @@ function GameLogic:getEventsOfScope(eventType, n, func, scope) end -- 在指定历史范围中找符合条件的事件(逆序) ----@param eventType integer @ 要查找的事件类型 +---@param eventType GameEvent @ 要查找的事件类型 ---@param func fun(e: GameEvent): boolean @ 过滤用的函数 ---@param n integer @ 最多找多少个 ---@param end_id integer @ 查询历史范围:从最后的事件开始逆序查找直到id为end_id的事件(不含) diff --git a/lua/server/serverplayer.lua b/lua/server/serverplayer.lua index 67a1b94c85d5054cddab7d3f2000ad4bc0b77822..9f3f7745f7cd7cc1b99b89ea15319fb00f654362 100644 --- a/lua/server/serverplayer.lua +++ b/lua/server/serverplayer.lua @@ -277,6 +277,9 @@ end function ServerPlayer:play(phase_table) phase_table = phase_table or {} if #phase_table > 0 then + if not table.contains(phase_table, Player.RoundStart) then + table.insert(phase_table, 1, Player.RoundStart) + end if not table.contains(phase_table, Player.NotActive) then table.insert(phase_table, Player.NotActive) end @@ -377,17 +380,19 @@ function ServerPlayer:endCurrentPhase() end --- 获得一个额外回合 ----@param delay? boolean ----@param skillName? string -function ServerPlayer:gainAnExtraTurn(delay, skillName) +---@param delay? boolean @ 是否延迟到当前回合结束再开启额外回合,默认是 +---@param skillName? string @ 额外回合原因 +---@param turnData? TurnStruct @ 额外回合的信息 +function ServerPlayer:gainAnExtraTurn(delay, skillName, turnData) local room = self.room delay = (delay == nil) and true or delay - skillName = (skillName == nil) and room.logic:getCurrentSkillName() or skillName + skillName = skillName or room.logic:getCurrentSkillName() or "game_rule" + turnData = turnData or {} + turnData.reason = skillName if delay then - local logic = room.logic - local turn = logic:getCurrentEvent():findParent(GameEvent.Turn, true) + local turn = room.logic:getCurrentEvent():findParent(GameEvent.Turn, true) if turn then - turn:prependExitFunc(function() self:gainAnExtraTurn(false, skillName) end) + turn:prependExitFunc(function() self:gainAnExtraTurn(false, skillName, turnData) end) return end end @@ -400,13 +405,15 @@ function ServerPlayer:gainAnExtraTurn(delay, skillName) local current = room.current room.current = self - self.tag["_extra_turn_count"] = self.tag["_extra_turn_count"] or {} - local ex_tag = self.tag["_extra_turn_count"] - table.insert(ex_tag, skillName) + room:addTableMark(self, "_extra_turn_count", skillName) - GameEvent.Turn:create(self):exec() + GameEvent.Turn:create(self, turnData):exec() - table.remove(ex_tag) + local mark = self:getTableMark("_extra_turn_count") + if #mark > 0 then + table.remove(mark) + room:setPlayerMark(self, "_extra_turn_count", mark) + end room.current = current end @@ -414,17 +421,14 @@ end --- 当前是否处于额外的回合。 --- @return boolean function ServerPlayer:insideExtraTurn() - return self.tag["_extra_turn_count"] and #self.tag["_extra_turn_count"] > 0 + return self:getCurrentExtraTurnReason() ~= "game_rule" end ---- 当前额外回合的技能原因。 +--- 当前额外回合的技能原因。非额外回合则为game_rule ---@return string function ServerPlayer:getCurrentExtraTurnReason() - local ex_tag = self.tag["_extra_turn_count"] - if (not ex_tag) or #ex_tag == 0 then - return "game_rule" - end - return ex_tag[#ex_tag] + local mark = self:getTableMark("_extra_turn_count") + return mark[#mark] or "game_rule" end --- 角色摸牌。 diff --git a/lua/server/system_enum.lua b/lua/server/system_enum.lua index cb9d3bc3d44ba90d73590e4e3818a91aaf499e1a..3139363291db1c192258ce272cfe97677c0296dc 100644 --- a/lua/server/system_enum.lua +++ b/lua/server/system_enum.lua @@ -246,6 +246,11 @@ fk.IceDamage = 4 ---@field public skillName string @ 技能名 ---@field public fromPlace "top"|"bottom" @ 摸牌的位置 +---@--- TurnStruct 回合事件的数据 +---@class TurnStruct +---@field public reason string? @ 当前额外回合的原因,不为额外回合则为game_rule +---@field public phase_table? Phase[] @ 此回合将进行的阶段,填空则为正常流程 + --- 移动理由 ---@alias CardMoveReason integer fk.ReasonJustMove = 1