2023-04-09 05:35:35 +00:00
|
|
|
|
-- SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
|
2023-02-28 17:43:44 +00:00
|
|
|
|
---@class GameEvent: Object
|
2023-06-08 17:10:16 +00:00
|
|
|
|
---@field public id integer @ 事件的id,随着时间推移自动增加并分配给新事件
|
|
|
|
|
---@field public end_id integer @ 事件的对应结束id,如果整个事件中未插入事件,那么end_id就是自己的id
|
|
|
|
|
---@field public room Room @ room实例
|
2024-06-10 07:19:47 +00:00
|
|
|
|
---@field public event GameEvent @ 该事件对应的EventType,现已改为对应的class
|
2023-06-08 17:10:16 +00:00
|
|
|
|
---@field public data any @ 事件的附加数据,视类型而定
|
|
|
|
|
---@field public parent GameEvent @ 事件的父事件(栈中的上一层事件)
|
2024-06-10 07:19:47 +00:00
|
|
|
|
---@field public extra_clear fun(self:GameEvent)[] @ 事件结束时执行的自定义函数列表
|
|
|
|
|
---@field public extra_exit fun(self:GameEvent)[] @ 事件结束后执行的自定义函数
|
2024-01-10 14:51:29 +00:00
|
|
|
|
---@field public exec_ret boolean? @ exec函数的返回值,可能不存在
|
2024-02-04 07:54:51 +00:00
|
|
|
|
---@field public status string @ ready, running, exiting, dead
|
2023-10-07 15:00:25 +00:00
|
|
|
|
---@field public interrupted boolean @ 事件是否是因为被中断而结束的,可能是防止事件或者被杀
|
|
|
|
|
---@field public killed boolean @ 事件因为终止一切结算而被中断(所谓的“被杀”)
|
2023-02-28 17:43:44 +00:00
|
|
|
|
local GameEvent = class("GameEvent")
|
|
|
|
|
|
2023-08-11 16:50:17 +00:00
|
|
|
|
---@type (fun(self: GameEvent): bool)[]
|
|
|
|
|
GameEvent.prepare_funcs = {}
|
|
|
|
|
|
2023-08-10 19:30:59 +00:00
|
|
|
|
---@type (fun(self: GameEvent): bool)[]
|
2023-02-28 17:43:44 +00:00
|
|
|
|
GameEvent.functions = {}
|
2023-06-08 17:10:16 +00:00
|
|
|
|
|
2023-08-10 19:30:59 +00:00
|
|
|
|
---@type (fun(self: GameEvent): bool)[]
|
2023-02-28 17:43:44 +00:00
|
|
|
|
GameEvent.cleaners = {}
|
2023-06-08 17:10:16 +00:00
|
|
|
|
|
2023-08-10 19:30:59 +00:00
|
|
|
|
---@type (fun(self: GameEvent): bool)[]
|
2023-06-08 17:10:16 +00:00
|
|
|
|
GameEvent.exit_funcs = {}
|
|
|
|
|
|
|
|
|
|
local dummyFunc = Util.DummyFunc
|
2023-02-28 17:43:44 +00:00
|
|
|
|
|
|
|
|
|
function GameEvent:initialize(event, ...)
|
2023-06-08 17:10:16 +00:00
|
|
|
|
self.id = -1
|
|
|
|
|
self.end_id = -1
|
2023-02-28 17:43:44 +00:00
|
|
|
|
self.room = RoomInstance
|
2024-06-10 07:19:47 +00:00
|
|
|
|
-- for compat
|
2023-02-28 17:43:44 +00:00
|
|
|
|
self.event = event
|
2024-06-10 07:19:47 +00:00
|
|
|
|
---@diagnostic disable-next-line
|
|
|
|
|
-- self.event = self.class
|
2023-02-28 17:43:44 +00:00
|
|
|
|
self.data = { ... }
|
2024-02-04 07:54:51 +00:00
|
|
|
|
self.status = "ready"
|
2023-03-07 06:55:28 +00:00
|
|
|
|
self.interrupted = false
|
2024-06-10 07:19:47 +00:00
|
|
|
|
|
|
|
|
|
self.extra_clear = Util.DummyTable
|
|
|
|
|
self.extra_exit = Util.DummyTable
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
---@generic T
|
|
|
|
|
---@param self T
|
|
|
|
|
---@return T
|
|
|
|
|
function GameEvent.create(self, ...)
|
|
|
|
|
if self.class then error('cannot use "create()" by event instances') end
|
|
|
|
|
return self:new(self, ...)
|
2023-03-07 06:55:28 +00:00
|
|
|
|
end
|
|
|
|
|
|
2024-06-10 07:19:47 +00:00
|
|
|
|
-- 获取最接近GameEvent的基类
|
|
|
|
|
---@return GameEvent
|
|
|
|
|
function GameEvent.getBaseClass(self, ...)
|
|
|
|
|
if self.class then error('cannot use "getBaseClass()" by event instances') end
|
|
|
|
|
if self.super == GameEvent or self == GameEvent then
|
|
|
|
|
return self
|
|
|
|
|
end
|
|
|
|
|
return self.super:getBaseClass()
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function GameEvent.static:subclassed(subclass)
|
|
|
|
|
local mt = getmetatable(subclass)
|
|
|
|
|
-- 适配老代码event == GameEvent.Turn之类的奇技淫巧,危险性待评估
|
|
|
|
|
-- 这样若某个模式启用派生类修改逻辑,那么findParent之类的基于父类也能找
|
|
|
|
|
mt.__eq = function(a, b)
|
|
|
|
|
if not a.super or not b.super then return false end
|
|
|
|
|
return rawequal(a, b) or a:isSubclassOf(b) or b:isSubclassOf(a)
|
|
|
|
|
end
|
2023-07-14 15:12:46 +00:00
|
|
|
|
end
|
|
|
|
|
|
2023-04-22 07:52:26 +00:00
|
|
|
|
function GameEvent:__tostring()
|
2024-06-10 07:19:47 +00:00
|
|
|
|
return string.format("<%s #%d>",
|
|
|
|
|
type(self.event == "string") and self.event or self.class.name, self.id)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function GameEvent:prepare()
|
|
|
|
|
return (GameEvent.prepare_funcs[self.event] or dummyFunc)(self)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function GameEvent:main()
|
|
|
|
|
return (GameEvent.functions[self.event] or dummyFunc)(self)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function GameEvent:clear()
|
|
|
|
|
return (GameEvent.cleaners[self.event] or dummyFunc)(self)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function GameEvent:exit()
|
|
|
|
|
return (GameEvent.exit_funcs[self.event] or dummyFunc)(self)
|
2023-06-08 17:10:16 +00:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function GameEvent:addCleaner(f)
|
2024-06-10 07:19:47 +00:00
|
|
|
|
if self.extra_clear == Util.DummyTable then
|
|
|
|
|
self.extra_clear= {}
|
2023-06-08 17:10:16 +00:00
|
|
|
|
end
|
2024-06-10 07:19:47 +00:00
|
|
|
|
table.insert(self.extra_clear, f)
|
2023-04-22 07:52:26 +00:00
|
|
|
|
end
|
|
|
|
|
|
2023-06-08 17:10:16 +00:00
|
|
|
|
function GameEvent:addExitFunc(f)
|
2024-06-10 07:19:47 +00:00
|
|
|
|
if self.extra_exit== Util.DummyTable then
|
|
|
|
|
self.extra_exit= {}
|
2023-06-08 17:10:16 +00:00
|
|
|
|
end
|
2024-06-10 07:19:47 +00:00
|
|
|
|
table.insert(self.extra_exit, f)
|
2023-06-08 17:10:16 +00:00
|
|
|
|
end
|
|
|
|
|
|
2023-09-19 06:27:54 +00:00
|
|
|
|
function GameEvent:prependExitFunc(f)
|
2024-06-10 07:19:47 +00:00
|
|
|
|
if self.extra_exit== Util.DummyTable then
|
|
|
|
|
self.extra_exit= {}
|
2023-09-19 06:27:54 +00:00
|
|
|
|
end
|
2024-06-10 07:19:47 +00:00
|
|
|
|
table.insert(self.extra_exit, 1, f)
|
2023-09-19 06:27:54 +00:00
|
|
|
|
end
|
|
|
|
|
|
2024-04-01 16:56:04 +00:00
|
|
|
|
-- 找第一个与当前事件有继承关系的特定事件
|
2024-06-10 07:19:47 +00:00
|
|
|
|
---@param eventType GameEvent @ 事件类型
|
2024-04-01 16:56:04 +00:00
|
|
|
|
---@param includeSelf bool @ 是否包括本事件
|
|
|
|
|
---@param depth? integer @ 搜索深度
|
|
|
|
|
---@return GameEvent?
|
|
|
|
|
function GameEvent:findParent(eventType, includeSelf, depth)
|
2023-06-08 17:10:16 +00:00
|
|
|
|
if includeSelf and self.event == eventType then return self end
|
2024-04-01 16:56:04 +00:00
|
|
|
|
if depth == 0 then return nil end
|
2023-04-09 03:44:19 +00:00
|
|
|
|
local e = self.parent
|
2024-04-01 16:56:04 +00:00
|
|
|
|
local l = 1
|
2024-01-24 19:13:57 +00:00
|
|
|
|
while e do
|
2023-04-09 03:44:19 +00:00
|
|
|
|
if e.event == eventType then return e end
|
2024-04-01 16:56:04 +00:00
|
|
|
|
if depth and l >= depth then break end
|
2023-04-09 03:44:19 +00:00
|
|
|
|
e = e.parent
|
2024-04-01 16:56:04 +00:00
|
|
|
|
l = l + 1
|
2024-01-24 19:13:57 +00:00
|
|
|
|
end
|
2023-04-09 03:44:19 +00:00
|
|
|
|
return nil
|
|
|
|
|
end
|
|
|
|
|
|
2023-06-08 17:10:16 +00:00
|
|
|
|
-- 找n个id介于from和to之间的事件。
|
2024-04-01 16:56:04 +00:00
|
|
|
|
---@param events GameEvent[] @ 事件数组
|
|
|
|
|
---@param from integer @ 起始id
|
|
|
|
|
---@param to integer @ 终止id
|
|
|
|
|
---@param n integer @ 最多找多少个
|
|
|
|
|
---@param func fun(e: GameEvent): boolean? @ 过滤用的函数
|
|
|
|
|
---@return GameEvent[] @ 找到的符合条件的所有事件,最多n个但不保证有n个
|
2023-06-08 17:10:16 +00:00
|
|
|
|
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]
|
2023-08-02 15:01:28 +00:00
|
|
|
|
if v.id <= to and func(v) then
|
2023-06-08 17:10:16 +00:00
|
|
|
|
table.insert(ret, v)
|
|
|
|
|
end
|
|
|
|
|
if #ret >= n then break end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
return ret
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- 从某个区间中,找出类型符合且符合func函数检测的至多n个事件。
|
|
|
|
|
---@param eventType integer @ 要查找的事件类型
|
|
|
|
|
---@param n integer @ 最多找多少个
|
2023-12-03 11:35:14 +00:00
|
|
|
|
---@param func fun(e: GameEvent): boolean? @ 过滤用的函数
|
|
|
|
|
---@param endEvent? GameEvent @ 区间终止点,默认为本事件结束
|
2023-06-08 17:10:16 +00:00
|
|
|
|
---@return GameEvent[] @ 找到的符合条件的所有事件,最多n个但不保证有n个
|
|
|
|
|
function GameEvent:searchEvents(eventType, n, func, endEvent)
|
|
|
|
|
local logic = self.room.logic
|
2023-06-10 12:54:48 +00:00
|
|
|
|
local events = logic.event_recorder[eventType] or Util.DummyTable
|
2023-06-08 17:10:16 +00:00
|
|
|
|
local from = self.id
|
|
|
|
|
local to = endEvent and endEvent.id or self.end_id
|
2023-11-07 13:14:51 +00:00
|
|
|
|
if math.abs(to) == 1 then to = #logic.all_game_events end
|
2023-06-08 17:10:16 +00:00
|
|
|
|
n = n or 1
|
2023-08-11 16:50:17 +00:00
|
|
|
|
func = func or Util.TrueFunc
|
2023-06-08 17:10:16 +00:00
|
|
|
|
|
|
|
|
|
local ret
|
|
|
|
|
if #events < 6 then
|
|
|
|
|
ret = {}
|
|
|
|
|
for _, v in ipairs(events) do
|
2023-08-02 15:01:28 +00:00
|
|
|
|
if v.id >= from and v.id <= to and func(v) then
|
2023-06-08 17:10:16 +00:00
|
|
|
|
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
|
|
|
|
|
|
2023-02-28 17:43:44 +00:00
|
|
|
|
function GameEvent:exec()
|
|
|
|
|
local room = self.room
|
|
|
|
|
local logic = room.logic
|
2024-02-04 07:54:51 +00:00
|
|
|
|
if self.status ~= "ready" then return true end
|
|
|
|
|
|
2023-04-09 03:44:19 +00:00
|
|
|
|
self.parent = logic:getCurrentEvent()
|
2023-08-11 16:50:17 +00:00
|
|
|
|
|
2024-06-10 07:19:47 +00:00
|
|
|
|
if self:prepare() then return true end
|
2023-08-11 16:50:17 +00:00
|
|
|
|
|
2024-01-10 14:51:29 +00:00
|
|
|
|
logic:pushEvent(self)
|
2023-06-08 17:10:16 +00:00
|
|
|
|
|
2024-06-10 07:19:47 +00:00
|
|
|
|
local co = coroutine.create(function() return self:main() end)
|
2023-10-07 15:00:25 +00:00
|
|
|
|
self._co = co
|
2024-02-04 07:54:51 +00:00
|
|
|
|
self.status = "running"
|
2023-02-28 17:43:44 +00:00
|
|
|
|
|
2024-01-10 14:51:29 +00:00
|
|
|
|
coroutine.yield(self, "__newEvent")
|
2023-02-28 17:43:44 +00:00
|
|
|
|
|
2024-06-10 07:19:47 +00:00
|
|
|
|
Pcall(self.exit, self)
|
|
|
|
|
for _, f in ipairs(self.extra_exit) do
|
2024-01-10 14:51:29 +00:00
|
|
|
|
if type(f) == "function" then
|
|
|
|
|
Pcall(f, self)
|
2023-02-28 17:43:44 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2024-01-10 14:51:29 +00:00
|
|
|
|
return self.interrupted, self.exec_ret
|
2023-02-28 17:43:44 +00:00
|
|
|
|
end
|
|
|
|
|
|
2023-04-22 07:52:26 +00:00
|
|
|
|
function GameEvent:shutdown()
|
2024-02-04 07:54:51 +00:00
|
|
|
|
if self.status ~= "running" then return end
|
2023-04-22 07:52:26 +00:00
|
|
|
|
-- yield to self and break
|
|
|
|
|
coroutine.yield(self, "__breakEvent")
|
|
|
|
|
end
|
|
|
|
|
|
2023-02-28 17:43:44 +00:00
|
|
|
|
return GameEvent
|