2022-03-27 06:49:41 +00:00
|
|
|
-- the iterator of QList object
|
|
|
|
local qlist_iterator = function(list, n)
|
2022-04-30 07:27:56 +00:00
|
|
|
if n < list:length() - 1 then
|
|
|
|
return n + 1, list:at(n + 1) -- the next element of list
|
|
|
|
end
|
2022-03-27 06:49:41 +00:00
|
|
|
end
|
|
|
|
|
2022-03-31 05:29:23 +00:00
|
|
|
function fk.qlist(list)
|
2022-04-30 07:27:56 +00:00
|
|
|
return qlist_iterator, list, -1
|
2022-03-27 06:49:41 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function table:contains(element)
|
2023-01-04 06:21:29 +00:00
|
|
|
if #self == 0 then return false end
|
2022-04-30 07:27:56 +00:00
|
|
|
for _, e in ipairs(self) do
|
|
|
|
if e == element then return true end
|
|
|
|
end
|
2022-03-27 06:49:41 +00:00
|
|
|
end
|
|
|
|
|
2022-03-28 14:24:30 +00:00
|
|
|
function table:shuffle()
|
2022-04-30 07:27:56 +00:00
|
|
|
for i = #self, 2, -1 do
|
|
|
|
local j = math.random(i)
|
|
|
|
self[i], self[j] = self[j], self[i]
|
|
|
|
end
|
2022-03-28 14:24:30 +00:00
|
|
|
end
|
|
|
|
|
2022-03-27 06:49:41 +00:00
|
|
|
function table:insertTable(list)
|
2022-04-30 07:27:56 +00:00
|
|
|
for _, e in ipairs(list) do
|
|
|
|
table.insert(self, e)
|
|
|
|
end
|
2022-03-27 06:49:41 +00:00
|
|
|
end
|
|
|
|
|
2022-04-01 12:51:01 +00:00
|
|
|
function table:indexOf(value, from)
|
2022-04-30 07:27:56 +00:00
|
|
|
from = from or 1
|
|
|
|
for i = from, #self do
|
|
|
|
if self[i] == value then return i end
|
|
|
|
end
|
|
|
|
return -1
|
2022-04-01 12:51:01 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function table:removeOne(element)
|
2022-04-30 07:27:56 +00:00
|
|
|
if #self == 0 or type(self[1]) ~= type(element) then return false end
|
2022-04-01 12:51:01 +00:00
|
|
|
|
2022-04-30 07:27:56 +00:00
|
|
|
for i = 1, #self do
|
|
|
|
if self[i] == element then
|
|
|
|
table.remove(self, i)
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return false
|
2022-04-01 12:51:01 +00:00
|
|
|
end
|
|
|
|
|
2022-04-14 10:22:00 +00:00
|
|
|
-- Note: only clone key and value, no metatable
|
|
|
|
-- so dont use for class or instance
|
|
|
|
---@generic T
|
|
|
|
---@param self T
|
|
|
|
---@return T
|
|
|
|
function table.clone(self)
|
2022-04-30 07:27:56 +00:00
|
|
|
local ret = {}
|
|
|
|
for k, v in pairs(self) do
|
|
|
|
if type(v) == "table" then
|
|
|
|
ret[k] = table.clone(v)
|
|
|
|
else
|
|
|
|
ret[k] = v
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return ret
|
2022-04-14 10:22:00 +00:00
|
|
|
end
|
|
|
|
|
2022-09-14 05:01:10 +00:00
|
|
|
-- if table does not contain the element, we insert it
|
|
|
|
function table:insertIfNeed(element)
|
|
|
|
if not table.contains(self, element) then
|
|
|
|
table.insert(self, element)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
---@param delimiter string
|
|
|
|
---@return string[]
|
|
|
|
function string:split(delimiter)
|
|
|
|
if #self == 0 then return {} end
|
|
|
|
local result = {}
|
|
|
|
local from = 1
|
|
|
|
local delim_from, delim_to = string.find(self, delimiter, from)
|
|
|
|
while delim_from do
|
|
|
|
table.insert(result, string.sub(self, from, delim_from - 1))
|
|
|
|
from = delim_to + 1
|
|
|
|
delim_from, delim_to = string.find(self, delimiter, from)
|
|
|
|
end
|
|
|
|
table.insert(result, string.sub(self, from))
|
|
|
|
return result
|
|
|
|
end
|
|
|
|
|
2022-03-30 08:33:56 +00:00
|
|
|
---@class Sql
|
2022-03-27 06:49:41 +00:00
|
|
|
Sql = {
|
2022-04-30 07:27:56 +00:00
|
|
|
---@param filename string
|
|
|
|
open = function(filename)
|
|
|
|
return fk.OpenDatabase(filename)
|
|
|
|
end,
|
|
|
|
|
|
|
|
---@param db fk.SQLite3
|
|
|
|
close = function(db)
|
|
|
|
fk.CloseDatabase(db)
|
|
|
|
end,
|
|
|
|
|
|
|
|
--- Execute an SQL statement.
|
|
|
|
---@param db fk.SQLite3
|
|
|
|
---@param sql string
|
|
|
|
exec = function(db, sql)
|
|
|
|
fk.ExecSQL(db, sql)
|
|
|
|
end,
|
|
|
|
|
|
|
|
--- Execute a `SELECT` SQL statement.
|
|
|
|
---@param db fk.SQLite3
|
|
|
|
---@param sql string
|
|
|
|
---@return table @ { [columnName] --> result : string[] }
|
|
|
|
exec_select = function(db, sql)
|
|
|
|
return json.decode(fk.SelectFromDb(db, sql))
|
|
|
|
end,
|
2022-03-27 06:49:41 +00:00
|
|
|
}
|
|
|
|
|
2022-03-28 14:24:30 +00:00
|
|
|
FileIO = {
|
2022-04-30 07:27:56 +00:00
|
|
|
pwd = fk.QmlBackend_pwd,
|
|
|
|
ls = function(filename)
|
|
|
|
if filename == nil then
|
|
|
|
return fk.QmlBackend_ls(".")
|
|
|
|
else
|
|
|
|
return fk.QmlBackend_ls(filename)
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
cd = fk.QmlBackend_cd,
|
|
|
|
exists = fk.QmlBackend_exists,
|
|
|
|
isDir = fk.QmlBackend_isDir
|
2022-03-28 14:24:30 +00:00
|
|
|
}
|
|
|
|
|
2022-03-31 05:29:23 +00:00
|
|
|
os.getms = fk.GetMicroSecond
|
2022-03-30 06:14:40 +00:00
|
|
|
|
2022-03-31 05:29:23 +00:00
|
|
|
---@class Stack : Object
|
2022-03-28 14:24:30 +00:00
|
|
|
Stack = class("Stack")
|
|
|
|
function Stack:initialize()
|
2022-04-30 07:27:56 +00:00
|
|
|
self.t = {}
|
|
|
|
self.p = 0
|
2022-03-28 14:24:30 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function Stack:push(e)
|
2022-04-30 07:27:56 +00:00
|
|
|
self.p = self.p + 1
|
|
|
|
self.t[self.p] = e
|
2022-03-28 14:24:30 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function Stack:isEmpty()
|
2022-04-30 07:27:56 +00:00
|
|
|
return self.p == 0
|
2022-03-28 14:24:30 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function Stack:pop()
|
2022-04-30 07:27:56 +00:00
|
|
|
if self.p == 0 then return nil end
|
|
|
|
self.p = self.p - 1
|
|
|
|
return self.t[self.p + 1]
|
2022-03-28 14:24:30 +00:00
|
|
|
end
|
|
|
|
|
2022-03-27 06:49:41 +00:00
|
|
|
|
2022-04-01 12:51:01 +00:00
|
|
|
--- useful function to create enums
|
|
|
|
---
|
|
|
|
--- only use it in a terminal
|
|
|
|
---@param table string
|
2022-03-31 05:29:23 +00:00
|
|
|
---@param enum string[]
|
2022-04-01 12:51:01 +00:00
|
|
|
function CreateEnum(table, enum)
|
2022-04-30 07:27:56 +00:00
|
|
|
local enum_format = "%s.%s = %d"
|
|
|
|
for i, v in ipairs(enum) do
|
|
|
|
print(string.format(enum_format, table, v, i))
|
|
|
|
end
|
2022-03-27 06:49:41 +00:00
|
|
|
end
|
2022-04-02 13:39:44 +00:00
|
|
|
|
|
|
|
function switch(param, case_table)
|
2022-04-30 07:27:56 +00:00
|
|
|
local case = case_table[param]
|
|
|
|
if case then return case() end
|
|
|
|
local def = case_table["default"]
|
|
|
|
return def and def() or nil
|
|
|
|
end
|
|
|
|
|
|
|
|
---@class TargetGroup : Object
|
|
|
|
local TargetGroup = class("TargetGroup")
|
|
|
|
|
|
|
|
function TargetGroup.static:getRealTargets(targetGroup)
|
|
|
|
if not targetGroup then
|
|
|
|
return {}
|
|
|
|
end
|
|
|
|
|
|
|
|
local realTargets = {}
|
|
|
|
for _, targets in ipairs(targetGroup) do
|
|
|
|
table.insert(realTargets, targets[1])
|
|
|
|
end
|
|
|
|
|
|
|
|
return realTargets
|
|
|
|
end
|
|
|
|
|
|
|
|
function TargetGroup.static:includeRealTargets(targetGroup, playerId)
|
|
|
|
if not targetGroup then
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
for _, targets in ipairs(targetGroup) do
|
|
|
|
if targets[1] == playerId then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
function TargetGroup.static:removeTarget(targetGroup, playerId)
|
|
|
|
if not targetGroup then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
for index, targets in ipairs(targetGroup) do
|
|
|
|
if (targets[1] == playerId) then
|
|
|
|
table.remove(targetGroup, index)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function TargetGroup.static:pushTargets(targetGroup, playerIds)
|
|
|
|
if not targetGroup then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
if type(playerIds) == "table" then
|
|
|
|
table.insert(targetGroup, playerIds)
|
|
|
|
elseif type(playerIds) == "number" then
|
|
|
|
table.insert(targetGroup, { playerIds })
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
---@class AimGroup : Object
|
|
|
|
local AimGroup = class("AimGroup")
|
|
|
|
|
|
|
|
AimGroup.Undone = 1
|
|
|
|
AimGroup.Done = 2
|
|
|
|
AimGroup.Cancelled = 3
|
|
|
|
|
|
|
|
function AimGroup.static:initAimGroup(playerIds)
|
|
|
|
return { [AimGroup.Undone] = playerIds, [AimGroup.Done] = {}, [AimGroup.Cancelled] = {} }
|
|
|
|
end
|
|
|
|
|
|
|
|
function AimGroup.static:getAllTargets(aimGroup)
|
|
|
|
local targets = {}
|
|
|
|
table.insertTable(targets, aimGroup[AimGroup.Undone])
|
|
|
|
table.insertTable(targets, aimGroup[AimGroup.Done])
|
|
|
|
return targets
|
|
|
|
end
|
|
|
|
|
|
|
|
function AimGroup.static:getUndoneOrDoneTargets(aimGroup, done)
|
|
|
|
return done and aimGroup[AimGroup.Done] or aimGroup[AimGroup.Undone]
|
|
|
|
end
|
|
|
|
|
|
|
|
function AimGroup.static:setTargetDone(aimGroup, playerId)
|
|
|
|
local index = table.indexOf(aimGroup[AimGroup.Undone], playerId)
|
|
|
|
if index ~= -1 then
|
|
|
|
table.remove(aimGroup[AimGroup.Undone], index)
|
|
|
|
table.insert(aimGroup[AimGroup.Done], playerId)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function AimGroup.static:addTargets(room, aimEvent, playerIds)
|
|
|
|
local playerId = type(playerIds) == "table" and playerIds[1] or playerIds
|
|
|
|
table.insert(aimEvent.tos[AimGroup.Undone], playerId)
|
2022-12-20 13:15:49 +00:00
|
|
|
|
|
|
|
if type(playerIds) == "table" then
|
|
|
|
for i = 2, #playerIds do
|
|
|
|
aimEvent.subTargets = aimEvent.subTargets or {}
|
|
|
|
table.insert(aimEvent.subTargets, playerIds[i])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-04-30 07:27:56 +00:00
|
|
|
room:sortPlayersByAction(aimEvent.tos[AimGroup.Undone])
|
|
|
|
if aimEvent.targetGroup then
|
|
|
|
TargetGroup:pushTargets(aimEvent.targetGroup, playerIds)
|
|
|
|
end
|
2022-04-02 13:39:44 +00:00
|
|
|
end
|
2022-04-30 07:27:56 +00:00
|
|
|
|
|
|
|
function AimGroup.static:cancelTarget(aimEvent, playerId)
|
|
|
|
local cancelled = false
|
|
|
|
for status = AimGroup.Undone, AimGroup.Done do
|
|
|
|
local indexList = {}
|
|
|
|
for index, pId in ipairs(aimEvent.tos[status]) do
|
|
|
|
if pId == playerId then
|
|
|
|
table.insert(indexList, index)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if #indexList > 0 then
|
|
|
|
cancelled = true
|
|
|
|
for i = 1, #indexList do
|
|
|
|
table.remove(aimEvent.tos[status], indexList[i])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if cancelled then
|
|
|
|
table.insert(aimEvent.tos[AimGroup.Cancelled], playerId)
|
|
|
|
if aimEvent.targetGroup then
|
|
|
|
TargetGroup:removeTarget(aimEvent.targetGroup, playerId)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function AimGroup.static:removeDeadTargets(room, aimEvent)
|
|
|
|
for index = AimGroup.Undone, AimGroup.Done do
|
|
|
|
aimEvent.tos[index] = room:deadPlayerFilter(aimEvent.tos[index])
|
|
|
|
end
|
|
|
|
|
|
|
|
if aimEvent.targetGroup then
|
|
|
|
local targets = TargetGroup:getRealTargets(aimEvent.targetGroup)
|
|
|
|
for _, target in ipairs(targets) do
|
|
|
|
if not room:getPlayerById(target):isAlive() then
|
|
|
|
TargetGroup:removeTarget(aimEvent.targetGroup, target)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function AimGroup.static:getCancelledTargets(aimGroup)
|
|
|
|
return aimGroup[AimGroup.Cancelled]
|
|
|
|
end
|
|
|
|
|
|
|
|
return { TargetGroup, AimGroup }
|