standard equip skills (#49)

* install and uninstall equip skill

* complete pr; filter skill viewAs equip

---------

Co-authored-by: notify <notify-ctrl@qq.com>
This commit is contained in:
Ho-spair 2023-02-15 21:20:40 +08:00 committed by GitHub
parent cc271bcdf8
commit 3fe92b4344
14 changed files with 201 additions and 38 deletions

View File

@ -83,7 +83,9 @@ function Client:moveCards(moves)
table.insert(self.discard_pile, move.ids[1]) table.insert(self.discard_pile, move.ids[1])
end end
Fk:filterCard(move.ids[1], move.to == Self.id and Self or nil) if (move.ids[1] ~= -1) then
Fk:filterCard(move.ids[1], ClientInstance:getPlayerById(move.to))
end
end end
end end

View File

@ -86,6 +86,7 @@ end
function Card:clone(suit, number) function Card:clone(suit, number)
local newCard = self.class:new(self.name, suit, number) local newCard = self.class:new(self.name, suit, number)
newCard.skill = self.skill newCard.skill = self.skill
newCard.equip_skill = self.equip_skill
return newCard return newCard
end end

View File

@ -1,11 +1,27 @@
---@class EquipCard : Card ---@class EquipCard : Card
---@field equipSkill Skill ---@field equip_skill Skill
local EquipCard = Card:subclass("EquipCard") local EquipCard = Card:subclass("EquipCard")
function EquipCard:initialize(name, suit, number) function EquipCard:initialize(name, suit, number)
Card.initialize(self, name, suit, number) Card.initialize(self, name, suit, number)
self.type = Card.TypeEquip self.type = Card.TypeEquip
self.equipSkill = nil self.equip_skill = nil
end
---@param room Room
---@param player Player
function EquipCard:onInstall(room, player)
if self.equip_skill then
room:handleAddLoseSkills(player, self.equip_skill.name, nil, false, true)
end
end
---@param room Room
---@param player Player
function EquipCard:onUninstall(room, player)
if self.equip_skill then
room:handleAddLoseSkills(player, "-" .. self.equip_skill.name, nil, false, true)
end
end end
---@class Weapon : EquipCard ---@class Weapon : EquipCard

View File

@ -460,27 +460,10 @@ local function getActualSkill(skill)
return skill return skill
end end
---@param skill string | Skill
function Player:hasEquipSkill(skill)
skill = getActualSkill(skill)
local equips = self.player_cards[Player.Equip]
for _, id in ipairs(equips) do
local card = Fk:getCardById(id)
if card.skill == skill then
return true
end
end
return false
end
---@param skill string | Skill ---@param skill string | Skill
function Player:hasSkill(skill) function Player:hasSkill(skill)
skill = getActualSkill(skill) skill = getActualSkill(skill)
if self:hasEquipSkill(skill) then
return true
end
if table.contains(self.player_skills, skill) then if table.contains(self.player_skills, skill) then
return true return true
end end

View File

@ -6,6 +6,7 @@
---@field mute boolean ---@field mute boolean
---@field anim_type string ---@field anim_type string
---@field related_skills Skill[] ---@field related_skills Skill[]
---@field attached_equip string
local Skill = class("Skill") local Skill = class("Skill")
---@alias Frequency integer ---@alias Frequency integer
@ -32,6 +33,8 @@ function Skill:initialize(name, frequency)
if string.sub(name, 1, 1) == "#" then if string.sub(name, 1, 1) == "#" then
self.visible = false self.visible = false
end end
self.attached_equip = nil
end end
---@param skill Skill ---@param skill Skill
@ -39,4 +42,9 @@ function Skill:addRelatedSkill(skill)
table.insert(self.related_skills, skill) table.insert(self.related_skills, skill)
end end
---@return boolean
function Skill:isEquipmentSkill()
return self.attached_equip and type(self.attached_equip) == 'string' and self.attached_equip ~= ""
end
return Skill return Skill

View File

@ -90,15 +90,17 @@ function fk.CreateTriggerSkill(spec)
skill.refresh = spec.on_refresh skill.refresh = spec.on_refresh
end end
if spec.attached_equip then
assert(type(spec.attached_equip) == "string")
skill.attached_equip = spec.attached_equip
if not spec.priority then if not spec.priority then
if frequency == Skill.Wake then spec.priority = 0.1
spec.priority = 3 end
elseif frequency == Skill.Compulsory then elseif not spec.priority then
spec.priority = 2
else
spec.priority = 1 spec.priority = 1
end end
end
if type(spec.priority) == "number" then if type(spec.priority) == "number" then
for _, event in ipairs(skill.events) do for _, event in ipairs(skill.events) do
skill.priority_table[event] = spec.priority skill.priority_table[event] = spec.priority
@ -137,6 +139,11 @@ function fk.CreateActiveSkill(spec)
} }
skill.distance_limit = spec.distance_limit or skill.distance_limit skill.distance_limit = spec.distance_limit or skill.distance_limit
if spec.attached_equip then
assert(type(spec.attached_equip) == "string")
skill.attached_equip = spec.attached_equip
end
if spec.can_use then skill.canUse = spec.can_use end if spec.can_use then skill.canUse = spec.can_use end
if spec.card_filter then skill.cardFilter = spec.card_filter 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.target_filter then skill.targetFilter = spec.target_filter end
@ -173,6 +180,11 @@ function fk.CreateViewAsSkill(spec)
} }
skill.distance_limit = spec.distance_limit or skill.distance_limit skill.distance_limit = spec.distance_limit or skill.distance_limit
if spec.attached_equip then
assert(type(spec.attached_equip) == "string")
skill.attached_equip = spec.attached_equip
end
skill.viewAs = spec.view_as skill.viewAs = spec.view_as
if spec.card_filter then if spec.card_filter then
skill.cardFilter = spec.card_filter skill.cardFilter = spec.card_filter
@ -205,6 +217,11 @@ function fk.CreateDistanceSkill(spec)
skill.global = spec.global skill.global = spec.global
end end
if spec.attached_equip then
assert(type(spec.attached_equip) == "string")
skill.attached_equip = spec.attached_equip
end
return skill return skill
end end
@ -223,6 +240,11 @@ function fk.CreateProhibitSkill(spec)
skill.global = spec.global skill.global = spec.global
end end
if spec.attached_equip then
assert(type(spec.attached_equip) == "string")
skill.attached_equip = spec.attached_equip
end
return skill return skill
end end
@ -241,6 +263,11 @@ function fk.CreateAttackRangeSkill(spec)
skill.global = spec.global skill.global = spec.global
end end
if spec.attached_equip then
assert(type(spec.attached_equip) == "string")
skill.attached_equip = spec.attached_equip
end
return skill return skill
end end
@ -265,6 +292,11 @@ function fk.CreateMaxCardsSkill(spec)
skill.global = spec.global skill.global = spec.global
end end
if spec.attached_equip then
assert(type(spec.attached_equip) == "string")
skill.attached_equip = spec.attached_equip
end
return skill return skill
end end
@ -292,6 +324,11 @@ function fk.CreateTargetModSkill(spec)
skill.global = spec.global skill.global = spec.global
end end
if spec.attached_equip then
assert(type(spec.attached_equip) == "string")
skill.attached_equip = spec.attached_equip
end
return skill return skill
end end
@ -382,6 +419,10 @@ function fk.CreateWeapon(spec)
local card = Weapon:new(spec.name, spec.suit, spec.number, spec.attack_range) local card = Weapon:new(spec.name, spec.suit, spec.number, spec.attack_range)
card.skill = spec.skill or defaultCardSkill card.skill = spec.skill or defaultCardSkill
card.equip_skill = spec.equip_skill
if spec.on_install then card.onInstall = spec.on_install end
if spec.on_uninstall then card.onUninstall = spec.on_uninstall end
return card return card
end end
@ -396,6 +437,10 @@ function fk.CreateArmor(spec)
local card = Armor:new(spec.name, spec.suit, spec.number) local card = Armor:new(spec.name, spec.suit, spec.number)
card.skill = spec.skill or defaultCardSkill card.skill = spec.skill or defaultCardSkill
card.equip_skill = spec.equip_skill
if spec.on_install then card.onInstall = spec.on_install end
if spec.on_uninstall then card.onUninstall = spec.on_uninstall end
return card return card
end end
@ -410,6 +455,10 @@ function fk.CreateDefensiveRide(spec)
local card = DefensiveRide:new(spec.name, spec.suit, spec.number) local card = DefensiveRide:new(spec.name, spec.suit, spec.number)
card.skill = spec.skill or defaultCardSkill card.skill = spec.skill or defaultCardSkill
card.equip_skill = spec.equip_skill
if spec.on_install then card.onInstall = spec.on_install end
if spec.on_uninstall then card.onUninstall = spec.on_uninstall end
return card return card
end end
@ -424,6 +473,10 @@ function fk.CreateOffensiveRide(spec)
local card = OffensiveRide:new(spec.name, spec.suit, spec.number) local card = OffensiveRide:new(spec.name, spec.suit, spec.number)
card.skill = spec.skill or defaultCardSkill card.skill = spec.skill or defaultCardSkill
card.equip_skill = spec.equip_skill
if spec.on_install then card.onInstall = spec.on_install end
if spec.on_uninstall then card.onUninstall = spec.on_uninstall end
return card return card
end end
@ -438,5 +491,9 @@ function fk.CreateTreasure(spec)
local card = Treasure:new(spec.name, spec.suit, spec.number) local card = Treasure:new(spec.name, spec.suit, spec.number)
card.skill = spec.skill or defaultCardSkill card.skill = spec.skill or defaultCardSkill
card.equip_skill = spec.equip_skill
if spec.on_install then card.onInstall = spec.on_install end
if spec.on_uninstall then card.onUninstall = spec.on_uninstall end
return card return card
end end

