2023-04-09 13:35:35 +08:00
|
|
|
-- SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
2022-04-30 15:27:56 +08:00
|
|
|
-- All functions in this file are used by Qml
|
|
|
|
|
2022-04-02 15:55:01 +08:00
|
|
|
function Translate(src)
|
2022-05-01 18:37:13 +08:00
|
|
|
return Fk:translate(src)
|
2022-04-02 15:55:01 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
function GetGeneralData(name)
|
2022-04-30 15:27:56 +08:00
|
|
|
local general = Fk.generals[name]
|
|
|
|
if general == nil then general = Fk.generals["diaochan"] end
|
|
|
|
return json.encode {
|
2023-02-15 19:54:35 +08:00
|
|
|
package = general.package.name,
|
|
|
|
extension = general.package.extensionName,
|
2022-04-30 15:27:56 +08:00
|
|
|
kingdom = general.kingdom,
|
2023-04-30 18:55:59 +08:00
|
|
|
subkingdom = general.subkingdom,
|
2022-04-30 15:27:56 +08:00
|
|
|
hp = general.hp,
|
2023-04-13 20:17:39 +08:00
|
|
|
maxHp = general.maxHp,
|
|
|
|
shield = general.shield,
|
2023-04-23 21:10:07 +08:00
|
|
|
hidden = general.hidden,
|
|
|
|
total_hidden = general.total_hidden,
|
2022-04-30 15:27:56 +08:00
|
|
|
}
|
2022-04-02 15:55:01 +08:00
|
|
|
end
|
2022-04-14 18:22:00 +08:00
|
|
|
|
2023-02-15 19:54:35 +08:00
|
|
|
function GetGeneralDetail(name)
|
|
|
|
local general = Fk.generals[name]
|
|
|
|
if general == nil then general = Fk.generals["diaochan"] end
|
|
|
|
local ret = {
|
|
|
|
package = general.package.name,
|
|
|
|
extension = general.package.extensionName,
|
|
|
|
kingdom = general.kingdom,
|
|
|
|
hp = general.hp,
|
|
|
|
maxHp = general.maxHp,
|
2023-07-02 13:21:13 +08:00
|
|
|
gender = general.gender,
|
2023-04-13 22:01:25 +08:00
|
|
|
skill = {},
|
2023-08-24 21:37:06 +08:00
|
|
|
related_skill = {},
|
|
|
|
companions = general.companions
|
2023-02-15 19:54:35 +08:00
|
|
|
}
|
|
|
|
for _, s in ipairs(general.skills) do
|
|
|
|
table.insert(ret.skill, {
|
|
|
|
name = s.name,
|
|
|
|
description = Fk:getDescription(s.name)
|
|
|
|
})
|
|
|
|
end
|
|
|
|
for _, s in ipairs(general.other_skills) do
|
|
|
|
table.insert(ret.skill, {
|
|
|
|
name = s,
|
|
|
|
description = Fk:getDescription(s)
|
|
|
|
})
|
|
|
|
end
|
2023-04-13 22:01:25 +08:00
|
|
|
for _, s in ipairs(general.related_skills) do
|
|
|
|
table.insert(ret.related_skill, {
|
|
|
|
name = s.name,
|
|
|
|
description = Fk:getDescription(s.name)
|
|
|
|
})
|
|
|
|
end
|
|
|
|
for _, s in ipairs(general.related_other_skills) do
|
|
|
|
table.insert(ret.related_skill, {
|
|
|
|
name = s,
|
|
|
|
description = Fk:getDescription(s)
|
|
|
|
})
|
|
|
|
end
|
2023-08-24 21:37:06 +08:00
|
|
|
for _, g in pairs(Fk.generals) do
|
2023-08-25 17:14:43 +08:00
|
|
|
if table.contains(g.companions, general.name) then
|
|
|
|
table.insertIfNeed(ret.companions, g.name)
|
2023-08-24 21:37:06 +08:00
|
|
|
end
|
|
|
|
end
|
2023-02-15 19:54:35 +08:00
|
|
|
return json.encode(ret)
|
|
|
|
end
|
|
|
|
|
2023-03-19 02:21:45 +08:00
|
|
|
function GetSameGenerals(name)
|
|
|
|
return json.encode(Fk:getSameGenerals(name))
|
|
|
|
end
|
|
|
|
|
2022-04-30 15:27:56 +08:00
|
|
|
local cardSubtypeStrings = {
|
|
|
|
[Card.SubtypeNone] = "none",
|
|
|
|
[Card.SubtypeDelayedTrick] = "delayed_trick",
|
|
|
|
[Card.SubtypeWeapon] = "weapon",
|
|
|
|
[Card.SubtypeArmor] = "armor",
|
|
|
|
[Card.SubtypeDefensiveRide] = "defensive_horse",
|
|
|
|
[Card.SubtypeOffensiveRide] = "offensive_horse",
|
|
|
|
[Card.SubtypeTreasure] = "treasure",
|
|
|
|
}
|
|
|
|
|
2023-07-16 19:18:43 +08:00
|
|
|
function GetCardData(id, virtualCardForm)
|
2023-02-15 19:54:35 +08:00
|
|
|
local card = Fk:getCardById(id)
|
2022-04-30 15:27:56 +08:00
|
|
|
if card == nil then return json.encode{
|
|
|
|
cid = id,
|
|
|
|
known = false
|
|
|
|
} end
|
2023-06-23 22:18:11 +08:00
|
|
|
local mark = {}
|
|
|
|
for k, v in pairs(card.mark) do
|
|
|
|
if k and k:startsWith("@") and v and v ~= 0 then
|
|
|
|
table.insert(mark, {
|
|
|
|
k = k, v = v,
|
|
|
|
})
|
|
|
|
end
|
|
|
|
end
|
2022-04-30 15:27:56 +08:00
|
|
|
local ret = {
|
|
|
|
cid = id,
|
|
|
|
name = card.name,
|
2023-02-15 19:54:35 +08:00
|
|
|
extension = card.package.extensionName,
|
2022-04-30 15:27:56 +08:00
|
|
|
number = card.number,
|
|
|
|
suit = card:getSuitString(),
|
2023-04-20 00:19:48 +08:00
|
|
|
color = card:getColorString(),
|
2023-06-23 22:18:11 +08:00
|
|
|
mark = mark,
|
2023-07-02 20:39:42 +08:00
|
|
|
type = card.type,
|
2022-04-30 15:27:56 +08:00
|
|
|
subtype = cardSubtypeStrings[card.sub_type]
|
|
|
|
}
|
2023-02-15 19:54:35 +08:00
|
|
|
if card.skillName ~= "" then
|
|
|
|
local orig = Fk:getCardById(id, true)
|
|
|
|
ret.name = orig.name
|
|
|
|
ret.virt_name = card.name
|
|
|
|
end
|
2023-07-16 19:18:43 +08:00
|
|
|
if virtualCardForm then
|
|
|
|
local virtualCard = ClientInstance:getPlayerById(virtualCardForm):getVirualEquip(id)
|
|
|
|
if virtualCard then
|
|
|
|
ret.virt_name = virtualCard.name
|
|
|
|
ret.subtype = cardSubtypeStrings[virtualCard.sub_type]
|
|
|
|
end
|
|
|
|
end
|
2022-04-30 15:27:56 +08:00
|
|
|
return json.encode(ret)
|
2022-04-14 18:22:00 +08:00
|
|
|
end
|
2022-04-15 18:37:20 +08:00
|
|
|
|
2023-05-20 16:00:03 +08:00
|
|
|
function GetCardExtensionByName(cardName)
|
2023-12-09 21:57:47 +08:00
|
|
|
local card = Fk.all_card_types[cardName]
|
2023-05-20 16:00:03 +08:00
|
|
|
return card and card.package.extensionName or ""
|
|
|
|
end
|
|
|
|
|
2024-01-25 03:23:29 +08:00
|
|
|
function GetAllMods()
|
|
|
|
return json.encode(Fk.extensions)
|
|
|
|
end
|
|
|
|
|
2024-01-26 14:02:55 +08:00
|
|
|
function GetAllModNames()
|
|
|
|
return json.encode(Fk.extension_names)
|
|
|
|
end
|
|
|
|
|
2022-04-15 18:37:20 +08:00
|
|
|
function GetAllGeneralPack()
|
2022-04-30 15:27:56 +08:00
|
|
|
local ret = {}
|
|
|
|
for _, name in ipairs(Fk.package_names) do
|
|
|
|
if Fk.packages[name].type == Package.GeneralPack then
|
|
|
|
table.insert(ret, name)
|
2022-04-15 18:37:20 +08:00
|
|
|
end
|
2022-04-30 15:27:56 +08:00
|
|
|
end
|
|
|
|
return json.encode(ret)
|
2022-04-15 18:37:20 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
function GetGenerals(pack_name)
|
2024-01-26 14:02:55 +08:00
|
|
|
if not Fk.packages[pack_name] then return "{}" end
|
2022-04-30 15:27:56 +08:00
|
|
|
local ret = {}
|
|
|
|
for _, g in ipairs(Fk.packages[pack_name].generals) do
|
2023-04-23 21:10:07 +08:00
|
|
|
if not g.total_hidden then
|
|
|
|
table.insert(ret, g.name)
|
|
|
|
end
|
2022-04-30 15:27:56 +08:00
|
|
|
end
|
|
|
|
return json.encode(ret)
|
2023-06-16 23:53:44 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
function SearchAllGenerals(word)
|
|
|
|
local ret = {}
|
|
|
|
for _, name in ipairs(Fk.package_names) do
|
|
|
|
if Fk.packages[name].type == Package.GeneralPack then
|
|
|
|
table.insertTable(ret, json.decode(SearchGenerals(name, word)))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return json.encode(ret)
|
|
|
|
end
|
|
|
|
|
|
|
|
function SearchGenerals(pack_name, word)
|
|
|
|
local ret = {}
|
|
|
|
if word == "" then return GetGenerals(pack_name) end
|
|
|
|
for _, g in ipairs(Fk.packages[pack_name].generals) do
|
|
|
|
if not g.total_hidden and string.find(Fk:translate(g.name), word) then
|
|
|
|
table.insert(ret, g.name)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return json.encode(ret)
|
2022-04-15 18:37:20 +08:00
|
|
|
end
|
|
|
|
|
2023-06-16 13:26:02 +08:00
|
|
|
function UpdatePackageEnable(pkg, enabled)
|
|
|
|
if enabled then
|
|
|
|
table.removeOne(ClientInstance.disabled_packs, pkg)
|
|
|
|
else
|
|
|
|
table.insertIfNeed(ClientInstance.disabled_packs, pkg)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-06-15 21:19:57 +08:00
|
|
|
function GetAvailableGeneralsNum()
|
|
|
|
local generalPool = Fk:getAllGenerals()
|
|
|
|
local except = {}
|
|
|
|
local ret = 0
|
|
|
|
for _, g in ipairs(Fk.packages["test_p_0"].generals) do
|
|
|
|
table.insert(except, g.name)
|
|
|
|
end
|
|
|
|
|
|
|
|
local availableGenerals = {}
|
|
|
|
for _, general in pairs(generalPool) do
|
|
|
|
if not table.contains(except, general.name) then
|
|
|
|
if (not general.hidden and not general.total_hidden) and
|
|
|
|
#table.filter(availableGenerals, function(g)
|
|
|
|
return g.trueName == general.trueName
|
|
|
|
end) == 0 then
|
|
|
|
ret = ret + 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return ret
|
|
|
|
end
|
|
|
|
|
2022-04-15 18:37:20 +08:00
|
|
|
function GetAllCardPack()
|
2022-04-30 15:27:56 +08:00
|
|
|
local ret = {}
|
|
|
|
for _, name in ipairs(Fk.package_names) do
|
|
|
|
if Fk.packages[name].type == Package.CardPack then
|
|
|
|
table.insert(ret, name)
|
2022-04-15 18:37:20 +08:00
|
|
|
end
|
2022-04-30 15:27:56 +08:00
|
|
|
end
|
|
|
|
return json.encode(ret)
|
2022-04-15 18:37:20 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
function GetCards(pack_name)
|
2022-04-30 15:27:56 +08:00
|
|
|
local ret = {}
|
|
|
|
for _, c in ipairs(Fk.packages[pack_name].cards) do
|
|
|
|
table.insert(ret, c.id)
|
|
|
|
end
|
|
|
|
return json.encode(ret)
|
|
|
|
end
|
|
|
|
|
2023-12-09 21:57:47 +08:00
|
|
|
function GetCardSkill(cid)
|
|
|
|
return Fk:getCardById(cid).skill and Fk:getCardById(cid).skill.name or ""
|
|
|
|
end
|
|
|
|
|
2023-03-20 20:15:24 +08:00
|
|
|
function GetCardSpecialSkills(cid)
|
2023-06-11 16:22:11 +08:00
|
|
|
return json.encode(Fk:getCardById(cid).special_skills or Util.DummyTable)
|
2023-03-20 20:15:24 +08:00
|
|
|
end
|
|
|
|
|
2022-12-20 12:51:54 +08:00
|
|
|
function DistanceTo(from, to)
|
|
|
|
local a = ClientInstance:getPlayerById(from)
|
|
|
|
local b = ClientInstance:getPlayerById(to)
|
|
|
|
return a:distanceTo(b)
|
|
|
|
end
|
|
|
|
|
2023-02-21 13:44:24 +08:00
|
|
|
function GetPile(id, name)
|
|
|
|
return json.encode(ClientInstance:getPlayerById(id):getPile(name) or {})
|
|
|
|
end
|
|
|
|
|
2023-03-05 01:28:59 +08:00
|
|
|
function GetAllPiles(id)
|
2023-06-11 16:22:11 +08:00
|
|
|
return json.encode(ClientInstance:getPlayerById(id).special_cards or Util.DummyTable)
|
2023-03-05 01:28:59 +08:00
|
|
|
end
|
|
|
|
|
2023-04-09 11:44:19 +08:00
|
|
|
function GetPlayerSkills(id)
|
|
|
|
local p = ClientInstance:getPlayerById(id)
|
2023-06-18 16:24:12 +08:00
|
|
|
return json.encode(table.map(p.player_skills, function(s)
|
|
|
|
return s.visible and {
|
|
|
|
name = s.name,
|
|
|
|
description = Fk:getDescription(s.name),
|
|
|
|
} or nil
|
2023-04-09 11:44:19 +08:00
|
|
|
end))
|
|
|
|
end
|
|
|
|
|
2022-04-30 15:27:56 +08:00
|
|
|
---@param card string | integer
|
|
|
|
---@param player integer
|
2024-01-25 03:13:57 +08:00
|
|
|
---@param extra_data_str string
|
|
|
|
function CanUseCard(card, player, extra_data_str)
|
2022-04-30 15:27:56 +08:00
|
|
|
local c ---@type Card
|
2024-01-25 03:13:57 +08:00
|
|
|
local extra_data = extra_data_str == "" and nil or json.decode(extra_data_str)
|
2022-04-30 15:27:56 +08:00
|
|
|
if type(card) == "number" then
|
|
|
|
c = Fk:getCardById(card)
|
|
|
|
else
|
2023-01-29 18:11:41 +08:00
|
|
|
local data = json.decode(card)
|
|
|
|
local skill = Fk.skills[data.skill]
|
|
|
|
local selected_cards = data.subcards
|
|
|
|
if skill:isInstanceOf(ViewAsSkill) then
|
|
|
|
c = skill:viewAs(selected_cards)
|
|
|
|
if not c then
|
|
|
|
return "false"
|
|
|
|
end
|
|
|
|
else
|
|
|
|
-- ActiveSkill should return true here
|
|
|
|
return "true"
|
|
|
|
end
|
2022-04-30 15:27:56 +08:00
|
|
|
end
|
|
|
|
|
2023-04-10 15:55:06 +08:00
|
|
|
player = ClientInstance:getPlayerById(player)
|
2024-01-25 03:13:57 +08:00
|
|
|
local ret = c.skill:canUse(player, c, extra_data)
|
2023-04-13 20:17:39 +08:00
|
|
|
ret = ret and not player:prohibitUse(c)
|
2023-05-28 12:22:43 +08:00
|
|
|
if ret then
|
|
|
|
local min_target = c.skill:getMinTargetNum()
|
|
|
|
if min_target > 0 then
|
|
|
|
for _, p in ipairs(ClientInstance.players) do
|
2024-01-25 03:13:57 +08:00
|
|
|
if c.skill:targetFilter(p.id, {}, {}, c, extra_data) then
|
2023-05-28 12:22:43 +08:00
|
|
|
return "true"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return "false"
|
|
|
|
end
|
|
|
|
end
|
2023-04-10 15:55:06 +08:00
|
|
|
return json.encode(ret)
|
|
|
|
end
|
|
|
|
|
2023-08-02 23:01:28 +08:00
|
|
|
function CardProhibitedUse(card)
|
|
|
|
local c ---@type Card
|
|
|
|
local ret = false
|
|
|
|
if type(card) == "number" then
|
|
|
|
c = Fk:getCardById(card)
|
|
|
|
else
|
|
|
|
local data = json.decode(card)
|
|
|
|
local skill = Fk.skills[data.skill]
|
|
|
|
local selected_cards = data.subcards
|
|
|
|
if skill:isInstanceOf(ViewAsSkill) then
|
|
|
|
c = skill:viewAs(selected_cards)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if c == nil then
|
|
|
|
return "true"
|
|
|
|
else
|
|
|
|
ret = Self:prohibitUse(c)
|
|
|
|
end
|
2022-04-30 15:27:56 +08:00
|
|
|
return json.encode(ret)
|
|
|
|
end
|
|
|
|
|
|
|
|
---@param card string | integer
|
|
|
|
---@param to_select integer @ id of the target
|
|
|
|
---@param selected integer[] @ ids of selected targets
|
2024-01-25 03:13:57 +08:00
|
|
|
---@param extra_data_str string @ extra data
|
|
|
|
function CanUseCardToTarget(card, to_select, selected, extra_data_str)
|
|
|
|
local extra_data = extra_data_str == "" and nil or json.decode(extra_data_str)
|
2022-12-20 12:51:54 +08:00
|
|
|
if ClientInstance:getPlayerById(to_select).dead then
|
|
|
|
return "false"
|
|
|
|
end
|
2022-04-30 15:27:56 +08:00
|
|
|
local c ---@type Card
|
|
|
|
local selected_cards
|
|
|
|
if type(card) == "number" then
|
|
|
|
c = Fk:getCardById(card)
|
|
|
|
selected_cards = {card}
|
|
|
|
else
|
2022-09-14 13:01:10 +08:00
|
|
|
local t = json.decode(card)
|
2024-01-25 03:13:57 +08:00
|
|
|
return ActiveTargetFilter(t.skill, to_select, selected, t.subcards, extra_data)
|
2022-04-30 15:27:56 +08:00
|
|
|
end
|
|
|
|
|
2024-01-25 03:13:57 +08:00
|
|
|
local ret = c.skill:targetFilter(to_select, selected, selected_cards, c, extra_data)
|
2023-04-13 20:17:39 +08:00
|
|
|
ret = ret and not Self:isProhibited(Fk:currentRoom():getPlayerById(to_select), c)
|
2022-04-30 15:27:56 +08:00
|
|
|
return json.encode(ret)
|
|
|
|
end
|
|
|
|
|
|
|
|
---@param card string | integer
|
|
|
|
---@param to_select integer @ id of a card not selected
|
|
|
|
---@param selected_targets integer[] @ ids of selected players
|
|
|
|
function CanSelectCardForSkill(card, to_select, selected_targets)
|
|
|
|
local c ---@type Card
|
|
|
|
local selected_cards
|
|
|
|
if type(card) == "number" then
|
|
|
|
c = Fk:getCardById(card)
|
|
|
|
selected_cards = {card}
|
|
|
|
else
|
|
|
|
error()
|
|
|
|
end
|
|
|
|
|
|
|
|
local ret = c.skill:cardFilter(to_select, selected_cards, selected_targets)
|
|
|
|
return json.encode(ret)
|
|
|
|
end
|
|
|
|
|
|
|
|
---@param card string | integer
|
|
|
|
---@param selected_targets integer[] @ ids of selected players
|
|
|
|
function CardFeasible(card, selected_targets)
|
|
|
|
local c ---@type Card
|
|
|
|
local selected_cards
|
|
|
|
if type(card) == "number" then
|
|
|
|
c = Fk:getCardById(card)
|
|
|
|
selected_cards = {card}
|
|
|
|
else
|
2022-09-14 13:01:10 +08:00
|
|
|
local t = json.decode(card)
|
|
|
|
return ActiveFeasible(t.skill, selected_targets, t.subcards)
|
|
|
|
end
|
|
|
|
|
2023-02-26 15:01:14 +08:00
|
|
|
local ret = c.skill:feasible(selected_targets, selected_cards, Self, c)
|
2022-09-14 13:01:10 +08:00
|
|
|
return json.encode(ret)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Handle skills
|
|
|
|
|
|
|
|
function GetSkillData(skill_name)
|
|
|
|
local skill = Fk.skills[skill_name]
|
2023-04-10 21:34:23 +08:00
|
|
|
if not skill then return "null" end
|
2022-09-14 13:01:10 +08:00
|
|
|
local freq = "notactive"
|
2023-01-16 19:13:07 +08:00
|
|
|
if skill:isInstanceOf(ActiveSkill) or skill:isInstanceOf(ViewAsSkill) then
|
2022-09-14 13:01:10 +08:00
|
|
|
freq = "active"
|
|
|
|
end
|
2023-04-05 01:05:06 +08:00
|
|
|
local frequency
|
|
|
|
if skill.frequency == Skill.Limited then
|
|
|
|
frequency = "limit"
|
|
|
|
elseif skill.frequency == Skill.Wake then
|
|
|
|
frequency = "wake"
|
2023-05-28 18:45:54 +08:00
|
|
|
elseif skill.frequency == Skill.Quest then
|
|
|
|
frequency = "quest"
|
2023-04-05 01:05:06 +08:00
|
|
|
end
|
2022-09-14 13:01:10 +08:00
|
|
|
return json.encode{
|
|
|
|
skill = Fk:translate(skill_name),
|
|
|
|
orig_skill = skill_name,
|
2023-02-15 19:54:35 +08:00
|
|
|
extension = skill.package.extensionName,
|
2023-04-05 01:05:06 +08:00
|
|
|
freq = freq,
|
|
|
|
frequency = frequency,
|
2023-05-13 14:20:34 +08:00
|
|
|
switchSkillName = skill.switchSkillName,
|
2023-06-04 19:40:14 +08:00
|
|
|
isViewAsSkill = skill:isInstanceOf(ViewAsSkill),
|
2022-09-14 13:01:10 +08:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2024-01-25 03:13:57 +08:00
|
|
|
function ActiveCanUse(skill_name, extra_data_str)
|
|
|
|
local extra_data = extra_data_str == "" and nil or json.decode(extra_data_str)
|
2022-09-14 13:01:10 +08:00
|
|
|
local skill = Fk.skills[skill_name]
|
|
|
|
local ret = false
|
2023-01-16 19:13:07 +08:00
|
|
|
if skill then
|
|
|
|
if skill:isInstanceOf(ActiveSkill) then
|
2024-01-25 03:13:57 +08:00
|
|
|
ret = skill:canUse(Self, extra_data)
|
2023-01-16 19:13:07 +08:00
|
|
|
elseif skill:isInstanceOf(ViewAsSkill) then
|
|
|
|
ret = skill:enabledAtPlay(Self)
|
2023-01-29 18:11:41 +08:00
|
|
|
if ret then
|
|
|
|
local exp = Exppattern:Parse(skill.pattern)
|
|
|
|
local cnames = {}
|
|
|
|
for _, m in ipairs(exp.matchers) do
|
2023-05-28 12:22:43 +08:00
|
|
|
if m.name then
|
|
|
|
table.insertTable(cnames, m.name)
|
2023-07-16 15:29:20 +08:00
|
|
|
end
|
|
|
|
if m.trueName then
|
2023-05-28 12:22:43 +08:00
|
|
|
table.insertTable(cnames, m.trueName)
|
|
|
|
end
|
2023-01-29 18:11:41 +08:00
|
|
|
end
|
|
|
|
for _, n in ipairs(cnames) do
|
|
|
|
local c = Fk:cloneCard(n)
|
2023-07-16 15:29:20 +08:00
|
|
|
c.skillName = skill_name
|
2024-01-25 03:13:57 +08:00
|
|
|
ret = c.skill:canUse(Self, c, extra_data)
|
2023-01-29 18:11:41 +08:00
|
|
|
if ret then break end
|
|
|
|
end
|
|
|
|
end
|
2023-01-16 19:13:07 +08:00
|
|
|
end
|
2022-09-14 13:01:10 +08:00
|
|
|
end
|
|
|
|
return json.encode(ret)
|
2023-06-16 10:58:28 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
function ActiveSkillPrompt(skill_name, selected, selected_targets)
|
|
|
|
local skill = Fk.skills[skill_name]
|
|
|
|
local ret = false
|
|
|
|
if skill then
|
|
|
|
if type(skill.prompt) == "function" then
|
|
|
|
ret = skill:prompt(selected, selected_targets)
|
|
|
|
else
|
|
|
|
ret = skill.prompt
|
|
|
|
end
|
|
|
|
end
|
2023-06-16 18:01:51 +08:00
|
|
|
return json.encode(ret or "")
|
2022-09-14 13:01:10 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
function ActiveCardFilter(skill_name, to_select, selected, selected_targets)
|
|
|
|
local skill = Fk.skills[skill_name]
|
|
|
|
local ret = false
|
2023-01-16 19:13:07 +08:00
|
|
|
if skill then
|
|
|
|
if skill:isInstanceOf(ActiveSkill) then
|
|
|
|
ret = skill:cardFilter(to_select, selected, selected_targets)
|
|
|
|
elseif skill:isInstanceOf(ViewAsSkill) then
|
|
|
|
ret = skill:cardFilter(to_select, selected)
|
|
|
|
end
|
2022-04-30 15:27:56 +08:00
|
|
|
end
|
2022-09-14 13:01:10 +08:00
|
|
|
return json.encode(ret)
|
|
|
|
end
|
2022-04-30 15:27:56 +08:00
|
|
|
|
2024-01-25 03:13:57 +08:00
|
|
|
function ActiveTargetFilter(skill_name, to_select, selected, selected_cards, extra_data)
|
2022-09-14 13:01:10 +08:00
|
|
|
local skill = Fk.skills[skill_name]
|
|
|
|
local ret = false
|
2023-01-16 19:13:07 +08:00
|
|
|
if skill then
|
|
|
|
if skill:isInstanceOf(ActiveSkill) then
|
|
|
|
ret = skill:targetFilter(to_select, selected, selected_cards)
|
|
|
|
elseif skill:isInstanceOf(ViewAsSkill) then
|
|
|
|
local card = skill:viewAs(selected_cards)
|
|
|
|
if card then
|
2024-01-25 03:13:57 +08:00
|
|
|
ret = card.skill:targetFilter(to_select, selected, selected_cards, card, extra_data)
|
2023-04-27 14:15:08 +08:00
|
|
|
ret = ret and not Self:isProhibited(Fk:currentRoom():getPlayerById(to_select), card)
|
2023-01-16 19:13:07 +08:00
|
|
|
end
|
|
|
|
end
|
2022-09-14 13:01:10 +08:00
|
|
|
end
|
2022-04-30 15:27:56 +08:00
|
|
|
return json.encode(ret)
|
2022-04-15 18:37:20 +08:00
|
|
|
end
|
2022-05-01 18:37:13 +08:00
|
|
|
|
2022-09-14 13:01:10 +08:00
|
|
|
function ActiveFeasible(skill_name, selected, selected_cards)
|
|
|
|
local skill = Fk.skills[skill_name]
|
|
|
|
local ret = false
|
2023-01-16 19:13:07 +08:00
|
|
|
if skill then
|
|
|
|
if skill:isInstanceOf(ActiveSkill) then
|
2023-02-26 15:01:14 +08:00
|
|
|
ret = skill:feasible(selected, selected_cards, Self, nil)
|
2023-01-16 19:13:07 +08:00
|
|
|
elseif skill:isInstanceOf(ViewAsSkill) then
|
|
|
|
local card = skill:viewAs(selected_cards)
|
|
|
|
if card then
|
2023-02-26 15:01:14 +08:00
|
|
|
ret = card.skill:feasible(selected, selected_cards, Self, card)
|
2023-01-16 19:13:07 +08:00
|
|
|
end
|
|
|
|
end
|
2022-09-14 13:01:10 +08:00
|
|
|
end
|
|
|
|
return json.encode(ret)
|
|
|
|
end
|
|
|
|
|
|
|
|
function CanViewAs(skill_name, card_ids)
|
2023-01-16 19:13:07 +08:00
|
|
|
local skill = Fk.skills[skill_name]
|
|
|
|
local ret = false
|
|
|
|
if skill then
|
|
|
|
if skill:isInstanceOf(ViewAsSkill) then
|
|
|
|
ret = skill:viewAs(card_ids) ~= nil
|
|
|
|
elseif skill:isInstanceOf(ActiveSkill) then
|
|
|
|
ret = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return json.encode(ret)
|
|
|
|
end
|
|
|
|
|
2023-01-29 18:11:41 +08:00
|
|
|
-- card_name may be id, name of card, or json string
|
2023-01-16 19:13:07 +08:00
|
|
|
function CardFitPattern(card_name, pattern)
|
|
|
|
local exp = Exppattern:Parse(pattern)
|
2023-01-29 18:11:41 +08:00
|
|
|
local c
|
|
|
|
local ret = false
|
|
|
|
if type(card_name) == "number" then
|
|
|
|
c = Fk:getCardById(card_name)
|
|
|
|
ret = exp:match(c)
|
|
|
|
elseif string.sub(card_name, 1, 1) == "{" then
|
|
|
|
local data = json.decode(card_name)
|
|
|
|
local skill = Fk.skills[data.skill]
|
|
|
|
local selected_cards = data.subcards
|
|
|
|
if skill:isInstanceOf(ViewAsSkill) then
|
|
|
|
c = skill:viewAs(selected_cards)
|
|
|
|
if c then
|
|
|
|
ret = exp:match(c)
|
|
|
|
end
|
|
|
|
else
|
|
|
|
return "true"
|
|
|
|
end
|
|
|
|
else
|
|
|
|
ret = exp:matchExp(card_name)
|
|
|
|
end
|
2023-01-16 19:13:07 +08:00
|
|
|
return json.encode(ret)
|
|
|
|
end
|
|
|
|
|
|
|
|
function SkillFitPattern(skill_name, pattern)
|
|
|
|
local skill = Fk.skills[skill_name]
|
|
|
|
local ret = false
|
|
|
|
if skill and skill.pattern then
|
|
|
|
local exp = Exppattern:Parse(pattern)
|
|
|
|
ret = exp:matchExp(skill.pattern)
|
|
|
|
end
|
|
|
|
return json.encode(ret)
|
2022-09-14 13:01:10 +08:00
|
|
|
end
|
|
|
|
|
2023-08-02 23:01:28 +08:00
|
|
|
function CardProhibitedResponse(card)
|
|
|
|
local c ---@type Card
|
|
|
|
local ret = false
|
|
|
|
if type(card) == "number" then
|
|
|
|
c = Fk:getCardById(card)
|
|
|
|
else
|
|
|
|
local data = json.decode(card)
|
|
|
|
local skill = Fk.skills[data.skill]
|
|
|
|
local selected_cards = data.subcards
|
|
|
|
if skill:isInstanceOf(ViewAsSkill) then
|
|
|
|
c = skill:viewAs(selected_cards)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if c == nil then
|
|
|
|
return "true"
|
|
|
|
else
|
2023-11-07 21:14:51 +08:00
|
|
|
ret = Self:prohibitResponse(c)
|
2023-08-02 23:01:28 +08:00
|
|
|
end
|
2023-04-10 15:55:06 +08:00
|
|
|
return json.encode(ret)
|
|
|
|
end
|
|
|
|
|
2023-04-30 18:55:59 +08:00
|
|
|
function SkillCanResponse(skill_name, cardResponsing)
|
2023-01-29 18:11:41 +08:00
|
|
|
local skill = Fk.skills[skill_name]
|
|
|
|
local ret = false
|
|
|
|
if skill and skill:isInstanceOf(ViewAsSkill) then
|
2023-04-30 18:55:59 +08:00
|
|
|
ret = skill:enabledAtResponse(Self, cardResponsing)
|
2023-01-29 18:11:41 +08:00
|
|
|
end
|
|
|
|
return json.encode(ret)
|
|
|
|
end
|
|
|
|
|
|
|
|
function GetVirtualEquip(player, cid)
|
|
|
|
local c = ClientInstance:getPlayerById(player):getVirualEquip(cid)
|
|
|
|
if not c then return "null" end
|
|
|
|
return json.encode{
|
|
|
|
name = c.name,
|
|
|
|
cid = c.subcards[1],
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2023-03-07 10:21:56 +08:00
|
|
|
function GetExpandPileOfSkill(skillName)
|
|
|
|
local skill = Fk.skills[skillName]
|
2024-01-26 14:56:07 +08:00
|
|
|
if not skill then return "" end
|
|
|
|
local e = skill.expand_pile
|
|
|
|
if type(e) == "function" then
|
|
|
|
e = e(skill)
|
|
|
|
end
|
|
|
|
|
|
|
|
if type(e) == "table" then
|
|
|
|
return json.encode(e)
|
|
|
|
else
|
|
|
|
return e or ""
|
|
|
|
end
|
2023-03-07 10:21:56 +08:00
|
|
|
end
|
|
|
|
|
2023-03-14 00:12:02 +08:00
|
|
|
function GetGameModes()
|
|
|
|
local ret = {}
|
|
|
|
for k, v in pairs(Fk.game_modes) do
|
|
|
|
table.insert(ret, {
|
|
|
|
name = Fk:translate(v.name),
|
|
|
|
orig_name = v.name,
|
|
|
|
minPlayer = v.minPlayer,
|
|
|
|
maxPlayer = v.maxPlayer,
|
|
|
|
})
|
|
|
|
end
|
|
|
|
table.sort(ret, function(a, b) return a.name > b.name end)
|
|
|
|
return json.encode(ret)
|
|
|
|
end
|
|
|
|
|
2023-04-05 00:49:54 +08:00
|
|
|
function GetInteractionOfSkill(skill_name)
|
|
|
|
local skill = Fk.skills[skill_name]
|
2023-04-13 20:17:39 +08:00
|
|
|
if skill and skill.interaction then
|
2023-04-20 00:19:48 +08:00
|
|
|
return json.encode(skill:interaction())
|
2023-04-13 20:17:39 +08:00
|
|
|
end
|
|
|
|
return "null"
|
2023-04-05 00:49:54 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
function SetInteractionDataOfSkill(skill_name, data)
|
|
|
|
local skill = Fk.skills[skill_name]
|
2023-04-13 20:17:39 +08:00
|
|
|
if skill and skill.interaction then
|
2023-04-05 00:49:54 +08:00
|
|
|
skill.interaction.data = json.decode(data)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-04-27 14:15:08 +08:00
|
|
|
function ChangeSelf(pid)
|
|
|
|
local c = ClientInstance
|
|
|
|
c.client:changeSelf(pid) -- for qml
|
|
|
|
Self = c:getPlayerById(pid)
|
|
|
|
end
|
|
|
|
|
|
|
|
function GetPlayerHandcards(pid)
|
|
|
|
local c = ClientInstance
|
|
|
|
local p = c:getPlayerById(pid)
|
2023-12-12 19:07:49 +08:00
|
|
|
return p and json.encode(p.player_cards[Player.Hand]) or ""
|
2023-04-27 14:15:08 +08:00
|
|
|
end
|
|
|
|
|
2023-06-18 16:24:12 +08:00
|
|
|
function GetPlayerEquips(pid)
|
|
|
|
local c = ClientInstance
|
|
|
|
local p = c:getPlayerById(pid)
|
|
|
|
return json.encode(p.player_cards[Player.Equip])
|
|
|
|
end
|
|
|
|
|
2023-06-04 20:00:35 +08:00
|
|
|
function ResetClientLua()
|
2023-08-02 23:01:28 +08:00
|
|
|
local _data = ClientInstance.enter_room_data;
|
2023-06-04 20:00:35 +08:00
|
|
|
local data = ClientInstance.room_settings
|
|
|
|
Self = ClientPlayer:new(fk.Self)
|
|
|
|
ClientInstance = Client:new() -- clear old client data
|
|
|
|
ClientInstance.players = {Self}
|
|
|
|
ClientInstance.alive_players = {Self}
|
|
|
|
ClientInstance.discard_pile = {}
|
2023-08-02 23:01:28 +08:00
|
|
|
|
|
|
|
ClientInstance.enter_room_data = _data;
|
2023-06-04 20:00:35 +08:00
|
|
|
ClientInstance.room_settings = data
|
|
|
|
|
2023-06-16 13:26:02 +08:00
|
|
|
ClientInstance.disabled_packs = data.disabledPack
|
|
|
|
ClientInstance.disabled_generals = data.disabledGenerals
|
2023-06-04 20:00:35 +08:00
|
|
|
-- ClientInstance:notifyUI("EnterRoom", jsonData)
|
|
|
|
end
|
|
|
|
|
|
|
|
function ResetAddPlayer(j)
|
|
|
|
fk.client_callback["AddPlayer"](j)
|
|
|
|
end
|
|
|
|
|
|
|
|
function GetRoomConfig()
|
|
|
|
return json.encode(ClientInstance.room_settings)
|
|
|
|
end
|
|
|
|
|
2023-06-16 23:04:31 +08:00
|
|
|
function GetPlayerGameData(pid)
|
|
|
|
local c = ClientInstance
|
|
|
|
local p = c:getPlayerById(pid)
|
2023-12-28 12:11:24 +08:00
|
|
|
if not p then return "[0, 0, 0, 0]" end
|
2023-06-16 23:04:31 +08:00
|
|
|
local raw = p.player:getGameData()
|
|
|
|
local ret = {}
|
|
|
|
for _, i in fk.qlist(raw) do
|
|
|
|
table.insert(ret, i)
|
|
|
|
end
|
2023-12-28 12:11:24 +08:00
|
|
|
table.insert(ret, p.player:getTotalGameTime())
|
2023-06-16 23:04:31 +08:00
|
|
|
return json.encode(ret)
|
|
|
|
end
|
|
|
|
|
2023-06-19 21:56:06 +08:00
|
|
|
function SetPlayerGameData(pid, data)
|
|
|
|
local c = ClientInstance
|
|
|
|
local p = c:getPlayerById(pid)
|
2023-12-28 12:11:24 +08:00
|
|
|
local total, win, run = table.unpack(data)
|
|
|
|
p.player:setGameData(total, win, run)
|
2023-06-27 16:50:24 +08:00
|
|
|
table.insert(data, 1, pid)
|
|
|
|
ClientInstance:notifyUI("UpdateGameData", json.encode(data))
|
2023-06-19 21:56:06 +08:00
|
|
|
end
|
|
|
|
|
2023-06-23 22:18:11 +08:00
|
|
|
function FilterMyHandcards()
|
|
|
|
Self:filterHandcards()
|
|
|
|
end
|
|
|
|
|
2023-06-27 16:50:24 +08:00
|
|
|
function SetObserving(o)
|
|
|
|
ClientInstance.observing = o
|
|
|
|
end
|
|
|
|
|
2023-07-02 20:39:42 +08:00
|
|
|
function CheckSurrenderAvailable(playedTime)
|
|
|
|
local curMode = ClientInstance.room_settings.gameMode
|
|
|
|
return json.encode(Fk.game_modes[curMode]:surrenderFunc(playedTime))
|
|
|
|
end
|
|
|
|
|
2023-08-01 21:01:01 +08:00
|
|
|
function SaveRecord()
|
|
|
|
local c = ClientInstance
|
|
|
|
c.client:saveRecord(json.encode(c.record), c.record[2])
|
|
|
|
end
|
|
|
|
|
2023-09-19 14:27:54 +08:00
|
|
|
function GetCardProhibitReason(cid, method, pattern)
|
|
|
|
local card = Fk:getCardById(cid)
|
|
|
|
if not card then return "" end
|
|
|
|
if method == "play" and not card.skill:canUse(Self, card) then return "" end
|
|
|
|
if method ~= "play" and not card:matchPattern(pattern) then return "" end
|
|
|
|
if method == "play" then method = "use" end
|
|
|
|
|
|
|
|
local status_skills = Fk:currentRoom().status_skills[ProhibitSkill] or Util.DummyTable
|
|
|
|
local s
|
|
|
|
for _, skill in ipairs(status_skills) do
|
|
|
|
local fn = method == "use" and skill.prohibitUse or skill.prohibitResponse
|
|
|
|
if fn(skill, Self, card) then
|
|
|
|
s = skill
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if not s then return "" end
|
|
|
|
|
|
|
|
-- try to return a translated string
|
|
|
|
local skillName = s.name
|
|
|
|
local ret = Fk:translate(skillName)
|
|
|
|
if ret ~= skillName then
|
|
|
|
-- TODO: translate
|
|
|
|
return ret .. "禁" .. (method == "use" and "使用" or "打出")
|
|
|
|
elseif skillName:endsWith("_prohibit") and skillName:startsWith("#") then
|
|
|
|
return Fk:translate(skillName:sub(2, -10)) .. "禁" .. (method == "use" and "使用" or "打出")
|
2023-09-21 23:21:28 +08:00
|
|
|
else
|
|
|
|
return ret
|
2023-09-19 14:27:54 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-11-07 12:57:00 +08:00
|
|
|
function PoxiPrompt(poxi_type, data, extra_data)
|
2023-09-19 14:27:54 +08:00
|
|
|
local poxi = Fk.poxi_methods[poxi_type]
|
2024-04-02 00:56:04 +08:00
|
|
|
extra_data = extra_data and json.decode(extra_data)
|
2023-09-19 14:27:54 +08:00
|
|
|
if not poxi or not poxi.prompt then return "" end
|
|
|
|
if type(poxi.prompt) == "string" then return Fk:translate(poxi.prompt) end
|
2024-01-25 03:13:57 +08:00
|
|
|
return Fk:translate(poxi.prompt(data, extra_data))
|
2023-09-19 14:27:54 +08:00
|
|
|
end
|
|
|
|
|
2023-10-27 22:19:30 +08:00
|
|
|
function PoxiFilter(poxi_type, to_select, selected, data, extra_data)
|
2023-09-19 14:27:54 +08:00
|
|
|
local poxi = Fk.poxi_methods[poxi_type]
|
2024-04-02 00:56:04 +08:00
|
|
|
extra_data = extra_data and json.decode(extra_data)
|
2023-09-19 14:27:54 +08:00
|
|
|
if not poxi then return "false" end
|
2023-10-27 22:19:30 +08:00
|
|
|
return json.encode(poxi.card_filter(to_select, selected, data, extra_data))
|
2023-09-19 14:27:54 +08:00
|
|
|
end
|
|
|
|
|
2023-10-27 22:19:30 +08:00
|
|
|
function PoxiFeasible(poxi_type, selected, data, extra_data)
|
2023-09-19 14:27:54 +08:00
|
|
|
local poxi = Fk.poxi_methods[poxi_type]
|
2024-04-02 00:56:04 +08:00
|
|
|
extra_data = extra_data and json.decode(extra_data)
|
2023-09-19 14:27:54 +08:00
|
|
|
if not poxi then return "false" end
|
2023-10-27 22:19:30 +08:00
|
|
|
return json.encode(poxi.feasible(selected, data, extra_data))
|
2023-09-19 14:27:54 +08:00
|
|
|
end
|
|
|
|
|
2023-12-28 12:11:24 +08:00
|
|
|
function GetQmlMark(mtype, name, value, p)
|
2023-12-06 21:07:35 +08:00
|
|
|
local spec = Fk.qml_marks[mtype]
|
|
|
|
if not spec then return "{}" end
|
2023-12-28 12:11:24 +08:00
|
|
|
p = ClientInstance:getPlayerById(p)
|
2023-12-06 21:07:35 +08:00
|
|
|
value = json.decode(value)
|
|
|
|
return json.encode {
|
2023-12-28 12:11:24 +08:00
|
|
|
qml_path = type(spec.qml_path) == "function" and spec.qml_path(name, value, p) or spec.qml_path,
|
|
|
|
text = spec.how_to_show(name, value, p)
|
2023-12-06 21:07:35 +08:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2024-01-11 18:36:05 +08:00
|
|
|
function GetMiniGame(gtype, p, data)
|
|
|
|
local spec = Fk.mini_games[gtype]
|
|
|
|
p = ClientInstance:getPlayerById(p)
|
|
|
|
data = json.decode(data)
|
|
|
|
return json.encode {
|
|
|
|
qml_path = type(spec.qml_path) == "function" and spec.qml_path(p, data) or spec.qml_path,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2024-04-02 01:00:10 +08:00
|
|
|
function ReloadPackage(path)
|
|
|
|
Fk:reloadPackage(path)
|
|
|
|
end
|
|
|
|
|
2023-02-27 10:23:48 +08:00
|
|
|
dofile "lua/client/i18n/init.lua"
|