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>
|
<source>updated packages for md5</source>
|
||||||
<translation>已为您与服务器同步拓展包,请尝试再次连入</translation>
|
<translation>已为您与服务器同步拓展包,请尝试再次连入</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Are you sure to exit?</source>
|
|
||||||
<translation>是否确认退出?</translation>
|
|
||||||
</message>
|
|
||||||
</context>
|
</context>
|
||||||
|
|
||||||
<context>
|
<context>
|
||||||
|
@ -179,6 +175,10 @@
|
||||||
<source>FreeKill</source>
|
<source>FreeKill</source>
|
||||||
<translation>新月杀</translation>
|
<translation>新月杀</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Are you sure to exit?</source>
|
||||||
|
<translation>是否确认退出?</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
|
||||||
<context>
|
<context>
|
||||||
|
|
|
@ -303,6 +303,7 @@ Fk:loadTranslationTable{
|
||||||
-- phase
|
-- phase
|
||||||
["#PhaseSkipped"] = "%from 跳过了 %arg",
|
["#PhaseSkipped"] = "%from 跳过了 %arg",
|
||||||
["#GainAnExtraTurn"] = "%from 开始进行一个额外的回合",
|
["#GainAnExtraTurn"] = "%from 开始进行一个额外的回合",
|
||||||
|
["#GainAnExtraPhase"] = "%from 开始进行一个额外的 %arg",
|
||||||
|
|
||||||
-- useCard
|
-- useCard
|
||||||
["#UseCard"] = "%from 使用了牌 %card",
|
["#UseCard"] = "%from 使用了牌 %card",
|
||||||
|
|
|
@ -59,6 +59,10 @@ function General:initialize(package, name, kingdom, hp, maxHp, gender)
|
||||||
package:addGeneral(self)
|
package:addGeneral(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function General:__tostring()
|
||||||
|
return string.format("<General %s>", self.name)
|
||||||
|
end
|
||||||
|
|
||||||
--- 为武将增加技能,需要注意增加其他武将技能时的处理方式。
|
--- 为武将增加技能,需要注意增加其他武将技能时的处理方式。
|
||||||
---@param skill Skill @ (单个)武将技能
|
---@param skill Skill @ (单个)武将技能
|
||||||
function General:addSkill(skill)
|
function General:addSkill(skill)
|
||||||
|
|
|
@ -444,6 +444,18 @@ function Player:inMyAttackRange(other, fixLimit)
|
||||||
return self:distanceTo(other) <= (baseAttackRange + fixLimit)
|
return self:distanceTo(other) <= (baseAttackRange + fixLimit)
|
||||||
end
|
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 cardName string @ 牌名
|
||||||
---@param num integer @ 次数
|
---@param num integer @ 次数
|
||||||
|
|
|
@ -1,6 +1,32 @@
|
||||||
-- SPDX-License-Identifier: GPL-3.0-or-later
|
-- SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
local Util = {}
|
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
|
-- the iterator of QList object
|
||||||
local qlist_iterator = function(list, n)
|
local qlist_iterator = function(list, n)
|
||||||
|
@ -150,13 +176,13 @@ function table.simpleClone(self)
|
||||||
return ret
|
return ret
|
||||||
end
|
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)
|
function table.cloneWithoutClass(self)
|
||||||
local ret = {}
|
local ret = {}
|
||||||
for k, v in pairs(self) do
|
for k, v in pairs(self) do
|
||||||
if type(v) == "table" then
|
if type(v) == "table" then
|
||||||
if v.class or v.super then
|
if v.class or v.super then
|
||||||
ret[k] = tostring(v)
|
ret[k] = v
|
||||||
else
|
else
|
||||||
ret[k] = table.cloneWithoutClass(v)
|
ret[k] = table.cloneWithoutClass(v)
|
||||||
end
|
end
|
||||||
|
|
|
@ -77,6 +77,9 @@ local function _call(self, ...) return self:new(...) end
|
||||||
local function _createClass(name, super)
|
local function _createClass(name, super)
|
||||||
local dict = {}
|
local dict = {}
|
||||||
dict.__index = dict
|
dict.__index = dict
|
||||||
|
--[[ debug
|
||||||
|
dict.__gc = function(t) printf("%s destructed", tostring(t)) end
|
||||||
|
--]]
|
||||||
|
|
||||||
local aClass = { name = name, super = super, static = {},
|
local aClass = { name = name, super = super, static = {},
|
||||||
__instanceDict = dict, __declaredMethods = {},
|
__instanceDict = dict, __declaredMethods = {},
|
||||||
|
|
|
@ -111,4 +111,7 @@ fk.CardShown = 77
|
||||||
-- 79 = BeforeTurnOver
|
-- 79 = BeforeTurnOver
|
||||||
-- 80 = BeforeChainStateChange
|
-- 80 = BeforeChainStateChange
|
||||||
|
|
||||||
fk.NumOfEvents = 81
|
fk.SkillEffect = 81
|
||||||
|
fk.AfterSkillEffect = 82
|
||||||
|
|
||||||
|
fk.NumOfEvents = 83
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
-- Definitions of game events
|
-- Definitions of game events
|
||||||
|
|
||||||
|
-- 某类事件对应的结束事件,其id刚好就是那个事件的相反数
|
||||||
|
-- GameEvent.EventFinish = -1
|
||||||
|
|
||||||
GameEvent.ChangeHp = 1
|
GameEvent.ChangeHp = 1
|
||||||
GameEvent.Damage = 2
|
GameEvent.Damage = 2
|
||||||
GameEvent.LoseHp = 3
|
GameEvent.LoseHp = 3
|
||||||
|
|
|
@ -1,6 +1,16 @@
|
||||||
-- SPDX-License-Identifier: GPL-3.0-or-later
|
-- SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
GameEvent.functions[GameEvent.SkillEffect] = function(self)
|
GameEvent.functions[GameEvent.SkillEffect] = function(self)
|
||||||
local effect_cb = table.unpack(self.data)
|
local effect_cb, player, skill = table.unpack(self.data)
|
||||||
return effect_cb()
|
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
|
end
|
||||||
|
|
|
@ -1,40 +1,70 @@
|
||||||
-- SPDX-License-Identifier: GPL-3.0-or-later
|
-- SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
---@class GameEvent: Object
|
---@class GameEvent: Object
|
||||||
---@field public room Room
|
---@field public id integer @ 事件的id,随着时间推移自动增加并分配给新事件
|
||||||
---@field public event integer
|
---@field public end_id integer @ 事件的对应结束id,如果整个事件中未插入事件,那么end_id就是自己的id
|
||||||
---@field public data any
|
---@field public room Room @ room实例
|
||||||
---@field public parent GameEvent
|
---@field public event integer @ 该事件对应的EventType
|
||||||
---@field public main_func fun(self: GameEvent)
|
---@field public data any @ 事件的附加数据,视类型而定
|
||||||
---@field public clear_func fun(self: GameEvent)
|
---@field public parent GameEvent @ 事件的父事件(栈中的上一层事件)
|
||||||
---@field public extra_clear_funcs any[]
|
---@field public main_func fun(self: GameEvent) @ 事件的主函数
|
||||||
---@field public interrupted boolean
|
---@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")
|
local GameEvent = class("GameEvent")
|
||||||
|
|
||||||
|
---@type fun(self: GameEvent)[]
|
||||||
GameEvent.functions = {}
|
GameEvent.functions = {}
|
||||||
|
|
||||||
|
---@type fun(self: GameEvent)[]
|
||||||
GameEvent.cleaners = {}
|
GameEvent.cleaners = {}
|
||||||
|
|
||||||
|
---@type fun(self: GameEvent)[]
|
||||||
|
GameEvent.exit_funcs = {}
|
||||||
|
|
||||||
local function wrapCoFunc(f, ...)
|
local function wrapCoFunc(f, ...)
|
||||||
if not f then return nil end
|
if not f then return nil end
|
||||||
local args = {...}
|
local args = {...}
|
||||||
return function() return f(table.unpack(args)) end
|
return function() return f(table.unpack(args)) end
|
||||||
end
|
end
|
||||||
local function dummyFunc() end
|
local dummyFunc = Util.DummyFunc
|
||||||
|
|
||||||
function GameEvent:initialize(event, ...)
|
function GameEvent:initialize(event, ...)
|
||||||
|
self.id = -1
|
||||||
|
self.end_id = -1
|
||||||
self.room = RoomInstance
|
self.room = RoomInstance
|
||||||
self.event = event
|
self.event = event
|
||||||
self.data = { ... }
|
self.data = { ... }
|
||||||
self.main_func = wrapCoFunc(GameEvent.functions[event], self) or dummyFunc
|
self.main_func = wrapCoFunc(GameEvent.functions[event], self) or dummyFunc
|
||||||
self.clear_func = GameEvent.cleaners[event] 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
|
self.interrupted = false
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameEvent:__tostring()
|
function GameEvent:__tostring()
|
||||||
return GameEvent:translate(self.event)
|
return string.format("<%s #%d>", GameEvent:translate(self.event), self.id)
|
||||||
end
|
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
|
local e = self.parent
|
||||||
repeat
|
repeat
|
||||||
if e.event == eventType then return e end
|
if e.event == eventType then return e end
|
||||||
|
@ -43,12 +73,83 @@ function GameEvent:findParent(eventType)
|
||||||
return nil
|
return nil
|
||||||
end
|
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()
|
function GameEvent:clear()
|
||||||
local clear_co = coroutine.create(function()
|
local clear_co = coroutine.create(function()
|
||||||
|
self:clear_func()
|
||||||
for _, f in ipairs(self.extra_clear_funcs) do
|
for _, f in ipairs(self.extra_clear_funcs) do
|
||||||
if type(f) == "function" then f(self) end
|
if type(f) == "function" then f(self) end
|
||||||
end
|
end
|
||||||
self:clear_func()
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
|
@ -72,6 +173,28 @@ function GameEvent:clear()
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
||||||
local function breakEvent(self, extra_yield_result)
|
local function breakEvent(self, extra_yield_result)
|
||||||
|
@ -95,6 +218,12 @@ function GameEvent:exec()
|
||||||
self.parent = logic:getCurrentEvent()
|
self.parent = logic:getCurrentEvent()
|
||||||
logic.game_event_stack:push(self)
|
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)
|
local co = coroutine.create(self.main_func)
|
||||||
while true do
|
while true do
|
||||||
local err, yield_result, extra_yield_result = coroutine.resume(co)
|
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
|
-- yield to corresponding GameEvent, first pop self from stack
|
||||||
self.interrupted = true
|
self.interrupted = true
|
||||||
self:clear()
|
self:clear()
|
||||||
logic.game_event_stack:pop(self)
|
-- logic.game_event_stack:pop(self)
|
||||||
coroutine.close(co)
|
coroutine.close(co)
|
||||||
|
|
||||||
-- then, call yield
|
-- then, call yield
|
||||||
|
@ -151,7 +280,6 @@ function GameEvent:exec()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
logic.game_event_stack:pop(self)
|
|
||||||
return ret, extra_ret
|
return ret, extra_ret
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,14 @@
|
||||||
---@class GameLogic: Object
|
---@class GameLogic: Object
|
||||||
---@field public room Room
|
---@field public room Room
|
||||||
---@field public skill_table table<Event, TriggerSkill[]>
|
---@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 refresh_skill_table table<Event, TriggerSkill[]>
|
||||||
---@field public skills string[]
|
---@field public skills string[]
|
||||||
---@field public event_stack Stack
|
|
||||||
---@field public game_event_stack Stack
|
---@field public game_event_stack Stack
|
||||||
---@field public role_table string[][]
|
---@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")
|
local GameLogic = class("GameLogic")
|
||||||
|
|
||||||
function GameLogic:initialize(room)
|
function GameLogic:initialize(room)
|
||||||
|
@ -17,8 +19,10 @@ function GameLogic:initialize(room)
|
||||||
self.skill_priority_table = {}
|
self.skill_priority_table = {}
|
||||||
self.refresh_skill_table = {}
|
self.refresh_skill_table = {}
|
||||||
self.skills = {} -- skillName[]
|
self.skills = {} -- skillName[]
|
||||||
self.event_stack = Stack:new()
|
|
||||||
self.game_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 = {
|
self.role_table = {
|
||||||
{ "lord" },
|
{ "lord" },
|
||||||
|
@ -381,8 +385,6 @@ function GameLogic:trigger(event, target, data, refresh_only)
|
||||||
local _target = room.current -- for iteration
|
local _target = room.current -- for iteration
|
||||||
local player = _target
|
local player = _target
|
||||||
|
|
||||||
self.event_stack:push({event, target, data})
|
|
||||||
|
|
||||||
if #skills_to_refresh > 0 then repeat do
|
if #skills_to_refresh > 0 then repeat do
|
||||||
-- refresh skills. This should not be broken
|
-- refresh skills. This should not be broken
|
||||||
for _, skill in ipairs(skills_to_refresh) do
|
for _, skill in ipairs(skills_to_refresh) do
|
||||||
|
@ -450,7 +452,6 @@ function GameLogic:trigger(event, target, data, refresh_only)
|
||||||
::trigger_loop_continue::
|
::trigger_loop_continue::
|
||||||
end
|
end
|
||||||
|
|
||||||
self.event_stack:pop()
|
|
||||||
return broken
|
return broken
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -459,6 +460,29 @@ function GameLogic:getCurrentEvent()
|
||||||
return self.game_event_stack.t[self.game_event_stack.p]
|
return self.game_event_stack.t[self.game_event_stack.p]
|
||||||
end
|
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)
|
function GameLogic:dumpEventStack(detailed)
|
||||||
local top = self:getCurrentEvent()
|
local top = self:getCurrentEvent()
|
||||||
local i = self.game_event_stack.p
|
local i = self.game_event_stack.p
|
||||||
|
@ -493,6 +517,28 @@ function GameLogic:dumpEventStack(detailed)
|
||||||
print("\n===== End of event stack dump =====")
|
print("\n===== End of event stack dump =====")
|
||||||
end
|
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)
|
function GameLogic:breakEvent(ret)
|
||||||
coroutine.yield("__breakEvent", ret)
|
coroutine.yield("__breakEvent", ret)
|
||||||
end
|
end
|
||||||
|
|
|
@ -62,8 +62,7 @@ dofile "lua/server/ai/init.lua"
|
||||||
---@param _room fk.Room
|
---@param _room fk.Room
|
||||||
function Room:initialize(_room)
|
function Room:initialize(_room)
|
||||||
self.room = _room
|
self.room = _room
|
||||||
|
_room.startGame = function(_self)
|
||||||
self.room.startGame = function(_self)
|
|
||||||
Room.initialize(self, _room) -- clear old data
|
Room.initialize(self, _room) -- clear old data
|
||||||
self.settings = json.decode(_room:settings())
|
self.settings = json.decode(_room:settings())
|
||||||
Fk.disabled_packs = self.settings.disabledPack
|
Fk.disabled_packs = self.settings.disabledPack
|
||||||
|
@ -1387,7 +1386,7 @@ function Room:handleUseCardReply(player, data)
|
||||||
Self = player
|
Self = player
|
||||||
local c = skill:viewAs(selected_cards)
|
local c = skill:viewAs(selected_cards)
|
||||||
if c then
|
if c then
|
||||||
self:useSkill(player, skill)
|
self:useSkill(player, skill, Util.DummyFunc)
|
||||||
|
|
||||||
local use = {} ---@type CardUseStruct
|
local use = {} ---@type CardUseStruct
|
||||||
use.from = player.id
|
use.from = player.id
|
||||||
|
@ -2177,7 +2176,7 @@ function Room:handleCardEffect(event, cardEffectEvent)
|
||||||
if cardEffectEvent.card.skill then
|
if cardEffectEvent.card.skill then
|
||||||
execGameEvent(GameEvent.SkillEffect, function ()
|
execGameEvent(GameEvent.SkillEffect, function ()
|
||||||
cardEffectEvent.card.skill:onEffect(self, cardEffectEvent)
|
cardEffectEvent.card.skill:onEffect(self, cardEffectEvent)
|
||||||
end)
|
end, self:getPlayerById(cardEffectEvent.from), cardEffectEvent.card.skill)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2691,7 +2690,7 @@ function Room:useSkill(player, skill, effect_cb)
|
||||||
player:addSkillUseHistory(skill.name)
|
player:addSkillUseHistory(skill.name)
|
||||||
|
|
||||||
if effect_cb then
|
if effect_cb then
|
||||||
return execGameEvent(GameEvent.SkillEffect, effect_cb)
|
return execGameEvent(GameEvent.SkillEffect, effect_cb, player, skill)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -322,18 +322,6 @@ function ServerPlayer:isAlive()
|
||||||
return self.dead == false
|
return self.dead == false
|
||||||
end
|
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()
|
function ServerPlayer:turnOver()
|
||||||
if self.room.logic:trigger(fk.BeforeTurnOver, self) then
|
if self.room.logic:trigger(fk.BeforeTurnOver, self) then
|
||||||
return
|
return
|
||||||
|
@ -367,6 +355,13 @@ function ServerPlayer:showCards(cards)
|
||||||
room.logic:trigger(fk.CardShown, self, { cardIds = cards })
|
room.logic:trigger(fk.CardShown, self, { cardIds = cards })
|
||||||
end
|
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 from_phase Phase
|
||||||
---@param to_phase Phase
|
---@param to_phase Phase
|
||||||
function ServerPlayer:changePhase(from_phase, to_phase)
|
function ServerPlayer:changePhase(from_phase, to_phase)
|
||||||
|
@ -397,25 +392,35 @@ function ServerPlayer:changePhase(from_phase, to_phase)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
function ServerPlayer:gainAnExtraPhase(phase)
|
function ServerPlayer:gainAnExtraPhase(phase, delay)
|
||||||
local room = self.room
|
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
|
local current = self.phase
|
||||||
self.phase = phase
|
self.phase = phase
|
||||||
room:notifyProperty(self, self, "phase")
|
room:notifyProperty(self, self, "phase")
|
||||||
|
|
||||||
|
room:sendLog{
|
||||||
|
type = "#GainAnExtraPhase",
|
||||||
|
from = self.id,
|
||||||
|
arg = phase_name_table[phase],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
GameEvent(GameEvent.Phase, self):exec()
|
GameEvent(GameEvent.Phase, self):exec()
|
||||||
|
|
||||||
self.phase = current
|
self.phase = current
|
||||||
room:notifyProperty(self, self, "phase")
|
room:notifyProperty(self, self, "phase")
|
||||||
end
|
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[]
|
---@param phase_table Phase[]
|
||||||
function ServerPlayer:play(phase_table)
|
function ServerPlayer:play(phase_table)
|
||||||
phase_table = phase_table or {}
|
phase_table = phase_table or {}
|
||||||
|
@ -505,8 +510,18 @@ function ServerPlayer:skip(phase)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ServerPlayer:gainAnExtraTurn()
|
function ServerPlayer:gainAnExtraTurn(delay)
|
||||||
local room = self.room
|
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{
|
room:sendLog{
|
||||||
type = "#GainAnExtraTurn",
|
type = "#GainAnExtraTurn",
|
||||||
from = self.id
|
from = self.id
|
||||||
|
|
Loading…
Reference in New Issue