View File

@ -1660,6 +1660,19 @@ function Room:moveCards(...)
end end
self:setCardArea(info.cardId, data.toArea, data.to) self:setCardArea(info.cardId, data.toArea, data.to)
Fk:filterCard(info.cardId, self:getPlayerById(data.to)) Fk:filterCard(info.cardId, self:getPlayerById(data.to))
local currentCard = Fk:getCardById(info.cardId)
if
data.toArea == Player.Equip and
currentCard.type == Card.TypeEquip and
data.to ~= nil and
self:getPlayerById(data.to):isAlive() and
currentCard.equip_skill
then
currentCard:onInstall(self, self:getPlayerById(data.to))
elseif realFromArea == Player.Equip and currentCard.type == Card.TypeEquip and data.from ~= nil and currentCard.equip_skill then
currentCard:onUninstall(self, self:getPlayerById(data.from))
end
end end
end end
end end
@ -2032,8 +2045,9 @@ end
---@param player ServerPlayer ---@param player ServerPlayer
---@param skill_names string[] | string ---@param skill_names string[] | string
---@param source_skill string | Skill | nil ---@param source_skill string | Skill | null
function Room:handleAddLoseSkills(player, skill_names, source_skill, sendlog) ---@param no_trigger boolean | null
function Room:handleAddLoseSkills(player, skill_names, source_skill, sendlog, no_trigger)
if type(skill_names) == "string" then if type(skill_names) == "string" then
skill_names = skill_names:split("|") skill_names = skill_names:split("|")
end end
@ -2094,7 +2108,7 @@ function Room:handleAddLoseSkills(player, skill_names, source_skill, sendlog)
end end
end end
if #triggers > 0 then if (not no_trigger) and #triggers > 0 then
for i = 1, #triggers do for i = 1, #triggers do
local event = losts[i] and fk.EventLoseSkill or fk.EventAcquireSkill local event = losts[i] and fk.EventLoseSkill or fk.EventAcquireSkill
self.logic:trigger(event, player, triggers[i]) self.logic:trigger(event, player, triggers[i])

