mirror of
https://github.com/Qsgs-Fans/FreeKill.git
synced 2024-11-15 19:22:25 +08:00
Use card (#19)
* the process of using card (uncompleted) * code style: tab is 2 spaces(not \t or 4 space) * update lua54.dll to MinGW version(no cygwin1.dll required) * basic ui logic * ActiveSkill * modidy ActiveSkill defaults * todo: defaultEquipSkill * client * send use card to server * playing phase, equip Co-authored-by: Ho-spair <linyuy@163.com>
This commit is contained in:
parent
fd2d7b4d10
commit
dedde94643
Before Width: | Height: | Size: 624 B After Width: | Height: | Size: 624 B |
Before Width: | Height: | Size: 371 B After Width: | Height: | Size: 371 B |
BIN
lib/win/lua54.dll
Normal file → Executable file
BIN
lib/win/lua54.dll
Normal file → Executable file
Binary file not shown.
|
@ -5,7 +5,6 @@ Client = class('Client')
|
|||
|
||||
-- load client classes
|
||||
ClientPlayer = require "client.clientplayer"
|
||||
dofile "lua/client/client_util.lua"
|
||||
|
||||
fk.client_callback = {}
|
||||
|
||||
|
@ -142,3 +141,4 @@ end
|
|||
|
||||
-- Create ClientInstance (used by Lua)
|
||||
ClientInstance = Client:new()
|
||||
dofile "lua/client/client_util.lua"
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
-- All functions in this file are used by Qml
|
||||
|
||||
function Translate(src)
|
||||
return Fk.translations[src]
|
||||
end
|
||||
|
@ -12,19 +14,31 @@ function GetGeneralData(name)
|
|||
}
|
||||
end
|
||||
|
||||
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",
|
||||
}
|
||||
|
||||
function GetCardData(id)
|
||||
local card = Fk.cards[id]
|
||||
if card == nil then return json.encode{
|
||||
cid = id,
|
||||
known = false
|
||||
} end
|
||||
return json.encode{
|
||||
local ret = {
|
||||
cid = id,
|
||||
name = card.name,
|
||||
number = card.number,
|
||||
suit = card:getSuitString(),
|
||||
color = card.color,
|
||||
subtype = cardSubtypeStrings[card.sub_type]
|
||||
}
|
||||
return json.encode(ret)
|
||||
end
|
||||
|
||||
function GetAllGeneralPack()
|
||||
|
@ -62,3 +76,70 @@ function GetCards(pack_name)
|
|||
end
|
||||
return json.encode(ret)
|
||||
end
|
||||
|
||||
---@param card string | integer
|
||||
---@param player integer
|
||||
function CanUseCard(card, player)
|
||||
local c ---@type Card
|
||||
if type(card) == "number" then
|
||||
c = Fk:getCardById(card)
|
||||
else
|
||||
error()
|
||||
end
|
||||
|
||||
local ret = c.skill:canUse(ClientInstance:findPlayer(player))
|
||||
return json.encode(ret)
|
||||
end
|
||||
|
||||
---@param card string | integer
|
||||
---@param to_select integer @ id of the target
|
||||
---@param selected integer[] @ ids of selected targets
|
||||
---@param selected_cards integer[] @ ids of selected cards
|
||||
function CanUseCardToTarget(card, to_select, selected)
|
||||
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:targetFilter(to_select, selected, selected_cards)
|
||||
return json.encode(ret)
|
||||
end
|
||||
|
||||
---@param card string | integer
|
||||
---@param to_select integer @ id of a card not selected
|
||||
---@param selected integer[] @ ids of selected cards
|
||||
---@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 integer[] @ ids of selected cards
|
||||
---@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
|
||||
error()
|
||||
end
|
||||
|
||||
local ret = c.skill:feasible(selected_cards, selected_targets)
|
||||
return json.encode(ret)
|
||||
end
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
---@field name string
|
||||
---@field suit Suit
|
||||
---@field number integer
|
||||
---@field trueName string
|
||||
---@field color Color
|
||||
---@field id integer
|
||||
---@field type CardType
|
||||
|
@ -26,10 +27,9 @@ Card.NoColor = 3
|
|||
|
||||
---@alias CardType integer
|
||||
|
||||
Card.TypeSkill = 1
|
||||
Card.TypeBasic = 2
|
||||
Card.TypeTrick = 3
|
||||
Card.TypeEquip = 4
|
||||
Card.TypeBasic = 1
|
||||
Card.TypeTrick = 2
|
||||
Card.TypeEquip = 3
|
||||
|
||||
---@alias CardSubtype integer
|
||||
|
||||
|
@ -57,6 +57,7 @@ function Card:initialize(name, suit, number, color)
|
|||
self.name = name
|
||||
self.suit = suit or Card.NoSuit
|
||||
self.number = number or 0
|
||||
self.trueName = name
|
||||
|
||||
if suit == Card.Spade or suit == Card.Club then
|
||||
self.color = Card.Black
|
||||
|
@ -72,6 +73,7 @@ function Card:initialize(name, suit, number, color)
|
|||
self.id = 0
|
||||
self.type = 0
|
||||
self.sub_type = Card.SubTypeNone
|
||||
self.skill = nil
|
||||
end
|
||||
|
||||
function Card:getSuitString()
|
||||
|
|
|
@ -11,6 +11,7 @@ end
|
|||
---@return BasicCard
|
||||
function BasicCard:clone(suit, number)
|
||||
local newCard = BasicCard:new(self.name, suit, number)
|
||||
newCard.skill = self.skill
|
||||
return newCard
|
||||
end
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
---@class EquipCard : Card
|
||||
---@field equipSkill Skill
|
||||
local EquipCard = Card:subclass("EquipCard")
|
||||
|
||||
function EquipCard:initialize(name, suit, number)
|
||||
Card.initialize(self, name, suit, number)
|
||||
self.type = Card.TypeEquip
|
||||
self.equipSkill = nil
|
||||
end
|
||||
|
||||
---@class Weapon : EquipCard
|
||||
|
@ -20,6 +22,7 @@ end
|
|||
---@return Weapon
|
||||
function Weapon:clone(suit, number)
|
||||
local newCard = Weapon:new(self.name, suit, number, self.attack_range)
|
||||
newCard.skill = self.skill
|
||||
return newCard
|
||||
end
|
||||
|
||||
|
@ -36,6 +39,7 @@ end
|
|||
---@return Armor
|
||||
function Armor:clone(suit, number)
|
||||
local newCard = Armor:new(self.name, suit, number)
|
||||
newCard.skill = self.skill
|
||||
return newCard
|
||||
end
|
||||
|
||||
|
@ -52,6 +56,7 @@ end
|
|||
---@return DefensiveRide
|
||||
function DefensiveRide:clone(suit, number)
|
||||
local newCard = DefensiveRide:new(self.name, suit, number)
|
||||
newCard.skill = self.skill
|
||||
return newCard
|
||||
end
|
||||
|
||||
|
@ -68,6 +73,7 @@ end
|
|||
---@return OffensiveRide
|
||||
function OffensiveRide:clone(suit, number)
|
||||
local newCard = OffensiveRide:new(self.name, suit, number)
|
||||
newCard.skill = self.skill
|
||||
return newCard
|
||||
end
|
||||
|
||||
|
@ -84,6 +90,7 @@ end
|
|||
---@return Treasure
|
||||
function Treasure:clone(suit, number)
|
||||
local newCard = Treasure:new(self.name, suit, number)
|
||||
newCard.skill = self.skill
|
||||
return newCard
|
||||
end
|
||||
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
---@class SkillCard : Card
|
||||
local SkillCard = Card:subclass("SkillCard")
|
||||
|
||||
function SkillCard:initialize(name)
|
||||
Card.initialize(self, name, Card.NoSuit, 0)
|
||||
self.type = Card.TypeSkill
|
||||
end
|
||||
|
||||
return SkillCard
|
|
@ -11,6 +11,9 @@ end
|
|||
---@return TrickCard
|
||||
function TrickCard:clone(suit, number)
|
||||
local newCard = TrickCard:new(self.name, suit, number)
|
||||
|
||||
newCard.skill = self.skill
|
||||
|
||||
return newCard
|
||||
end
|
||||
|
||||
|
@ -27,6 +30,7 @@ end
|
|||
---@return DelayedTrickCard
|
||||
function DelayedTrickCard:clone(suit, number)
|
||||
local newCard = DelayedTrickCard:new(self.name, suit, number)
|
||||
newCard.skill = self.skill
|
||||
return newCard
|
||||
end
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
---@field mark table<string, integer>
|
||||
---@field player_cards table<integer, integer[]>
|
||||
---@field special_cards table<string, integer[]>
|
||||
---@field cardUsedHistory table<string, integer>
|
||||
local Player = class("Player")
|
||||
|
||||
---@alias Phase integer
|
||||
|
@ -65,6 +66,8 @@ function Player:initialize()
|
|||
[Player.Judge] = {},
|
||||
}
|
||||
self.special_cards = {}
|
||||
|
||||
self.cardUsedHistory = {}
|
||||
end
|
||||
|
||||
---@param general General
|
||||
|
@ -194,6 +197,18 @@ function Player:getCardIds(playerAreas, specialName)
|
|||
return cardIds
|
||||
end
|
||||
|
||||
---@param cardSubtype CardSubtype
|
||||
---@return integer|null
|
||||
function Player:getEquipment(cardSubtype)
|
||||
for _, cardId in ipairs(self.player_cards[Player.Equip]) do
|
||||
if Fk:getCardById(cardId).sub_type == cardSubtype then
|
||||
return cardId
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
function Player:getMaxCards()
|
||||
local baseValue = math.max(self.hp, 0)
|
||||
|
||||
|
@ -205,7 +220,7 @@ end
|
|||
function Player:getEquipBySubtype(subtype)
|
||||
local equipId = nil
|
||||
for _, id in ipairs(self.player_cards[Player.Equip]) do
|
||||
if Fk.getCardById(id).sub_type == subtype then
|
||||
if Fk:getCardById(id).sub_type == subtype then
|
||||
equipId = id
|
||||
break
|
||||
end
|
||||
|
@ -215,10 +230,23 @@ function Player:getEquipBySubtype(subtype)
|
|||
end
|
||||
|
||||
function Player:getAttackRange()
|
||||
local weapon = Fk.getCardById(self:getEquipBySubtype(Card.SubtypeWeapon))
|
||||
local weapon = Fk:getCardById(self:getEquipBySubtype(Card.SubtypeWeapon))
|
||||
local baseAttackRange = math.max(weapon and weapon.attack_range or 1, 0)
|
||||
|
||||
return math.max(baseAttackRange, 0)
|
||||
end
|
||||
|
||||
function Player:addCardUseHistory(cardName, num)
|
||||
assert(type(num) == "number" and num ~= 0)
|
||||
|
||||
self.cardUsedHistory[cardName] = self.cardUsedHistory[cardName] or 0
|
||||
self.cardUsedHistory[cardName] = self.cardUsedHistory[cardName] + num
|
||||
end
|
||||
|
||||
function Player:resetCardUseHistory(cardName)
|
||||
if self.cardUsedHistory[cardName] then
|
||||
self.cardUsedHistory[cardName] = 0
|
||||
end
|
||||
end
|
||||
|
||||
return Player
|
||||
|
|
57
lua/core/skill_type/active_skill.lua
Normal file
57
lua/core/skill_type/active_skill.lua
Normal file
|
@ -0,0 +1,57 @@
|
|||
--- ActiveSkill is a skill type like SkillCard+ViewAsSkill in QSanguosha
|
||||
---
|
||||
---@class ActiveSkill : Skill
|
||||
local ActiveSkill = Skill:subclass("ActiveSkill")
|
||||
|
||||
function ActiveSkill:initialize(name)
|
||||
Skill.initialize(self, name, Skill.NotFrequent)
|
||||
end
|
||||
|
||||
---------
|
||||
-- Note: these functions are used both client and ai
|
||||
------- {
|
||||
|
||||
--- Determine whether the skill can be used in playing phase
|
||||
---@param player Player
|
||||
function ActiveSkill:canUse(player)
|
||||
return true
|
||||
end
|
||||
|
||||
--- Determine whether a card can be selected by this skill
|
||||
--- only used in skill of players
|
||||
---@param to_select integer @ id of a card not selected
|
||||
---@param selected integer[] @ ids of selected cards
|
||||
---@param selected_targets integer[] @ ids of selected players
|
||||
function ActiveSkill:cardFilter(to_select, selected, selected_targets)
|
||||
return true
|
||||
end
|
||||
|
||||
--- Determine whether a target can be selected by this skill
|
||||
--- only used in skill of players
|
||||
---@param to_select integer @ id of the target
|
||||
---@param selected integer[] @ ids of selected targets
|
||||
---@param selected_cards integer[] @ ids of selected cards
|
||||
function ActiveSkill:targetFilter(to_select, selected, selected_cards)
|
||||
return false
|
||||
end
|
||||
|
||||
--- Determine if selected cards and targets are valid for this skill
|
||||
--- If returns true, the OK button should be enabled
|
||||
--- only used in skill of players
|
||||
---@param selected integer[] @ ids of selected cards
|
||||
---@param selected_targets integer[] @ ids of selected players
|
||||
function ActiveSkill:feasible(selected, selected_targets)
|
||||
return true
|
||||
end
|
||||
|
||||
------- }
|
||||
|
||||
---@param room Room
|
||||
---@param cardUseEvent CardUseStruct
|
||||
function ActiveSkill:onUse(room, cardUseEvent) end
|
||||
|
||||
---@param room Room
|
||||
---@param cardEffectEvent CardEffectEvent
|
||||
function ActiveSkill:onEffect(room, cardEffectEvent) end
|
||||
|
||||
return ActiveSkill
|
|
@ -151,3 +151,144 @@ function switch(param, case_table)
|
|||
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)
|
||||
room:sortPlayersByAction(aimEvent.tos[AimGroup.Undone])
|
||||
if aimEvent.targetGroup then
|
||||
TargetGroup:pushTargets(aimEvent.targetGroup, playerIds)
|
||||
end
|
||||
end
|
||||
|
||||
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 }
|
||||
|
|
264
lua/fk_ex.lua
264
lua/fk_ex.lua
|
@ -1,18 +1,16 @@
|
|||
-- load types for extension
|
||||
|
||||
SkillCard = require "core.card_type.skill"
|
||||
dofile "lua/server/event.lua"
|
||||
dofile "lua/server/system_enum.lua"
|
||||
TriggerSkill = require "core.skill_type.trigger"
|
||||
ActiveSkill = require "core.skill_type.active_skill"
|
||||
|
||||
BasicCard = require "core.card_type.basic"
|
||||
local Trick = require "core.card_type.trick"
|
||||
TrickCard, DelayedTrickCard = table.unpack(Trick)
|
||||
local Equip = require "core.card_type.equip"
|
||||
_, Weapon, Armor, DefensiveRide, OffensiveRide, Treasure = table.unpack(Equip)
|
||||
|
||||
dofile "lua/server/event.lua"
|
||||
dofile "lua/server/system_enum.lua"
|
||||
TriggerSkill = require "core.skill_type.trigger"
|
||||
|
||||
---@class CardSpec: Card
|
||||
|
||||
---@class SkillSpec: Skill
|
||||
|
||||
---@alias TrigFunc fun(self: TriggerSkill, event: Event, target: ServerPlayer, player: ServerPlayer):boolean
|
||||
|
@ -26,111 +24,6 @@ TriggerSkill = require "core.skill_type.trigger"
|
|||
---@field on_refresh TrigFunc
|
||||
---@field can_refresh TrigFunc
|
||||
|
||||
---@param spec CardSpec
|
||||
---@return BasicCard
|
||||
function fk.CreateBasicCard(spec)
|
||||
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
||||
if not spec.name then spec.name = spec.class_name
|
||||
elseif not spec.class_name then spec.class_name = spec.name end
|
||||
if spec.suit then assert(type(spec.suit) == "number") end
|
||||
if spec.number then assert(type(spec.number) == "number") end
|
||||
|
||||
local card = BasicCard:new(spec.name, spec.suit, spec.number)
|
||||
return card
|
||||
end
|
||||
|
||||
---@param spec CardSpec
|
||||
---@return TrickCard
|
||||
function fk.CreateTrickCard(spec)
|
||||
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
||||
if not spec.name then spec.name = spec.class_name
|
||||
elseif not spec.class_name then spec.class_name = spec.name end
|
||||
if spec.suit then assert(type(spec.suit) == "number") end
|
||||
if spec.number then assert(type(spec.number) == "number") end
|
||||
|
||||
local card = TrickCard:new(spec.name, spec.suit, spec.number)
|
||||
return card
|
||||
end
|
||||
|
||||
---@param spec CardSpec
|
||||
---@return DelayedTrickCard
|
||||
function fk.CreateDelayedTrickCard(spec)
|
||||
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
||||
if not spec.name then spec.name = spec.class_name
|
||||
elseif not spec.class_name then spec.class_name = spec.name end
|
||||
if spec.suit then assert(type(spec.suit) == "number") end
|
||||
if spec.number then assert(type(spec.number) == "number") end
|
||||
|
||||
local card = DelayedTrickCard:new(spec.name, spec.suit, spec.number)
|
||||
return card
|
||||
end
|
||||
|
||||
---@param spec CardSpec
|
||||
---@return Weapon
|
||||
function fk.CreateWeapon(spec)
|
||||
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
||||
if not spec.name then spec.name = spec.class_name
|
||||
elseif not spec.class_name then spec.class_name = spec.name end
|
||||
if spec.suit then assert(type(spec.suit) == "number") end
|
||||
if spec.number then assert(type(spec.number) == "number") end
|
||||
if spec.attack_range then assert(type(spec.attack_range) == "number" and spec.attack_range >= 0) end
|
||||
|
||||
local card = Weapon:new(spec.name, spec.suit, spec.number, spec.attack_range)
|
||||
return card
|
||||
end
|
||||
|
||||
---@param spec CardSpec
|
||||
---@return Armor
|
||||
function fk.CreateArmor(spec)
|
||||
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
||||
if not spec.name then spec.name = spec.class_name
|
||||
elseif not spec.class_name then spec.class_name = spec.name end
|
||||
if spec.suit then assert(type(spec.suit) == "number") end
|
||||
if spec.number then assert(type(spec.number) == "number") end
|
||||
|
||||
local card = Armor:new(spec.name, spec.suit, spec.number)
|
||||
return card
|
||||
end
|
||||
|
||||
---@param spec CardSpec
|
||||
---@return DefensiveRide
|
||||
function fk.CreateDefensiveRide(spec)
|
||||
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
||||
if not spec.name then spec.name = spec.class_name
|
||||
elseif not spec.class_name then spec.class_name = spec.name end
|
||||
if spec.suit then assert(type(spec.suit) == "number") end
|
||||
if spec.number then assert(type(spec.number) == "number") end
|
||||
|
||||
local card = DefensiveRide:new(spec.name, spec.suit, spec.number)
|
||||
return card
|
||||
end
|
||||
|
||||
---@param spec CardSpec
|
||||
---@return OffensiveRide
|
||||
function fk.CreateOffensiveRide(spec)
|
||||
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
||||
if not spec.name then spec.name = spec.class_name
|
||||
elseif not spec.class_name then spec.class_name = spec.name end
|
||||
if spec.suit then assert(type(spec.suit) == "number") end
|
||||
if spec.number then assert(type(spec.number) == "number") end
|
||||
|
||||
local card = OffensiveRide:new(spec.name, spec.suit, spec.number)
|
||||
return card
|
||||
end
|
||||
|
||||
---@param spec CardSpec
|
||||
---@return Treasure
|
||||
function fk.CreateTreasure(spec)
|
||||
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
||||
if not spec.name then spec.name = spec.class_name
|
||||
elseif not spec.class_name then spec.class_name = spec.name end
|
||||
if spec.suit then assert(type(spec.suit) == "number") end
|
||||
if spec.number then assert(type(spec.number) == "number") end
|
||||
|
||||
local card = Treasure:new(spec.name, spec.suit, spec.number)
|
||||
return card
|
||||
end
|
||||
|
||||
---@param spec TriggerSkillSpec
|
||||
---@return TriggerSkill
|
||||
function fk.CreateTriggerSkill(spec)
|
||||
|
@ -189,3 +82,150 @@ function fk.CreateTriggerSkill(spec)
|
|||
end
|
||||
return skill
|
||||
end
|
||||
|
||||
---@class ActiveSkillSpec: SkillSpec
|
||||
---@field can_use fun(self: ActiveSkill, player: Player): boolean
|
||||
---@field card_filter fun(self: ActiveSkill, to_select: integer, selected: integer[], selected_targets: integer[]): boolean
|
||||
---@field target_filter fun(self: ActiveSkill, to_select: integer, selected: integer[], selected_cards: integer[]): boolean
|
||||
---@field feasible fun(self: ActiveSkill, selected: integer[], selected_targets: integer[]): boolean
|
||||
---@field on_use fun(self: ActiveSkill, room: Room, cardUseEvent: CardUseStruct): boolean
|
||||
---@field on_effect fun(self: ActiveSkill, room: Room, cardEffectEvent: CardEffectEvent): boolean
|
||||
|
||||
---@param spec ActiveSkillSpec
|
||||
---@return ActiveSkill
|
||||
function fk.CreateActiveSkill(spec)
|
||||
assert(type(spec.name) == "string")
|
||||
local skill = ActiveSkill:new(spec.name)
|
||||
if spec.can_use then skill.canUse = spec.can_use end
|
||||
if spec.card_filter then skill.cardFilter = spec.card_filter end
|
||||
if spec.target_filter then skill.targetFilter = spec.target_filter end
|
||||
if spec.feasible then skill.feasible = spec.feasible end
|
||||
if spec.on_use then skill.onUse = spec.on_use end
|
||||
if spec.on_effect then skill.onEffect = spec.on_effect end
|
||||
return skill
|
||||
end
|
||||
|
||||
---@class CardSpec: Card
|
||||
---@field skill Skill
|
||||
|
||||
local defaultCardSkill = fk.CreateActiveSkill{
|
||||
name = "default_card_skill",
|
||||
on_use = function(self, room, use)
|
||||
if not use.tos or #TargetGroup:getRealTargets(use.tos) == 0 then
|
||||
use.tos = { { use.from } }
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
---@param spec CardSpec
|
||||
---@return BasicCard
|
||||
function fk.CreateBasicCard(spec)
|
||||
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
||||
if not spec.name then spec.name = spec.class_name
|
||||
elseif not spec.class_name then spec.class_name = spec.name end
|
||||
if spec.suit then assert(type(spec.suit) == "number") end
|
||||
if spec.number then assert(type(spec.number) == "number") end
|
||||
|
||||
local card = BasicCard:new(spec.name, spec.suit, spec.number)
|
||||
card.skill = spec.skill or defaultCardSkill
|
||||
return card
|
||||
end
|
||||
|
||||
---@param spec CardSpec
|
||||
---@return TrickCard
|
||||
function fk.CreateTrickCard(spec)
|
||||
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
||||
if not spec.name then spec.name = spec.class_name
|
||||
elseif not spec.class_name then spec.class_name = spec.name end
|
||||
if spec.suit then assert(type(spec.suit) == "number") end
|
||||
if spec.number then assert(type(spec.number) == "number") end
|
||||
|
||||
local card = TrickCard:new(spec.name, spec.suit, spec.number)
|
||||
card.skill = spec.skill or defaultCardSkill
|
||||
return card
|
||||
end
|
||||
|
||||
---@param spec CardSpec
|
||||
---@return DelayedTrickCard
|
||||
function fk.CreateDelayedTrickCard(spec)
|
||||
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
||||
if not spec.name then spec.name = spec.class_name
|
||||
elseif not spec.class_name then spec.class_name = spec.name end
|
||||
if spec.suit then assert(type(spec.suit) == "number") end
|
||||
if spec.number then assert(type(spec.number) == "number") end
|
||||
|
||||
local card = DelayedTrickCard:new(spec.name, spec.suit, spec.number)
|
||||
card.skill = spec.skill or defaultCardSkill
|
||||
return card
|
||||
end
|
||||
|
||||
---@param spec CardSpec
|
||||
---@return Weapon
|
||||
function fk.CreateWeapon(spec)
|
||||
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
||||
if not spec.name then spec.name = spec.class_name
|
||||
elseif not spec.class_name then spec.class_name = spec.name end
|
||||
if spec.suit then assert(type(spec.suit) == "number") end
|
||||
if spec.number then assert(type(spec.number) == "number") end
|
||||
if spec.attack_range then assert(type(spec.attack_range) == "number" and spec.attack_range >= 0) end
|
||||
|
||||
local card = Weapon:new(spec.name, spec.suit, spec.number, spec.attack_range)
|
||||
card.skill = spec.skill or defaultCardSkill
|
||||
return card
|
||||
end
|
||||
|
||||
---@param spec CardSpec
|
||||
---@return Armor
|
||||
function fk.CreateArmor(spec)
|
||||
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
||||
if not spec.name then spec.name = spec.class_name
|
||||
elseif not spec.class_name then spec.class_name = spec.name end
|
||||
if spec.suit then assert(type(spec.suit) == "number") end
|
||||
if spec.number then assert(type(spec.number) == "number") end
|
||||
|
||||
local card = Armor:new(spec.name, spec.suit, spec.number)
|
||||
card.skill = spec.skill or defaultCardSkill
|
||||
return card
|
||||
end
|
||||
|
||||
---@param spec CardSpec
|
||||
---@return DefensiveRide
|
||||
function fk.CreateDefensiveRide(spec)
|
||||
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
||||
if not spec.name then spec.name = spec.class_name
|
||||
elseif not spec.class_name then spec.class_name = spec.name end
|
||||
if spec.suit then assert(type(spec.suit) == "number") end
|
||||
if spec.number then assert(type(spec.number) == "number") end
|
||||
|
||||
local card = DefensiveRide:new(spec.name, spec.suit, spec.number)
|
||||
card.skill = spec.skill or defaultCardSkill
|
||||
return card
|
||||
end
|
||||
|
||||
---@param spec CardSpec
|
||||
---@return OffensiveRide
|
||||
function fk.CreateOffensiveRide(spec)
|
||||
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
||||
if not spec.name then spec.name = spec.class_name
|
||||
elseif not spec.class_name then spec.class_name = spec.name end
|
||||
if spec.suit then assert(type(spec.suit) == "number") end
|
||||
if spec.number then assert(type(spec.number) == "number") end
|
||||
|
||||
local card = OffensiveRide:new(spec.name, spec.suit, spec.number)
|
||||
card.skill = spec.skill or defaultCardSkill
|
||||
return card
|
||||
end
|
||||
|
||||
---@param spec CardSpec
|
||||
---@return Treasure
|
||||
function fk.CreateTreasure(spec)
|
||||
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
||||
if not spec.name then spec.name = spec.class_name
|
||||
elseif not spec.class_name then spec.class_name = spec.name end
|
||||
if spec.suit then assert(type(spec.suit) == "number") end
|
||||
if spec.number then assert(type(spec.number) == "number") end
|
||||
|
||||
local card = Treasure:new(spec.name, spec.suit, spec.number)
|
||||
card.skill = spec.skill or defaultCardSkill
|
||||
return card
|
||||
end
|
||||
|
|
|
@ -10,7 +10,8 @@ class = require "middleclass"
|
|||
json = require "json"
|
||||
|
||||
dofile "lua/lib/sha256.lua"
|
||||
dofile "lua/core/util.lua"
|
||||
local GroupUtils = require "core.util"
|
||||
TargetGroup, AimGroup = table.unpack(GroupUtils)
|
||||
dofile "lua/core/debug.lua"
|
||||
|
||||
math.randomseed(os.time())
|
||||
|
|
|
@ -50,4 +50,24 @@ fk.EnterDying = 38
|
|||
fk.Dying = 39
|
||||
fk.AfterDying = 40
|
||||
|
||||
fk.NumOfEvents = 41
|
||||
fk.PreCardUse = 41
|
||||
fk.AfterCardUseDeclared = 42
|
||||
fk.AfterCardTargetDeclared = 43
|
||||
fk.BeforeCardUseEffect = 44
|
||||
fk.CardUsing = 45
|
||||
fk.TargetSpecifying = 46
|
||||
fk.TargetConfirming = 47
|
||||
fk.TargetSpecified = 48
|
||||
fk.TargetConfirmed = 49
|
||||
fk.CardUseFinished = 50
|
||||
|
||||
fk.PreCardRespond = 51
|
||||
fk.CardResponding = 52
|
||||
fk.CardRespondFinished = 53
|
||||
|
||||
fk.PreCardEffect = 54
|
||||
fk.BeforeCardEffect = 55
|
||||
fk.CardEffecting = 56
|
||||
fk.CardEffectFinished = 57
|
||||
|
||||
fk.NumOfEvents = 58
|
||||
|
|
|
@ -416,6 +416,22 @@ function Room:getPlayerById(id)
|
|||
error("cannot find player by " .. id)
|
||||
end
|
||||
|
||||
---@param playerIds integer[]
|
||||
function Room:sortPlayersByAction(playerIds)
|
||||
|
||||
end
|
||||
|
||||
function Room:deadPlayerFilter(playerIds)
|
||||
local newPlayerIds = {}
|
||||
for _, playerId in ipairs(playerIds) do
|
||||
if self:getPlayerById(playerId):isAlive() then
|
||||
table.insert(newPlayerIds, playerId)
|
||||
end
|
||||
end
|
||||
|
||||
return newPlayerIds
|
||||
end
|
||||
|
||||
---@param sortBySeat boolean
|
||||
---@return ServerPlayer[]
|
||||
function Room:getAlivePlayers(sortBySeat)
|
||||
|
@ -718,6 +734,227 @@ function Room:killPlayer(deathStruct)
|
|||
self:gameOver()
|
||||
end
|
||||
|
||||
---@param room Room
|
||||
---@param cardUseEvent CardUseStruct
|
||||
---@param aimEventCollaborators table<string, AimStruct[]>
|
||||
---@return boolean
|
||||
local onAim = function(room, cardUseEvent, aimEventCollaborators)
|
||||
local eventStages = { fk.TargetSpecifying, fk.TargetConfirming, fk.TargetSpecified, fk.TargetConfirmed }
|
||||
for _, stage in ipairs(eventStages) do
|
||||
if not cardUseEvent.tos then
|
||||
return false
|
||||
end
|
||||
|
||||
room:sortPlayersByAction(cardUseEvent.tos)
|
||||
local aimGroup = AimGroup:initAimGroup(TargetGroup:getRealTargets(cardUseEvent.tos))
|
||||
|
||||
local collaboratorsIndex = {}
|
||||
local firstTarget = true
|
||||
repeat
|
||||
local toId = AimGroup:getUndoneOrDoneTargets(aimGroup)[1]
|
||||
---@type AimStruct
|
||||
local aimStruct
|
||||
local initialEvent = false
|
||||
collaboratorsIndex[toId] = collaboratorsIndex[toId] or 0
|
||||
|
||||
if not aimEventCollaborators[toId] or collaboratorsIndex[toId] >= #aimEventCollaborators[toId] then
|
||||
aimStruct = {
|
||||
from = cardUseEvent.from,
|
||||
cardId = cardUseEvent.cardId,
|
||||
to = toId,
|
||||
targetGroup = cardUseEvent.tos,
|
||||
nullifiedTargets = cardUseEvent.nullifiedTargets or {},
|
||||
tos = aimGroup,
|
||||
firstTarget = firstTarget,
|
||||
additionalDamage = cardUseEvent.addtionalDamage
|
||||
}
|
||||
|
||||
collaboratorsIndex[toId] = 1
|
||||
initialEvent = true
|
||||
else
|
||||
aimStruct = aimEventCollaborators[toId][collaboratorsIndex[toId]]
|
||||
aimStruct.from = cardUseEvent.from
|
||||
aimStruct.cardId = cardUseEvent.cardId
|
||||
aimStruct.tos = aimGroup
|
||||
aimStruct.targetGroup = cardUseEvent.tos
|
||||
aimStruct.nullifiedTargets = cardUseEvent.nullifiedTargets or {}
|
||||
aimStruct.firstTarget = firstTarget
|
||||
end
|
||||
|
||||
firstTarget = false
|
||||
|
||||
if room.logic:trigger(stage, (stage == fk.TargetSpecifying or stage == fk.TargetSpecified) and room:getPlayerById(aimStruct.from) or room:getPlayerById(aimStruct.to), aimStruct) then
|
||||
return false
|
||||
end
|
||||
AimGroup:removeDeadTargets(room, aimStruct)
|
||||
|
||||
local aimEventTargetGroup = aimStruct.targetGroup
|
||||
if aimEventTargetGroup then
|
||||
room:sortPlayersByAction(aimEventTargetGroup)
|
||||
end
|
||||
|
||||
cardUseEvent.from = aimStruct.from
|
||||
cardUseEvent.tos = aimEventTargetGroup
|
||||
cardUseEvent.nullifiedTargets = aimStruct.nullifiedTargets
|
||||
|
||||
if #AimGroup:getAllTargets(aimStruct.tos) == 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
local cancelledTargets = AimGroup:getCancelledTargets(aimStruct.tos)
|
||||
if #cancelledTargets > 0 then
|
||||
for _, target in ipairs(cancelledTargets) do
|
||||
aimEventCollaborators[target] = {}
|
||||
collaboratorsIndex[target] = 0
|
||||
end
|
||||
end
|
||||
aimStruct.tos[AimGroup.Cancelled] = {}
|
||||
|
||||
aimEventCollaborators[toId] = aimEventCollaborators[toId] or {}
|
||||
if not room:getPlayerById(toId):isAlive() then
|
||||
if initialEvent then
|
||||
table.insert(aimEventCollaborators[toId], aimStruct)
|
||||
else
|
||||
aimEventCollaborators[toId][collaboratorsIndex[toId]] = aimStruct
|
||||
end
|
||||
end
|
||||
|
||||
AimGroup:setTargetDone(aimStruct.tos, toId)
|
||||
aimGroup = aimStruct.tos
|
||||
until #AimGroup:getUndoneOrDoneTargets(aimGroup) == 0
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
---@param cardUseEvent CardUseStruct
|
||||
---@return boolean
|
||||
function Room:useCard(cardUseEvent)
|
||||
self:moveCards({
|
||||
ids = { cardUseEvent.cardId },
|
||||
from = cardUseEvent.customFrom or cardUseEvent.from,
|
||||
toArea = Card.Processing,
|
||||
moveReason = fk.ReasonUse,
|
||||
})
|
||||
|
||||
if Fk:getCardById(cardUseEvent.cardId).skill then
|
||||
Fk:getCardById(cardUseEvent.cardId).skill:onUse(self, cardUseEvent)
|
||||
end
|
||||
if self.logic:trigger(fk.PreCardUse, self:getPlayerById(cardUseEvent.from), cardUseEvent) then
|
||||
return false
|
||||
end
|
||||
|
||||
if not cardUseEvent.extraUse then
|
||||
self:getPlayerById(cardUseEvent.from):addCardUseHistory(Fk:getCardById(cardUseEvent.cardId).trueName, 1)
|
||||
end
|
||||
|
||||
if cardUseEvent.responseToEvent then
|
||||
cardUseEvent.responseToEvent.cardIdsResponded = cardUseEvent.responseToEvent.cardIdsResponded or {}
|
||||
table.insert(cardUseEvent.responseToEvent.cardIdsResponded, cardUseEvent.cardId)
|
||||
end
|
||||
|
||||
for _, event in ipairs({ fk.AfterCardUseDeclared, fk.AfterCardTargetDeclared, fk.BeforeCardUseEffect, fk.CardUsing }) do
|
||||
-- TODO: need to complete the cards for response
|
||||
|
||||
self.logic:trigger(event, self:getPlayerById(cardUseEvent.from), cardUseEvent)
|
||||
if event == fk.CardUsing then
|
||||
---@type table<string, AimStruct>
|
||||
local aimEventCollaborators = {}
|
||||
if cardUseEvent.tos and not onAim(self, cardUseEvent, aimEventCollaborators) then
|
||||
break
|
||||
end
|
||||
|
||||
if Fk:getCardById(cardUseEvent.cardId).type == Card.TypeEquip then
|
||||
if self:getCardArea(cardUseEvent.cardId) ~= Card.Processing then
|
||||
break
|
||||
end
|
||||
|
||||
if self:getPlayerById(TargetGroup:getRealTargets(cardUseEvent.tos)[1]).dead then
|
||||
self.moveCards({
|
||||
ids = { cardUseEvent.cardId },
|
||||
toArea = Card.DiscardPile,
|
||||
moveReason = fk.ReasonPutIntoDiscardPile,
|
||||
})
|
||||
else
|
||||
local target = TargetGroup:getRealTargets(cardUseEvent.tos)[1]
|
||||
local existingEquipId = self:getPlayerById(target):getEquipment(Fk:getCardById(cardUseEvent.cardId).sub_type)
|
||||
if existingEquipId then
|
||||
self:moveCards(
|
||||
{
|
||||
ids = { existingEquipId },
|
||||
from = target,
|
||||
toArea = Card.DiscardPile,
|
||||
moveReason = fk.ReasonPutIntoDiscardPile,
|
||||
},
|
||||
{
|
||||
ids = { cardUseEvent.cardId },
|
||||
to = target,
|
||||
toArea = Card.PlayerEquip,
|
||||
moveReason = fk.ReasonUse,
|
||||
}
|
||||
)
|
||||
else
|
||||
self:moveCards({
|
||||
ids = { cardUseEvent.cardId },
|
||||
to = target,
|
||||
toArea = Card.PlayerEquip,
|
||||
moveReason = fk.ReasonUse,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
break
|
||||
elseif Fk:getCardById(cardUseEvent.cardId).sub_type == Card.SubtypeDelayedTrick then
|
||||
if self:getCardArea(cardUseEvent.cardId) ~= Card.Processing then
|
||||
break
|
||||
end
|
||||
|
||||
local target = TargetGroup:getRealTargets(cardUseEvent.tos)[1]
|
||||
if not self:getPlayerById(target).dead then
|
||||
local findSameCard = false
|
||||
for _, cardId in ipairs(self:getPlayerById(target):getCardIds(Player.Equip)) do
|
||||
if Fk:getCardById(cardId).trueName == Fk:getCardById(cardUseEvent.cardId) then
|
||||
findSameCard = true
|
||||
end
|
||||
end
|
||||
|
||||
if not findSameCard then
|
||||
self:moveCards({
|
||||
ids = { cardUseEvent.cardId },
|
||||
to = target,
|
||||
toArea = Card.PlayerJudge,
|
||||
moveReason = fk.ReasonUse,
|
||||
})
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
self:moveCards({
|
||||
ids = { cardUseEvent.cardId },
|
||||
toArea = Card.DiscardPile,
|
||||
moveReason = fk.ReasonPutIntoDiscardPile,
|
||||
})
|
||||
|
||||
break
|
||||
end
|
||||
|
||||
if Fk:getCardById(cardUseEvent.cardId).skill then
|
||||
Fk:getCardById(cardUseEvent.cardId).skill:onEffect(self, cardUseEvent)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.logic:trigger(fk.CardUseFinished, self:getPlayerById(cardUseEvent.from), cardUseEvent)
|
||||
if self:getCardArea(cardUseEvent.cardId) == Card.Processing then
|
||||
self:moveCards({
|
||||
ids = { cardUseEvent.cardId },
|
||||
toArea = Card.DiscardPile,
|
||||
moveReason = fk.ReasonPutIntoDiscardPile,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
fk.room_callback["QuitRoom"] = function(jsonData)
|
||||
-- jsonData: [ int uid ]
|
||||
local data = json.decode(jsonData)
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
---@alias DyingStruct { who: integer, damage: DamageStruct }
|
||||
---@alias DeathStruct { who: integer, damage: DamageStruct }
|
||||
|
||||
---@alias CardUseStruct { from: integer, tos: TargetGroup, cardId: integer, toCardId: integer|null, responseToEvent: CardUseStruct|null, nullifiedTargets: interger[]|null, extraUse: boolean|null, disresponsiveList: integer[]|null, unoffsetableList: integer[]|null, addtionalDamage: integer|null, customFrom: integer|null, cardIdsResponded: integer[]|null }
|
||||
---@alias AimStruct { from: integer, cardId: integer, tos: AimGroup, to: integer, targetGroup: TargetGroup|null, nullifiedTargets: integer[]|null, firstTarget: boolean, additionalDamage: integer|null, disresponsive: boolean|null, unoffsetableList: boolean|null }
|
||||
---@alias CardEffectEvent { from: integer, tos: TargetGroup, cardId: integer, toCardId: integer|null, responseToEvent: CardUseStruct|null, nullifiedTargets: interger[]|null, extraUse: boolean|null, disresponsiveList: integer[]|null, unoffsetableList: integer[]|null, addtionalDamage: integer|null, customFrom: integer|null, cardIdsResponded: integer[]|null }
|
||||
|
||||
---@alias MoveReason integer
|
||||
|
||||
|
@ -21,6 +24,8 @@ fk.ReasonPut = 5
|
|||
fk.ReasonPutIntoDiscardPile = 6
|
||||
fk.ReasonPrey = 7
|
||||
fk.ReasonExchange = 8
|
||||
fk.ReasonUse = 9
|
||||
fk.ReasonResonpse = 10
|
||||
|
||||
---@alias DamageType integer
|
||||
|
||||
|
|
|
@ -83,7 +83,22 @@ GameRule = fk.CreateTriggerSkill{
|
|||
room:drawCards(player, 2, self.name)
|
||||
end,
|
||||
[Player.Play] = function()
|
||||
room:askForSkillInvoke(player, "rule")
|
||||
while not player.dead do
|
||||
local result = room:doRequest(player, "PlayCard", player:getId())
|
||||
if result == "" then break end
|
||||
|
||||
local data = json.decode(result)
|
||||
local card = data.card
|
||||
local targets = data.targets
|
||||
local use = {} ---@type CardUseStruct
|
||||
use.from = player:getId()
|
||||
use.tos = {}
|
||||
for _, target in ipairs(targets) do
|
||||
table.insert(use.tos, { target })
|
||||
end
|
||||
use.cardId = card
|
||||
room:useCard(use)
|
||||
end
|
||||
end,
|
||||
[Player.Discard] = function()
|
||||
local discardNum = #player:getCardIds(Player.Hand) - player:getMaxCards()
|
||||
|
|
|
@ -167,10 +167,23 @@ extension:addCards({
|
|||
collateral:clone(Card.Club, 13),
|
||||
})
|
||||
|
||||
local exNihiloSkill = fk.CreateActiveSkill{
|
||||
name = "ex_nihilo_skill",
|
||||
on_use = function(self, room, cardUseEvent)
|
||||
if not cardUseEvent.tos or #TargetGroup:getRealTargets(cardUseEvent.tos) == 0 then
|
||||
cardUseEvent.tos = { { cardUseEvent.from } }
|
||||
end
|
||||
end,
|
||||
on_effect = function(self, room, cardEffectEvent)
|
||||
room:drawCards(room:getPlayerById(TargetGroup:getRealTargets(cardEffectEvent.tos)[1]), 2, "ex_nihilo")
|
||||
end
|
||||
}
|
||||
|
||||
local exNihilo = fk.CreateTrickCard{
|
||||
name = "ex_nihilo",
|
||||
suit = Card.Heart,
|
||||
number = 7,
|
||||
skill = exNihiloSkill,
|
||||
}
|
||||
Fk:loadTranslationTable{
|
||||
["ex_nihilo"] = "无中生有",
|
||||
|
|
|
@ -22,11 +22,11 @@ Item {
|
|||
GridLayout {
|
||||
columns: root.width / 98
|
||||
Repeater {
|
||||
model: JSON.parse(Backend.getCards(name))
|
||||
model: JSON.parse(Backend.callLuaFunction("GetCards", [name]))
|
||||
CardItem {
|
||||
autoBack: false
|
||||
Component.onCompleted: {
|
||||
let data = JSON.parse(Backend.getCardData(modelData));
|
||||
let data = JSON.parse(Backend.callLuaFunction("GetCardData", [modelData]));
|
||||
setData(data);
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ Item {
|
|||
|
||||
function loadPackages() {
|
||||
if (loaded) return;
|
||||
let packs = JSON.parse(Backend.getAllCardPack());
|
||||
let packs = JSON.parse(Backend.callLuaFunction("GetAllCardPack", []));
|
||||
packs.forEach((name) => packages.append({ name: name }));
|
||||
loaded = true;
|
||||
}
|
||||
|
|
|
@ -22,11 +22,11 @@ Item {
|
|||
GridLayout {
|
||||
columns: root.width / 98
|
||||
Repeater {
|
||||
model: JSON.parse(Backend.getGenerals(name))
|
||||
model: JSON.parse(Backend.callLuaFunction("GetGenerals", [name]))
|
||||
GeneralCardItem {
|
||||
autoBack: false
|
||||
Component.onCompleted: {
|
||||
let data = JSON.parse(Backend.getGeneralData(modelData));
|
||||
let data = JSON.parse(Backend.callLuaFunction("GetGeneralData", [modelData]));
|
||||
name = modelData;
|
||||
kingdom = data.kingdom;
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ Item {
|
|||
|
||||
function loadPackages() {
|
||||
if (loaded) return;
|
||||
let packs = JSON.parse(Backend.getAllGeneralPack());
|
||||
let packs = JSON.parse(Backend.callLuaFunction("GetAllGeneralPack", []));
|
||||
packs.forEach((name) => packages.append({ name: name }));
|
||||
loaded = true;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ Item {
|
|||
property alias popupBox: popupBox
|
||||
property alias promptText: prompt.text
|
||||
|
||||
property var selected_targets: []
|
||||
|
||||
// tmp
|
||||
Row {
|
||||
Button{text:"摸1牌"
|
||||
|
@ -68,6 +70,11 @@ Item {
|
|||
okCancel.visible = false;
|
||||
endPhaseButton.visible = false;
|
||||
|
||||
dashboard.disableAllCards();
|
||||
if (dashboard.pending_skill !== "")
|
||||
dashboard.stopPending();
|
||||
selected_targets = [];
|
||||
|
||||
if (popupBox.item != null) {
|
||||
popupBox.item.finished();
|
||||
}
|
||||
|
@ -79,6 +86,7 @@ Item {
|
|||
from: "*"; to: "playing"
|
||||
ScriptAction {
|
||||
script: {
|
||||
dashboard.enableCards();
|
||||
progress.visible = true;
|
||||
okCancel.visible = true;
|
||||
endPhaseButton.visible = true;
|
||||
|
@ -130,6 +138,7 @@ Item {
|
|||
id: photos
|
||||
model: photoModel
|
||||
Photo {
|
||||
playerid: model.id
|
||||
general: model.general
|
||||
screenName: model.screenName
|
||||
role: model.role
|
||||
|
@ -144,6 +153,10 @@ Item {
|
|||
chained: model.chained
|
||||
drank: model.drank
|
||||
isOwner: model.isOwner
|
||||
|
||||
onSelectedChanged: {
|
||||
Logic.updateSelectedTargets(playerid, selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,6 +183,7 @@ Item {
|
|||
width: roomScene.width
|
||||
anchors.top: roomArea.bottom
|
||||
|
||||
self.playerid: dashboardModel.id
|
||||
self.general: dashboardModel.general
|
||||
self.screenName: dashboardModel.screenName
|
||||
self.role: dashboardModel.role
|
||||
|
@ -184,6 +198,14 @@ Item {
|
|||
self.chained: dashboardModel.chained
|
||||
self.drank: dashboardModel.drank
|
||||
self.isOwner: dashboardModel.isOwner
|
||||
|
||||
onSelectedChanged: {
|
||||
Logic.updateSelectedTargets(self.playerid, selected);
|
||||
}
|
||||
|
||||
onCardSelected: {
|
||||
Logic.enableTargets(card);
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
|
|
|
@ -11,6 +11,16 @@ RowLayout {
|
|||
property alias delayedTrickArea: selfPhoto.delayedTrickArea
|
||||
property alias specialArea: selfPhoto.specialArea
|
||||
|
||||
property bool selected: selfPhoto.selected
|
||||
|
||||
property bool is_pending: false
|
||||
property string pending_skill: ""
|
||||
property var pending_card
|
||||
property var pendings: [] // int[], store cid
|
||||
property int selected_card: -1
|
||||
|
||||
signal cardSelected(var card)
|
||||
|
||||
Item {
|
||||
width: 40
|
||||
}
|
||||
|
@ -28,4 +38,131 @@ RowLayout {
|
|||
}
|
||||
|
||||
Item { width: 5 }
|
||||
|
||||
Connections {
|
||||
target: handcardAreaItem
|
||||
function onCardSelected(cardId, selected) {
|
||||
dashboard.selectCard(cardId, selected);
|
||||
}
|
||||
}
|
||||
|
||||
function disableAllCards() {
|
||||
handcardAreaItem.enableCards([]);
|
||||
}
|
||||
|
||||
function unSelectAll(expectId) {
|
||||
handcardAreaItem.unselectAll(expectId);
|
||||
}
|
||||
|
||||
function enableCards() {
|
||||
// TODO: expand pile
|
||||
let ids = [], cards = handcardAreaItem.cards;
|
||||
for (let i = 0; i < cards.length; i++) {
|
||||
if (JSON.parse(Backend.callLuaFunction("CanUseCard", [cards[i].cid, Self.id])))
|
||||
ids.push(cards[i].cid);
|
||||
}
|
||||
handcardAreaItem.enableCards(ids)
|
||||
}
|
||||
|
||||
function selectCard(cardId, selected) {
|
||||
if (pending_skill !== "") {
|
||||
if (selected) {
|
||||
pendings.push(cardId);
|
||||
} else {
|
||||
pendings.splice(pendings.indexOf(cardId), 1);
|
||||
}
|
||||
|
||||
updatePending();
|
||||
} else {
|
||||
if (selected) {
|
||||
handcardAreaItem.unselectAll(cardId);
|
||||
selected_card = cardId;
|
||||
} else {
|
||||
handcardAreaItem.unselectAll();
|
||||
selected_card = -1;
|
||||
}
|
||||
cardSelected(selected_card);
|
||||
}
|
||||
}
|
||||
|
||||
function getSelectedCard() {
|
||||
if (pending_skill !== "") {
|
||||
return JSON.stringify({
|
||||
skill: pending_skill,
|
||||
subcards: pendings
|
||||
});
|
||||
} else {
|
||||
return selected_card;
|
||||
}
|
||||
}
|
||||
|
||||
function updatePending() {
|
||||
if (pending_skill === "") return;
|
||||
|
||||
let enabled_cards = [];
|
||||
|
||||
handcardAreaItem.cards.forEach(function(card) {
|
||||
if (card.selected || Router.vs_view_filter(pending_skill, pendings, card.cid))
|
||||
enabled_cards.push(card.cid);
|
||||
});
|
||||
handcardAreaItem.enableCards(enabled_cards);
|
||||
|
||||
let equip;
|
||||
for (let i = 0; i < 5; i++) {
|
||||
equip = equipAreaItem.equips.itemAt(i);
|
||||
if (equip.selected || equip.cid !== -1 &&
|
||||
Router.vs_view_filter(pending_skill, pendings, equip.cid))
|
||||
enabled_cards.push(equip.cid);
|
||||
}
|
||||
equipAreaItem.enableCards(enabled_cards);
|
||||
|
||||
if (Router.vs_can_view_as(pending_skill, pendings)) {
|
||||
pending_card = {
|
||||
skill: pending_skill,
|
||||
subcards: pendings
|
||||
};
|
||||
cardSelected(JSON.stringify(pending_card));
|
||||
} else {
|
||||
pending_card = -1;
|
||||
cardSelected(pending_card);
|
||||
}
|
||||
}
|
||||
|
||||
function startPending(skill_name) {
|
||||
pending_skill = skill_name;
|
||||
pendings = [];
|
||||
handcardAreaItem.unselectAll();
|
||||
|
||||
// TODO: expand pile
|
||||
|
||||
// TODO: equipment
|
||||
|
||||
updatePending();
|
||||
}
|
||||
|
||||
function deactivateSkillButton() {
|
||||
for (let i = 0; i < headSkills.length; i++) {
|
||||
headSkillButtons.itemAt(i).pressed = false;
|
||||
}
|
||||
}
|
||||
|
||||
function stopPending() {
|
||||
pending_skill = "";
|
||||
pending_card = -1;
|
||||
|
||||
// TODO: expand pile
|
||||
|
||||
let equip;
|
||||
for (let i = 0; i < 5; i++) {
|
||||
equip = equipAreaItem.equips.itemAt(i);
|
||||
if (equip.name !== "") {
|
||||
equip.selected = false;
|
||||
equip.selectable = false;
|
||||
}
|
||||
}
|
||||
|
||||
pendings = [];
|
||||
handcardAreaItem.adjustCards();
|
||||
cardSelected(-1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ Item {
|
|||
let items = [];
|
||||
for (let i = 0; i < outputs.length; i++) {
|
||||
if (_contains(outputs[i])) {
|
||||
let state = JSON.parse(Backend.getCardData(outputs[i]))
|
||||
let state = JSON.parse(Backend.callLuaFunction("GetCardData", [outputs[i]]))
|
||||
state.x = parentPos.x;
|
||||
state.y = parentPos.y;
|
||||
state.opacity = 0;
|
||||
|
|
|
@ -9,6 +9,7 @@ Item {
|
|||
width: 175
|
||||
height: 233
|
||||
scale: 0.8
|
||||
property int playerid
|
||||
property string general: ""
|
||||
property string screenName: ""
|
||||
property string role: "unknown"
|
||||
|
@ -45,12 +46,63 @@ Item {
|
|||
NumberAnimation { duration: 600; easing.type: Easing.InOutQuad }
|
||||
}
|
||||
|
||||
states: [
|
||||
State { name: "normal" },
|
||||
State { name: "candidate" },
|
||||
State { name: "playing" }
|
||||
//State { name: "responding" },
|
||||
//State { name: "sos" }
|
||||
]
|
||||
|
||||
state: "normal"
|
||||
transitions: [
|
||||
Transition {
|
||||
from: "*"; to: "normal"
|
||||
ScriptAction {
|
||||
script: {
|
||||
animPlaying.stop();
|
||||
animSelectable.stop();
|
||||
animSelected.stop();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Transition {
|
||||
from: "*"; to: "playing"
|
||||
ScriptAction {
|
||||
script: {
|
||||
animPlaying.start();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Transition {
|
||||
from: "*"; to: "candidate"
|
||||
ScriptAction {
|
||||
script: {
|
||||
animSelectable.start();
|
||||
animSelected.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
PixmapAnimation {
|
||||
id: animFrame
|
||||
id: animPlaying
|
||||
source: "playing"
|
||||
anchors.centerIn: parent
|
||||
loop: true
|
||||
scale: 1.1
|
||||
visible: root.state === "playing"
|
||||
}
|
||||
|
||||
PixmapAnimation {
|
||||
id: animSelected
|
||||
source: "selected"
|
||||
anchors.centerIn: parent
|
||||
loop: true
|
||||
scale: 1.1
|
||||
visible: root.state === "candidate" && selected
|
||||
}
|
||||
|
||||
Image {
|
||||
|
@ -193,6 +245,15 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
if (parent.state != "candidate" || !parent.selectable)
|
||||
return;
|
||||
parent.selected = !parent.selected;
|
||||
}
|
||||
}
|
||||
|
||||
RoleComboBox {
|
||||
id: role
|
||||
value: root.role
|
||||
|
@ -202,6 +263,12 @@ Item {
|
|||
anchors.rightMargin: -4
|
||||
}
|
||||
|
||||
Image {
|
||||
visible: root.state === "candidate" && !selectable && !selected
|
||||
source: SkinBank.PHOTO_DIR + "disable"
|
||||
x: 31; y: -21
|
||||
}
|
||||
|
||||
GlowText {
|
||||
id: seatNum
|
||||
visible: !progressBar.visible
|
||||
|
@ -285,6 +352,7 @@ Item {
|
|||
source: "selectable"
|
||||
anchors.centerIn: parent
|
||||
loop: true
|
||||
visible: root.state === "candidate" && selectable
|
||||
}
|
||||
|
||||
InvisibleCardArea {
|
||||
|
@ -307,7 +375,7 @@ Item {
|
|||
onGeneralChanged: {
|
||||
if (!roomScene.isStarted) return;
|
||||
generalName.text = Backend.translate(general);
|
||||
let data = JSON.parse(Backend.getGeneralData(general));
|
||||
let data = JSON.parse(Backend.callLuaFunction("GetGeneralData", [general]));
|
||||
kingdom = data.kingdom;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ Item {
|
|||
text = "-1"
|
||||
icon = "horse";
|
||||
} else {
|
||||
text = name;
|
||||
text = Backend.translate(name);
|
||||
icon = name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,6 +61,15 @@ function arrangePhotos() {
|
|||
}
|
||||
|
||||
function doOkButton() {
|
||||
if (roomScene.state == "playing") {
|
||||
replyToServer(JSON.stringify(
|
||||
{
|
||||
card: dashboard.getSelectedCard(),
|
||||
targets: selected_targets
|
||||
}
|
||||
));
|
||||
return;
|
||||
}
|
||||
replyToServer("1");
|
||||
}
|
||||
|
||||
|
@ -218,6 +227,76 @@ callbacks["AddPlayer"] = function(jsonData) {
|
|||
}
|
||||
}
|
||||
|
||||
function enableTargets(card) { // card: int | { skill: string, subcards: int[] }
|
||||
let i = 0;
|
||||
let candidate = (!isNaN(card) && card !== -1) || typeof(card) === "string";
|
||||
let all_photos = [dashboard.self];
|
||||
for (i = 0; i < playerNum - 1; i++) {
|
||||
all_photos.push(photos.itemAt(i))
|
||||
}
|
||||
selected_targets = [];
|
||||
for (i = 0; i < playerNum; i++) {
|
||||
all_photos[i].selected = false;
|
||||
}
|
||||
|
||||
if (candidate) {
|
||||
let data = {
|
||||
ok_enabled: false,
|
||||
enabled_targets: []
|
||||
}
|
||||
|
||||
all_photos.forEach(photo => {
|
||||
photo.state = "candidate";
|
||||
let id = photo.playerid;
|
||||
let ret = JSON.parse(Backend.callLuaFunction(
|
||||
"CanUseCardToTarget",
|
||||
[card, id, selected_targets]
|
||||
));
|
||||
photo.selectable = ret;
|
||||
})
|
||||
|
||||
okButton.enabled = JSON.parse(Backend.callLuaFunction(
|
||||
"CardFeasible", [card, selected_targets]
|
||||
));
|
||||
} else {
|
||||
all_photos.forEach(photo => {
|
||||
photo.state = "normal";
|
||||
photo.selected = false;
|
||||
});
|
||||
|
||||
okButton.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
function updateSelectedTargets(playerid, selected) {
|
||||
let i = 0;
|
||||
let card = dashboard.getSelectedCard();
|
||||
let all_photos = [dashboard.self]
|
||||
for (i = 0; i < playerNum - 1; i++) {
|
||||
all_photos.push(photos.itemAt(i))
|
||||
}
|
||||
|
||||
if (selected) {
|
||||
selected_targets.push(playerid);
|
||||
} else {
|
||||
selected_targets.splice(selected_targets.indexOf(playerid), 1);
|
||||
}
|
||||
|
||||
all_photos.forEach(photo => {
|
||||
if (photo.selected) return;
|
||||
let id = photo.playerid;
|
||||
let ret = JSON.parse(Backend.callLuaFunction(
|
||||
"CanUseCardToTarget",
|
||||
[card, id, selected_targets]
|
||||
));
|
||||
photo.selectable = ret;
|
||||
})
|
||||
|
||||
okButton.enabled = JSON.parse(Backend.callLuaFunction(
|
||||
"CardFeasible", [card, selected_targets]
|
||||
));
|
||||
}
|
||||
|
||||
callbacks["RemovePlayer"] = function(jsonData) {
|
||||
// jsonData: int uid
|
||||
let uid = JSON.parse(jsonData)[0];
|
||||
|
@ -375,3 +454,12 @@ callbacks["MoveCards"] = function(jsonData) {
|
|||
let moves = JSON.parse(jsonData);
|
||||
moveCards(moves);
|
||||
}
|
||||
|
||||
callbacks["PlayCard"] = function(jsonData) {
|
||||
// jsonData: int playerId
|
||||
let playerId = parseInt(jsonData);
|
||||
if (playerId == Self.id) {
|
||||
roomScene.promptText = "Please use a card";
|
||||
roomScene.state = "playing";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,8 @@ int main(int argc, char *argv[])
|
|||
#endif
|
||||
engine->rootContext()->setContextProperty("Debugging", debugging);
|
||||
engine->load("qml/main.qml");
|
||||
if (engine->rootObjects().isEmpty())
|
||||
return -1;
|
||||
|
||||
int ret = app->exec();
|
||||
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>qml/main.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -85,70 +85,71 @@ bool QmlBackend::isDir(const QString &file) {
|
|||
return QFileInfo(file).isDir();
|
||||
}
|
||||
|
||||
#define CALLFUNC int err = lua_pcall(L, 1, 1, 0); \
|
||||
const char *result = lua_tostring(L, -1); \
|
||||
if (err) { \
|
||||
qDebug() << result; \
|
||||
lua_pop(L, 1); \
|
||||
return ""; \
|
||||
} \
|
||||
lua_pop(L, 1); \
|
||||
return QString(result); \
|
||||
|
||||
QString QmlBackend::translate(const QString &src) {
|
||||
lua_State *L = ClientInstance->getLuaState();
|
||||
lua_getglobal(L, "Translate");
|
||||
lua_pushstring(L, src.toUtf8().data());
|
||||
|
||||
CALLFUNC
|
||||
int err = lua_pcall(L, 1, 1, 0);
|
||||
const char *result = lua_tostring(L, -1);
|
||||
if (err) {
|
||||
qDebug() << result;
|
||||
lua_pop(L, 1);
|
||||
return "";
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
return QString(result);
|
||||
}
|
||||
|
||||
QString QmlBackend::getGeneralData(const QString &general_name) {
|
||||
void QmlBackend::pushLuaValue(lua_State *L, QVariant v) {
|
||||
QVariantList list;
|
||||
switch(v.type()) {
|
||||
case QVariant::Bool:
|
||||
lua_pushboolean(L, v.toBool());
|
||||
break;
|
||||
case QVariant::Int:
|
||||
case QVariant::UInt:
|
||||
lua_pushinteger(L, v.toInt());
|
||||
break;
|
||||
case QVariant::Double:
|
||||
lua_pushnumber(L, v.toDouble());
|
||||
break;
|
||||
case QVariant::String:
|
||||
lua_pushstring(L, v.toString().toUtf8().data());
|
||||
break;
|
||||
case QVariant::List:
|
||||
lua_newtable(L);
|
||||
list = v.toList();
|
||||
for (int i = 1; i <= list.length(); i++) {
|
||||
lua_pushinteger(L, i);
|
||||
pushLuaValue(L, list[i - 1]);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
qDebug() << "cannot handle QVariant type" << v.type();
|
||||
lua_pushnil(L);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QString QmlBackend::callLuaFunction(const QString &func_name,
|
||||
QVariantList params)
|
||||
{
|
||||
lua_State *L = ClientInstance->getLuaState();
|
||||
lua_getglobal(L, "GetGeneralData");
|
||||
lua_pushstring(L, general_name.toUtf8().data());
|
||||
lua_getglobal(L, func_name.toLatin1().data());
|
||||
|
||||
CALLFUNC
|
||||
foreach (QVariant v, params) {
|
||||
pushLuaValue(L, v);
|
||||
}
|
||||
|
||||
QString QmlBackend::getCardData(int id) {
|
||||
lua_State *L = ClientInstance->getLuaState();
|
||||
lua_getglobal(L, "GetCardData");
|
||||
lua_pushinteger(L, id);
|
||||
|
||||
CALLFUNC
|
||||
int err = lua_pcall(L, params.length(), 1, 0);
|
||||
const char *result = lua_tostring(L, -1);
|
||||
if (err) {
|
||||
qDebug() << result;
|
||||
lua_pop(L, 1);
|
||||
return "";
|
||||
}
|
||||
|
||||
QString QmlBackend::getAllGeneralPack() {
|
||||
lua_State *L = ClientInstance->getLuaState();
|
||||
lua_getglobal(L, "GetAllGeneralPack");
|
||||
lua_pushinteger(L, 0);
|
||||
|
||||
CALLFUNC
|
||||
lua_pop(L, 1);
|
||||
return QString(result);
|
||||
}
|
||||
|
||||
QString QmlBackend::getGenerals(const QString &pack_name) {
|
||||
lua_State *L = ClientInstance->getLuaState();
|
||||
lua_getglobal(L, "GetGenerals");
|
||||
lua_pushstring(L, pack_name.toUtf8().data());
|
||||
|
||||
CALLFUNC
|
||||
}
|
||||
|
||||
QString QmlBackend::getAllCardPack() {
|
||||
lua_State *L = ClientInstance->getLuaState();
|
||||
lua_getglobal(L, "GetAllCardPack");
|
||||
lua_pushinteger(L, 0);
|
||||
|
||||
CALLFUNC
|
||||
}
|
||||
|
||||
QString QmlBackend::getCards(const QString &pack_name) {
|
||||
lua_State *L = ClientInstance->getLuaState();
|
||||
lua_getglobal(L, "GetCards");
|
||||
lua_pushstring(L, pack_name.toUtf8().data());
|
||||
|
||||
CALLFUNC
|
||||
}
|
||||
|
||||
#undef CALLFUNC
|
||||
|
|
|
@ -27,18 +27,16 @@ public:
|
|||
|
||||
// read data from lua, call lua functions
|
||||
Q_INVOKABLE QString translate(const QString &src);
|
||||
Q_INVOKABLE QString getGeneralData(const QString &general_name);
|
||||
Q_INVOKABLE QString getCardData(int id);
|
||||
Q_INVOKABLE QString getAllGeneralPack();
|
||||
Q_INVOKABLE QString getGenerals(const QString &pack_name);
|
||||
Q_INVOKABLE QString getAllCardPack();
|
||||
Q_INVOKABLE QString getCards(const QString &pack_name);
|
||||
Q_INVOKABLE QString callLuaFunction(const QString &func_name,
|
||||
QVariantList params);
|
||||
|
||||
signals:
|
||||
void notifyUI(const QString &command, const QString &jsonData);
|
||||
|
||||
private:
|
||||
QQmlApplicationEngine *engine;
|
||||
|
||||
void pushLuaValue(lua_State *L, QVariant v);
|
||||
};
|
||||
|
||||
extern QmlBackend *Backend;
|
||||
|
|
Loading…
Reference in New Issue
Block a user