Recorder (#178)
提供了一个简单的事件记录器机制和一个功能简单的查询函数。 在GameEvent的clear环节中,先执行默认的clear函数,再执行用户自订的clear函数。
This commit is contained in:
parent
73fcb765d4
commit
713bbca17a
|
@ -167,10 +167,6 @@
|
|||
<source>updated packages for md5</source>
|
||||
<translation>已为您与服务器同步拓展包,请尝试再次连入</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure to exit?</source>
|
||||
<translation>是否确认退出?</translation>
|
||||
</message>
|
||||
</context>
|
||||
|
||||
<context>
|
||||
|
@ -179,6 +175,10 @@
|
|||
<source>FreeKill</source>
|
||||
<translation>新月杀</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure to exit?</source>
|
||||
<translation>是否确认退出?</translation>
|
||||
</message>
|
||||
</context>
|
||||
|
||||
<context>
|
||||
|
|
|
@ -303,6 +303,7 @@ Fk:loadTranslationTable{
|
|||
-- phase
|
||||
["#PhaseSkipped"] = "%from 跳过了 %arg",
|
||||
["#GainAnExtraTurn"] = "%from 开始进行一个额外的回合",
|
||||
["#GainAnExtraPhase"] = "%from 开始进行一个额外的 %arg",
|
||||
|
||||
-- useCard
|
||||
["#UseCard"] = "%from 使用了牌 %card",
|
||||
|
|
|
@ -59,6 +59,10 @@ function General:initialize(package, name, kingdom, hp, maxHp, gender)
|
|||
package:addGeneral(self)
|
||||
end
|
||||
|
||||
function General:__tostring()
|
||||
return string.format("<General %s>", self.name)
|
||||
end
|
||||
|
||||
--- 为武将增加技能,需要注意增加其他武将技能时的处理方式。
|
||||
---@param skill Skill @ (单个)武将技能
|
||||
function General:addSkill(skill)
|
||||
|
|
|
@ -444,6 +444,18 @@ function Player:inMyAttackRange(other, fixLimit)
|
|||
return self:distanceTo(other) <= (baseAttackRange + fixLimit)
|
||||
end
|
||||
|
||||
function Player:getNextAlive()
|
||||
if Fk:currentRoom().alive_players == 0 then
|
||||
return self
|
||||
end
|
||||
|
||||
local ret = self.next
|
||||
while ret.dead do
|
||||
ret = ret.next
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
--- 增加玩家使用特定牌的历史次数。
|
||||
---@param cardName string @ 牌名
|
||||
---@param num integer @ 次数
|
||||
|
|
|
@ -1,6 +1,32 @@
|
|||
-- SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
local Util = {}
|
||||
Util.DummyFunc = function() end
|
||||
Util.DummyTable = setmetatable({}, {
|
||||
__newindex = function() error("Cannot assign to dummy table") end
|
||||
})
|
||||
|
||||
local metamethods = {
|
||||
"__add", "__sub", "__mul", "__div", "__mod", "__pow", "__unm", "__idiv",
|
||||
"__band", "__bor", "__bxor", "__bnot", "__shl", "__shr",
|
||||
"__concat", "__len", "__eq", "__lt", "__le", "__call",
|
||||
-- "__index", "__newindex",
|
||||
}
|
||||
-- 别对类用 暂且会弄坏isSubclassOf 懒得研究先
|
||||
Util.lockTable = function(t)
|
||||
local mt = getmetatable(t) or Util.DummyTable
|
||||
local new_mt = {
|
||||
__index = t,
|
||||
__newindex = function() error("Cannot assign to locked table") end,
|
||||
__metatable = false,
|
||||
}
|
||||
for _, e in ipairs(metamethods) do
|
||||
new_mt[e] = mt[e]
|
||||
end
|
||||
return setmetatable({}, new_mt)
|
||||
end
|
||||
|
||||
function printf(fmt, ...) print(string.format(fmt, ...)) end
|
||||
|
||||
-- the iterator of QList object
|
||||
local qlist_iterator = function(list, n)
|
||||
|
@ -150,13 +176,13 @@ function table.simpleClone(self)
|
|||
return ret
|
||||
end
|
||||
|
||||
-- similar to table.clone but convert all class/instances to string
|
||||
-- similar to table.clone but not clone class/instances
|
||||
function table.cloneWithoutClass(self)
|
||||
local ret = {}
|
||||
for k, v in pairs(self) do
|
||||
if type(v) == "table" then
|
||||
if v.class or v.super then
|
||||
ret[k] = tostring(v)
|
||||
ret[k] = v
|
||||
else
|
||||
ret[k] = table.cloneWithoutClass(v)
|
||||
end
|
||||
|
|
|
@ -77,6 +77,9 @@ local function _call(self, ...) return self:new(...) end
|
|||
local function _createClass(name, super)
|
||||
local dict = {}
|
||||
dict.__index = dict
|
||||
--[[ debug
|
||||
dict.__gc = function(t) printf("%s destructed", tostring(t)) end
|
||||
--]]
|
||||
|
||||
local aClass = { name = name, super = super, static = {},
|
||||
__instanceDict = dict, __declaredMethods = {},
|
||||
|
|
|
@ -111,4 +111,7 @@ fk.CardShown = 77
|
|||
-- 79 = BeforeTurnOver
|
||||
-- 80 = BeforeChainStateChange
|
||||
|
||||
fk.NumOfEvents = 81
|
||||
fk.SkillEffect = 81
|
||||
fk.AfterSkillEffect = 82
|
||||
|
||||
fk.NumOfEvents = 83
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
-- Definitions of game events
|
||||
|
||||
-- 某类事件对应的结束事件,其id刚好就是那个事件的相反数
|
||||
-- GameEvent.EventFinish = -1
|
||||
|
||||
GameEvent.ChangeHp = 1
|
||||
GameEvent.Damage = 2
|
||||
GameEvent.LoseHp = 3
|
||||
|
|
|
@ -1,6 +1,16 @@
|
|||
-- SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
GameEvent.functions[GameEvent.SkillEffect] = function(self)
|
||||
local effect_cb = table.unpack(self.data)
|
||||
return effect_cb()
|
||||
local effect_cb, player, skill = table.unpack(self.data)
|
||||
local room = self.room
|
||||
local logic = room.logic
|
||||
|
||||
local cost_data_bak = skill.cost_data
|
||||
logic:trigger(fk.SkillEffect, player, skill)
|
||||
skill.cost_data = cost_data_bak
|
||||
|
||||
local ret = effect_cb()
|
||||
|
||||
logic:trigger(fk.AfterSkillEffect, player, skill)
|
||||
return ret
|
||||
end
|
||||
|
|
|
@ -1,40 +1,70 @@
|
|||
-- SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
---@class GameEvent: Object
|
||||
---@field public room Room
|
||||
---@field public event integer
|
||||
---@field public data any
|
||||
---@field public parent GameEvent
|
||||
---@field public main_func fun(self: GameEvent)
|
||||
---@field public clear_func fun(self: GameEvent)
|
||||
---@field public extra_clear_funcs any[]
|
||||
---@field public interrupted boolean
|
||||
---@field public id integer @ 事件的id,随着时间推移自动增加并分配给新事件
|
||||
---@field public end_id integer @ 事件的对应结束id,如果整个事件中未插入事件,那么end_id就是自己的id
|
||||
---@field public room Room @ room实例
|
||||
---@field public event integer @ 该事件对应的EventType
|
||||
---@field public data any @ 事件的附加数据,视类型而定
|
||||
---@field public parent GameEvent @ 事件的父事件(栈中的上一层事件)
|
||||
---@field public main_func fun(self: GameEvent) @ 事件的主函数
|
||||
---@field public clear_func fun(self: GameEvent) @ 事件结束时执行的函数
|
||||
---@field public extra_clear_funcs fun(self:GameEvent)[] @ 事件结束时执行的自定义函数列表
|
||||
---@field public exit_func fun(self: GameEvent) @ 事件结束后执行的函数
|
||||
---@field public extra_exit_funcs fun(self:GameEvent)[] @ 事件结束后执行的自定义函数
|
||||
---@field public interrupted boolean @ 事件是否是因为被强行中断而结束的
|
||||
local GameEvent = class("GameEvent")
|
||||
|
||||
---@type fun(self: GameEvent)[]
|
||||
GameEvent.functions = {}
|
||||
|
||||
---@type fun(self: GameEvent)[]
|
||||
GameEvent.cleaners = {}
|
||||
|
||||
---@type fun(self: GameEvent)[]
|
||||
GameEvent.exit_funcs = {}
|
||||
|
||||
local function wrapCoFunc(f, ...)
|
||||
if not f then return nil end
|
||||
local args = {...}
|
||||
return function() return f(table.unpack(args)) end
|
||||
end
|
||||
local function dummyFunc() end
|
||||
local dummyFunc = Util.DummyFunc
|
||||
|
||||
function GameEvent:initialize(event, ...)
|
||||
self.id = -1
|
||||
self.end_id = -1
|
||||
self.room = RoomInstance
|
||||
self.event = event
|
||||
self.data = { ... }
|
||||
self.main_func = wrapCoFunc(GameEvent.functions[event], self) or dummyFunc
|
||||
self.clear_func = GameEvent.cleaners[event] or dummyFunc
|
||||
self.extra_clear_funcs = {}
|
||||
self.extra_clear_funcs = Util.DummyTable
|
||||
self.exit_func = GameEvent.exit_funcs[event] or dummyFunc
|
||||
self.extra_exit_funcs = Util.DummyTable
|
||||
self.interrupted = false
|
||||
end
|
||||
|
||||
function GameEvent:__tostring()
|
||||
return GameEvent:translate(self.event)
|
||||
return string.format("<%s #%d>", GameEvent:translate(self.event), self.id)
|
||||
end
|
||||
|
||||
function GameEvent:findParent(eventType)
|
||||
function GameEvent:addCleaner(f)
|
||||
if self.extra_clear_funcs == Util.DummyTable then
|
||||
self.extra_clear_funcs = {}
|
||||
end
|
||||
table.insert(self.extra_clear_funcs, f)
|
||||
end
|
||||
|
||||
function GameEvent:addExitFunc(f)
|
||||
if self.extra_exit_funcs == Util.DummyTable then
|
||||
self.extra_exit_funcs = {}
|
||||
end
|
||||
table.insert(self.extra_exit_funcs, f)
|
||||
end
|
||||
|
||||
function GameEvent:findParent(eventType, includeSelf)
|
||||
if includeSelf and self.event == eventType then return self end
|
||||
local e = self.parent
|
||||
repeat
|
||||
if e.event == eventType then return e end
|
||||
|
@ -43,12 +73,83 @@ function GameEvent:findParent(eventType)
|
|||
return nil
|
||||
end
|
||||
|
||||
-- 找n个id介于from和to之间的事件。
|
||||
local function bin_search(events, from, to, n, func)
|
||||
local left = 1
|
||||
local right = #events
|
||||
local mid
|
||||
local ret = {}
|
||||
|
||||
if from < events[1].id then
|
||||
mid = 1
|
||||
elseif from > events[right].id then
|
||||
return ret
|
||||
else
|
||||
while true do
|
||||
if left > right then return ret end
|
||||
mid = (left + right) // 2
|
||||
local id = events[mid].id
|
||||
local id_left = mid == 1 and -math.huge or events[mid - 1].id
|
||||
|
||||
if from < id then
|
||||
if from >= id_left then
|
||||
break
|
||||
end
|
||||
right = mid - 1
|
||||
else
|
||||
left = mid + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for i = mid, #events do
|
||||
local v = events[i]
|
||||
if v.id < to and func(v) then
|
||||
table.insert(ret, v)
|
||||
end
|
||||
if #ret >= n then break end
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
-- 从某个区间中,找出类型符合且符合func函数检测的至多n个事件。
|
||||
---@param eventType integer @ 要查找的事件类型
|
||||
---@param n integer @ 最多找多少个
|
||||
---@param func fun(e: GameEvent): boolean @ 过滤用的函数
|
||||
---@param endEvent GameEvent|nil @ 区间终止点,默认为本事件结束
|
||||
---@return GameEvent[] @ 找到的符合条件的所有事件,最多n个但不保证有n个
|
||||
function GameEvent:searchEvents(eventType, n, func, endEvent)
|
||||
local logic = self.room.logic
|
||||
local events = logic.event_recorder[eventType]
|
||||
local from = self.id
|
||||
local to = endEvent and endEvent.id or self.end_id
|
||||
if to == -1 then to = #logic.all_game_events end
|
||||
n = n or 1
|
||||
func = func or function() return true end
|
||||
|
||||
local ret
|
||||
if #events < 6 then
|
||||
ret = {}
|
||||
for _, v in ipairs(events) do
|
||||
if v.id > from and v.id < to and func(v) then
|
||||
table.insert(ret, v)
|
||||
end
|
||||
if #ret >= n then break end
|
||||
end
|
||||
else
|
||||
ret = bin_search(events, from, to, n, func)
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
function GameEvent:clear()
|
||||
local clear_co = coroutine.create(function()
|
||||
self:clear_func()
|
||||
for _, f in ipairs(self.extra_clear_funcs) do
|
||||
if type(f) == "function" then f(self) end
|
||||
end
|
||||
self:clear_func()
|
||||
end)
|
||||
|
||||
while true do
|
||||
|
@ -72,6 +173,28 @@ function GameEvent:clear()
|
|||
break
|
||||
end
|
||||
end
|
||||
|
||||
local logic = RoomInstance.logic
|
||||
local end_id = logic.current_event_id + 1
|
||||
if self.id ~= end_id - 1 then
|
||||
logic.all_game_events[end_id] = -self.event
|
||||
logic.current_event_id = end_id
|
||||
self.end_id = end_id
|
||||
else
|
||||
self.end_id = self.id
|
||||
end
|
||||
|
||||
logic.game_event_stack:pop()
|
||||
|
||||
local err, msg
|
||||
err, msg = xpcall(self.exit_func, debug.traceback, self)
|
||||
if err == false then fk.qCritical(msg) end
|
||||
for _, f in ipairs(self.extra_exit_funcs) do
|
||||
if type(f) == "function" then
|
||||
err, msg = xpcall(f, debug.traceback, self)
|
||||
if err == false then fk.qCritical(msg) end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function breakEvent(self, extra_yield_result)
|
||||
|
@ -95,6 +218,12 @@ function GameEvent:exec()
|
|||
self.parent = logic:getCurrentEvent()
|
||||
logic.game_event_stack:push(self)
|
||||
|
||||
logic.current_event_id = logic.current_event_id + 1
|
||||
self.id = logic.current_event_id
|
||||
logic.all_game_events[self.id] = self
|
||||
logic.event_recorder[self.event] = logic.event_recorder[self.event] or {}
|
||||
table.insert(logic.event_recorder[self.event], self)
|
||||
|
||||
local co = coroutine.create(self.main_func)
|
||||
while true do
|
||||
local err, yield_result, extra_yield_result = coroutine.resume(co)
|
||||
|
@ -123,7 +252,7 @@ function GameEvent:exec()
|
|||
-- yield to corresponding GameEvent, first pop self from stack
|
||||
self.interrupted = true
|
||||
self:clear()
|
||||
logic.game_event_stack:pop(self)
|
||||
-- logic.game_event_stack:pop(self)
|
||||
coroutine.close(co)
|
||||
|
||||
-- then, call yield
|
||||
|
@ -151,7 +280,6 @@ function GameEvent:exec()
|
|||
end
|
||||
end
|
||||
|
||||
logic.game_event_stack:pop(self)
|
||||
return ret, extra_ret
|
||||
end
|
||||
|
||||
|
|
|
@ -3,12 +3,14 @@
|
|||
---@class GameLogic: Object
|
||||
---@field public room Room
|
||||
---@field public skill_table table<Event, TriggerSkill[]>
|
||||
---@field public skill_priority_table<Event, number[]>
|
||||
---@field public skill_priority_table table<Event, number[]>
|
||||
---@field public refresh_skill_table table<Event, TriggerSkill[]>
|
||||
---@field public skills string[]
|
||||
---@field public event_stack Stack
|
||||
---@field public game_event_stack Stack
|
||||
---@field public role_table string[][]
|
||||
---@field public all_game_events GameEvent[]
|
||||
---@field public event_recorder table<integer, GameEvent>
|
||||
---@field public current_event_id integer
|
||||
local GameLogic = class("GameLogic")
|
||||
|
||||
function GameLogic:initialize(room)
|
||||
|
@ -17,8 +19,10 @@ function GameLogic:initialize(room)
|
|||
self.skill_priority_table = {}
|
||||
self.refresh_skill_table = {}
|
||||
self.skills = {} -- skillName[]
|
||||
self.event_stack = Stack:new()
|
||||
self.game_event_stack = Stack:new()
|
||||
self.all_game_events = {}
|
||||
self.event_recorder = {}
|
||||
self.current_event_id = 0
|
||||
|
||||
self.role_table = {
|
||||
{ "lord" },
|
||||
|
@ -381,8 +385,6 @@ function GameLogic:trigger(event, target, data, refresh_only)
|
|||
local _target = room.current -- for iteration
|
||||
local player = _target
|
||||
|
||||
self.event_stack:push({event, target, data})
|
||||
|
||||
if #skills_to_refresh > 0 then repeat do
|
||||
-- refresh skills. This should not be broken
|
||||
for _, skill in ipairs(skills_to_refresh) do
|
||||
|
@ -450,7 +452,6 @@ function GameLogic:trigger(event, target, data, refresh_only)
|
|||
::trigger_loop_continue::
|
||||
end
|
||||
|
||||
self.event_stack:pop()
|
||||
return broken
|
||||
end
|
||||
|
||||
|
@ -459,6 +460,29 @@ function GameLogic:getCurrentEvent()
|
|||
return self.game_event_stack.t[self.game_event_stack.p]
|
||||
end
|
||||
|
||||
-- 在指定历史范围中找至多n个符合条件的事件
|
||||
---@param eventType integer @ 要查找的事件类型
|
||||
---@param n integer @ 最多找多少个
|
||||
---@param func fun(e: GameEvent): boolean @ 过滤用的函数
|
||||
---@param scope integer @ 查询历史范围,只能是当前阶段/回合/轮次
|
||||
---@return GameEvent[] @ 找到的符合条件的所有事件,最多n个但不保证有n个
|
||||
function GameLogic:getEventsOfScope(eventType, n, func, scope)
|
||||
scope = scope or Player.HistoryTurn
|
||||
local event = self:getCurrentEvent()
|
||||
local start_event ---@type GameEvent
|
||||
if scope == Player.HistoryGame then
|
||||
start_event = self.all_game_events[1]
|
||||
elseif scope == Player.HistoryRound then
|
||||
start_event = event:findParent(GameEvent.Round)
|
||||
elseif scope == Player.HistoryTurn then
|
||||
start_event = event:findParent(GameEvent.Turn)
|
||||
elseif scope == Player.HistoryPhase then
|
||||
start_event = event:findParent(GameEvent.Phase)
|
||||
end
|
||||
|
||||
return start_event:searchEvents(eventType, n, func)
|
||||
end
|
||||
|
||||
function GameLogic:dumpEventStack(detailed)
|
||||
local top = self:getCurrentEvent()
|
||||
local i = self.game_event_stack.p
|
||||
|
@ -493,6 +517,28 @@ function GameLogic:dumpEventStack(detailed)
|
|||
print("\n===== End of event stack dump =====")
|
||||
end
|
||||
|
||||
function GameLogic:dumpAllEvents(from, to)
|
||||
from = from or 1
|
||||
to = to or #self.all_game_events
|
||||
assert(from <= to)
|
||||
|
||||
local indent = 0
|
||||
local tab = " "
|
||||
for i = from, to, 1 do
|
||||
local v = self.all_game_events[i]
|
||||
if type(v) == "number" then
|
||||
indent = math.max(indent - 1, 0)
|
||||
-- v = "End"
|
||||
-- print(tab:rep(indent) .. string.format("#%d: %s", i, v))
|
||||
else
|
||||
print(tab:rep(indent) .. string.format("%s", tostring(v)))
|
||||
if v.id ~= v.end_id then
|
||||
indent = indent + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function GameLogic:breakEvent(ret)
|
||||
coroutine.yield("__breakEvent", ret)
|
||||
end
|
||||
|
|
|
@ -62,8 +62,7 @@ dofile "lua/server/ai/init.lua"
|
|||
---@param _room fk.Room
|
||||
function Room:initialize(_room)
|
||||
self.room = _room
|
||||
|
||||
self.room.startGame = function(_self)
|
||||
_room.startGame = function(_self)
|
||||
Room.initialize(self, _room) -- clear old data
|
||||
self.settings = json.decode(_room:settings())
|
||||
Fk.disabled_packs = self.settings.disabledPack
|
||||
|
@ -1387,7 +1386,7 @@ function Room:handleUseCardReply(player, data)
|
|||
Self = player
|
||||
local c = skill:viewAs(selected_cards)
|
||||
if c then
|
||||
self:useSkill(player, skill)
|
||||
self:useSkill(player, skill, Util.DummyFunc)
|
||||
|
||||
local use = {} ---@type CardUseStruct
|
||||
use.from = player.id
|
||||
|
@ -2177,7 +2176,7 @@ function Room:handleCardEffect(event, cardEffectEvent)
|
|||
if cardEffectEvent.card.skill then
|
||||
execGameEvent(GameEvent.SkillEffect, function ()
|
||||
cardEffectEvent.card.skill:onEffect(self, cardEffectEvent)
|
||||
end)
|
||||
end, self:getPlayerById(cardEffectEvent.from), cardEffectEvent.card.skill)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -2691,7 +2690,7 @@ function Room:useSkill(player, skill, effect_cb)
|
|||
player:addSkillUseHistory(skill.name)
|
||||
|
||||
if effect_cb then
|
||||
return execGameEvent(GameEvent.SkillEffect, effect_cb)
|
||||
return execGameEvent(GameEvent.SkillEffect, effect_cb, player, skill)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -322,18 +322,6 @@ function ServerPlayer:isAlive()
|
|||
return self.dead == false
|
||||
end
|
||||
|
||||
function ServerPlayer:getNextAlive()
|
||||
if #self.room.alive_players == 0 then
|
||||
return self
|
||||
end
|
||||
|
||||
local ret = self.next
|
||||
while ret.dead do
|
||||
ret = ret.next
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
function ServerPlayer:turnOver()
|
||||
if self.room.logic:trigger(fk.BeforeTurnOver, self) then
|
||||
return
|
||||
|
@ -367,6 +355,13 @@ function ServerPlayer:showCards(cards)
|
|||
room.logic:trigger(fk.CardShown, self, { cardIds = cards })
|
||||
end
|
||||
|
||||
local phase_name_table = {
|
||||
[Player.Judge] = "phase_judge",
|
||||
[Player.Draw] = "phase_draw",
|
||||
[Player.Play] = "phase_play",
|
||||
[Player.Discard] = "phase_discard",
|
||||
}
|
||||
|
||||
---@param from_phase Phase
|
||||
---@param to_phase Phase
|
||||
function ServerPlayer:changePhase(from_phase, to_phase)
|
||||
|
@ -397,25 +392,35 @@ function ServerPlayer:changePhase(from_phase, to_phase)
|
|||
return false
|
||||
end
|
||||
|
||||
function ServerPlayer:gainAnExtraPhase(phase)
|
||||
function ServerPlayer:gainAnExtraPhase(phase, delay)
|
||||
local room = self.room
|
||||
delay = (delay == nil) and true or delay
|
||||
if delay then
|
||||
local logic = room.logic
|
||||
local turn = logic:getCurrentEvent():findParent(GameEvent.Phase, true)
|
||||
if turn then
|
||||
turn:addExitFunc(function() self:gainAnExtraPhase(phase, false) end)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local current = self.phase
|
||||
self.phase = phase
|
||||
room:notifyProperty(self, self, "phase")
|
||||
|
||||
room:sendLog{
|
||||
type = "#GainAnExtraPhase",
|
||||
from = self.id,
|
||||
arg = phase_name_table[phase],
|
||||
}
|
||||
|
||||
|
||||
GameEvent(GameEvent.Phase, self):exec()
|
||||
|
||||
self.phase = current
|
||||
room:notifyProperty(self, self, "phase")
|
||||
end
|
||||
|
||||
local phase_name_table = {
|
||||
[Player.Judge] = "phase_judge",
|
||||
[Player.Draw] = "phase_draw",
|
||||
[Player.Play] = "phase_play",
|
||||
[Player.Discard] = "phase_discard",
|
||||
}
|
||||
|
||||
---@param phase_table Phase[]
|
||||
function ServerPlayer:play(phase_table)
|
||||
phase_table = phase_table or {}
|
||||
|
@ -505,8 +510,18 @@ function ServerPlayer:skip(phase)
|
|||
end
|
||||
end
|
||||
|
||||
function ServerPlayer:gainAnExtraTurn()
|
||||
function ServerPlayer:gainAnExtraTurn(delay)
|
||||
local room = self.room
|
||||
delay = (delay == nil) and true or delay
|
||||
if delay then
|
||||
local logic = room.logic
|
||||
local turn = logic:getCurrentEvent():findParent(GameEvent.Turn, true)
|
||||
if turn then
|
||||
turn:addExitFunc(function() self:gainAnExtraTurn(false) end)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
room:sendLog{
|
||||
type = "#GainAnExtraTurn",
|
||||
from = self.id
|
||||
|
|
Loading…
Reference in New Issue