View File

@ -722,11 +722,24 @@ extension:addCards({
indulgence:clone(Card.Heart, 6), indulgence:clone(Card.Heart, 6),
}) })
local crossbowSkill = fk.CreateTargetModSkill{
name = "#crossbow_skill",
attached_equip = "crossbow",
residue_func = function(self, player, skill, scope)
if player:hasSkill(self.name) and skill.name == "slash_skill"
and scope == Player.HistoryPhase then
return 999
end
end,
}
Fk:addSkill(crossbowSkill)
local crossbow = fk.CreateWeapon{ local crossbow = fk.CreateWeapon{
name = "crossbow", name = "crossbow",
suit = Card.Club, suit = Card.Club,
number = 1, number = 1,
attack_range = 1, attack_range = 1,
equip_skill = crossbowSkill,
} }
Fk:loadTranslationTable{ Fk:loadTranslationTable{
["crossbow"] = "诸葛连弩", ["crossbow"] = "诸葛连弩",

View File

@ -1,22 +1,73 @@
local fkp_extensions = require "packages.test.test" local fkp_extensions = require "packages.test.test"
local extension = fkp_extensions[1] local extension = fkp_extensions[1]
local cheat = fk.CreateActiveSkill{
name = "cheat",
anim_type = "drawcard",
can_use = function(self, player)
return true
end,
feasible = function(self, selected, selected_cards)
return #selected == 0 and #selected_cards == 0
end,
on_use = function(self, room, effect)
local from = room:getPlayerById(effect.from)
local cardTypeName = room:askForChoice(from, { 'BasicCard', 'TrickCard', 'Equip' }, "cheat")
local cardType = Card.TypeBasic
if cardTypeName == 'TrickCard' then
cardType = Card.TypeTrick
elseif cardTypeName == 'Equip' then
cardType = Card.TypeEquip
end
local allCardIds = Fk:getAllCardIds()
local allCardMapper = {}
local allCardNames = {}
for _, id in ipairs(allCardIds) do
local card = Fk:getCardById(id)
if card.type == cardType then
if allCardMapper[card.name] == nil then
table.insert(allCardNames, card.name)
end
allCardMapper[card.name] = allCardMapper[card.name] or {}
table.insert(allCardMapper[card.name], id)
end
end
if #allCardNames == 0 then
return
end
local cardName = room:askForChoice(from, allCardNames, "cheat")
local toGain = nil
if #allCardMapper[cardName] > 0 then
toGain = allCardMapper[cardName][math.random(1, #allCardMapper[cardName])]
end
room:obtainCard(effect.from, toGain, true, fk.ReasonPrey)
end
}
local test_filter = fk.CreateFilterSkill{ local test_filter = fk.CreateFilterSkill{
name = "test_filter", name = "test_filter",
card_filter = function(self, card) card_filter = function(self, card)
return true return card.number > 11
end, end,
view_as = function(self, card) view_as = function(self, card)
return Fk:cloneCard("ex_nihilo", card.suit, card.number) return Fk:cloneCard("crossbow", card.suit, card.number)
end, end,
} }
local test2 = General(extension, "mouxusheng", "wu", 4) local test2 = General(extension, "mouxusheng", "wu", 4)
test2:addSkill(test_filter) test2:addSkill(test_filter)
test2:addSkill(cheat)
Fk:loadTranslationTable{ Fk:loadTranslationTable{
["test"] = "测试", ["test"] = "测试",
["test_filter"] = "破军", ["test_filter"] = "破军",
[":test_filter"] = "你的点数大于11的牌视为无中生有。",
["mouxusheng"] = "谋徐盛", ["mouxusheng"] = "谋徐盛",
--["cheat"] = "开挂",
[":cheat"] = "出牌阶段,你可以获得一张想要的牌。",
} }
return fkp_extensions return fkp_extensions

View File

@ -24,6 +24,8 @@ Item {
for (let i = 0; i < cards.length; i++) { for (let i = 0; i < cards.length; i++) {
for (let j = 0; j < outputs.length; j++) { for (let j = 0; j < outputs.length; j++) {
if (outputs[j] === cards[i].cid) { if (outputs[j] === cards[i].cid) {
let state = JSON.parse(Backend.callLuaFunction("GetCardData", [cards[i].cid]));
cards[i].setData(state);
result.push(cards[i]); result.push(cards[i]);
cards.splice(i, 1); cards.splice(i, 1);
i--; i--;

View File

@ -241,6 +241,8 @@ Item {
suit = data.suit; suit = data.suit;
number = data.number; number = data.number;
color = data.color; color = data.color;
subtype = data.subtype ? data.subtype : "";
virt_name = data.virt_name ? data.virt_name : "";
} }
function toData() function toData()
@ -250,7 +252,9 @@ Item {
name: name, name: name,
suit: suit, suit: suit,
number: number, number: number,
color: color color: color,
subtype: subtype,
virt_name: virt_name,
}; };
return data; return data;
} }

View File

@ -122,9 +122,13 @@ Item {
icon = "horse"; icon = "horse";
} else { } else {
text = Backend.translate(name); text = Backend.translate(name);
if (card.virt_name) {
icon = card.virt_name;
} else {
icon = name; icon = name;
} }
} }
}
function show() function show()
{ {

View File

@ -9,6 +9,8 @@ Window {
visible: true visible: true
width: 960 width: 960
height: 540 height: 540
minimumWidth: 160
minimumHeight: 90
property var callbacks: Logic.callbacks property var callbacks: Logic.callbacks
Item { Item {
@ -36,7 +38,8 @@ Item {
StackView { StackView {
id: mainStack id: mainStack
visible: !mainWindow.busy visible: !mainWindow.busy
initialItem: OS !== "Web" ? init : webinit // If error occurs during loading initialItem, the program will fall into "polish()" loop
// initialItem: OS !== "Web" ? init : webinit
anchors.fill: parent anchors.fill: parent
} }
@ -151,7 +154,7 @@ Item {
anchors.centerIn: parent anchors.centerIn: parent
width: Math.min(contentWidth + 24, realMainWin.width * 0.9) width: Math.min(contentWidth + 24, realMainWin.width * 0.9)
height: Math.min(contentHeight + 24, realMainWin.height * 0.9) height: Math.min(contentHeight + 24, realMainWin.height * 0.9)
closePolicy: Popup.CloseOnEscape closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
padding: 12 padding: 12
contentItem: Text { contentItem: Text {
text: errDialog.txt text: errDialog.txt
@ -197,6 +200,11 @@ Item {
} }
Component.onCompleted: { Component.onCompleted: {
if (OS !== "Web") {
mainStack.push(init);
} else {
mainStack.push(webinit);
}
if (OS !== "Android" && OS !== "Web") { if (OS !== "Android" && OS !== "Web") {
width = config.winWidth; width = config.winWidth;
height = config.winHeight; height = config.winHeight;

View File

@ -77,8 +77,8 @@ void QmlBackend::quitLobby()
{ {
if (ClientInstance) if (ClientInstance)
delete ClientInstance; delete ClientInstance;
if (ServerInstance) // if (ServerInstance)
delete ServerInstance; // delete ServerInstance;
} }
void QmlBackend::emitNotifyUI(const QString &command, const QString &jsonData) { void QmlBackend::emitNotifyUI(const QString &command, const QString &jsonData) {