Qing gang sword & zhu que fan (#85)

- 完成【青釭剑】效果
- 初步完成技能失效技
- 完成【朱雀羽扇】
- 修改“连环状态”传导逻辑
- 修改八卦阵匹配的pattern
This commit is contained in:
Ho-spair 2023-03-20 20:49:23 +08:00 committed by GitHub
parent 44c932981b
commit dfe3e8b2e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 164 additions and 31 deletions

View File

@ -191,7 +191,7 @@ function Card:getTypeString()
elseif t == Card.TypeEquip then elseif t == Card.TypeEquip then
return "equip" return "equip"
end end
return "nocolor" return "notype"
end end
local function getNumberStr(num) local function getNumberStr(num)

View File

@ -479,9 +479,17 @@ local function getActualSkill(skill)
end end
---@param skill string | Skill ---@param skill string | Skill
function Player:hasSkill(skill) function Player:hasSkill(skill, ignoreNullified, ignoreAlive)
if not ignoreAlive and self.dead then
return false
end
skill = getActualSkill(skill) skill = getActualSkill(skill)
if not (ignoreNullified or skill:isEffectable(self)) then
return false
end
if table.contains(self.player_skills, skill) then if table.contains(self.player_skills, skill) then
return true return true
end end
@ -507,7 +515,7 @@ function Player:addSkill(skill, source_skill)
local room = Fk:currentRoom() local room = Fk:currentRoom()
local ret = {} local ret = {}
for _, s in ipairs(toget) do for _, s in ipairs(toget) do
if not self:hasSkill(s) then if not self:hasSkill(s, true, true) then
table.insert(ret, s) table.insert(ret, s)
if s:isInstanceOf(TriggerSkill) and RoomInstance then if s:isInstanceOf(TriggerSkill) and RoomInstance then
room.logic:addTriggerSkill(s) room.logic:addTriggerSkill(s)
@ -563,7 +571,7 @@ function Player:loseSkill(skill, source_skill)
local ret = {} ---@type Skill[] local ret = {} ---@type Skill[]
for _, s in ipairs(tolose) do for _, s in ipairs(tolose) do
if not self:hasSkill(s) then if not self:hasSkill(s, true, true) then
table.insert(ret, s) table.insert(ret, s)
end end
end end

View File

@ -51,4 +51,17 @@ function Skill:isEquipmentSkill()
return self.attached_equip and type(self.attached_equip) == 'string' and self.attached_equip ~= "" return self.attached_equip and type(self.attached_equip) == 'string' and self.attached_equip ~= ""
end end
---@param player Player
---@return boolean
function Skill:isEffectable(player)
local nullifySkills = Fk:currentRoom().status_skills[InvaliditySkill] or {}
for _, nullifySkill in ipairs(nullifySkills) do
if self.name ~= nullifySkill.name and nullifySkill:getInvalidity(player, self) then
return false
end
end
return true
end
return Skill return Skill

View File

@ -0,0 +1,11 @@
---@class InvaliditySkill : StatusSkill
local InvaliditySkill = StatusSkill:subclass("InvaliditySkill")
---@param from Player
---@param skill Skill
---@return boolean
function InvaliditySkill:getInvalidity(from, skill)
return false
end
return InvaliditySkill

View File

@ -38,7 +38,7 @@ function TriggerSkill:refresh(event, target, player, data) end
---@return boolean ---@return boolean
function TriggerSkill:triggerable(event, target, player, data) function TriggerSkill:triggerable(event, target, player, data)
return target and (target == player) return target and (target == player)
and (self.global or (target:isAlive() and target:hasSkill(self))) and (self.global or target:hasSkill(self))
end end
-- Determine how to cost this skill. -- Determine how to cost this skill.

View File

@ -11,6 +11,7 @@ AttackRangeSkill = require "core.skill_type.attack_range"
MaxCardsSkill = require "core.skill_type.max_cards" MaxCardsSkill = require "core.skill_type.max_cards"
TargetModSkill = require "core.skill_type.target_mod" TargetModSkill = require "core.skill_type.target_mod"
FilterSkill = require "core.skill_type.filter" FilterSkill = require "core.skill_type.filter"
InvaliditySkill = require "lua.core.skill_type.invalidity"
BasicCard = require "core.card_type.basic" BasicCard = require "core.card_type.basic"
local Trick = require "core.card_type.trick" local Trick = require "core.card_type.trick"
@ -320,6 +321,21 @@ function fk.CreateFilterSkill(spec)
return skill return skill
end end
---@class InvaliditySpec: StatusSkillSpec
---@field invalidity_func fun(self: InvaliditySkill, from: Player, skill: Skill)
---@param spec InvaliditySpec
---@return InvaliditySkill
function fk.CreateInvaliditySkill(spec)
assert(type(spec.name) == "string")
local skill = InvaliditySkill:new(spec.name)
readStatusSpecToSkill(skill, spec)
skill.getInvalidity = spec.invalidity_func
return skill
end
---@class CardSpec: Card ---@class CardSpec: Card
---@field skill Skill ---@field skill Skill
---@field equip_skill Skill ---@field equip_skill Skill

View File

@ -11,6 +11,7 @@ GameEvent.functions[GameEvent.ChangeHp] = function(self)
num = num, num = num,
reason = reason, reason = reason,
skillName = skillName, skillName = skillName,
damageEvent = damageStruct,
} }
if self.logic:trigger(fk.BeforeHpChanged, player, data) then if self.logic:trigger(fk.BeforeHpChanged, player, data) then

View File

@ -1317,7 +1317,8 @@ local onAim = function(room, cardUseEvent, aimEventCollaborators)
nullifiedTargets = cardUseEvent.nullifiedTargets or {}, nullifiedTargets = cardUseEvent.nullifiedTargets or {},
tos = aimGroup, tos = aimGroup,
firstTarget = firstTarget, firstTarget = firstTarget,
additionalDamage = cardUseEvent.additionalDamage additionalDamage = cardUseEvent.additionalDamage,
extra_data = cardUseEvent.extra_data,
} }
local index = 1 local index = 1
@ -1344,6 +1345,7 @@ local onAim = function(room, cardUseEvent, aimEventCollaborators)
aimStruct.targetGroup = cardUseEvent.tos aimStruct.targetGroup = cardUseEvent.tos
aimStruct.nullifiedTargets = cardUseEvent.nullifiedTargets or {} aimStruct.nullifiedTargets = cardUseEvent.nullifiedTargets or {}
aimStruct.firstTarget = firstTarget aimStruct.firstTarget = firstTarget
aimStruct.extra_data = cardUseEvent.extra_data
end end
firstTarget = false firstTarget = false
@ -1361,6 +1363,7 @@ local onAim = function(room, cardUseEvent, aimEventCollaborators)
cardUseEvent.from = aimStruct.from cardUseEvent.from = aimStruct.from
cardUseEvent.tos = aimEventTargetGroup cardUseEvent.tos = aimEventTargetGroup
cardUseEvent.nullifiedTargets = aimStruct.nullifiedTargets cardUseEvent.nullifiedTargets = aimStruct.nullifiedTargets
cardUseEvent.extra_data = aimStruct.extra_data
if #AimGroup:getAllTargets(aimStruct.tos) == 0 then if #AimGroup:getAllTargets(aimStruct.tos) == 0 then
return false return false
@ -1824,7 +1827,7 @@ function Room:handleAddLoseSkills(player, skill_names, source_skill, sendlog, no
for _, skill in ipairs(skill_names) do for _, skill in ipairs(skill_names) do
if string.sub(skill, 1, 1) == "-" then if string.sub(skill, 1, 1) == "-" then
local actual_skill = string.sub(skill, 2, #skill) local actual_skill = string.sub(skill, 2, #skill)
if player:hasSkill(actual_skill) then if player:hasSkill(actual_skill, true, true) then
local lost_skills = player:loseSkill(actual_skill, source_skill) local lost_skills = player:loseSkill(actual_skill, source_skill)
for _, s in ipairs(lost_skills) do for _, s in ipairs(lost_skills) do
self:doBroadcastNotify("LoseSkill", json.encode{ self:doBroadcastNotify("LoseSkill", json.encode{
@ -1846,7 +1849,7 @@ function Room:handleAddLoseSkills(player, skill_names, source_skill, sendlog, no
end end
else else
local sk = Fk.skills[skill] local sk = Fk.skills[skill]
if sk and not player:hasSkill(sk) then if sk and not player:hasSkill(sk, true, true) then
local got_skills = player:addSkill(sk) local got_skills = player:addSkill(sk)
for _, s in ipairs(got_skills) do for _, s in ipairs(got_skills) do

View File

@ -35,6 +35,7 @@
---@field num integer ---@field num integer
---@field reason string ---@field reason string
---@field skillName string ---@field skillName string
---@field damageEvent DamageStruct|null
---@class HpLostData ---@class HpLostData
---@field num integer ---@field num integer
@ -54,6 +55,7 @@ fk.FireDamage = 3
---@field chain boolean ---@field chain boolean
---@field damageType DamageType ---@field damageType DamageType
---@field skillName string ---@field skillName string
---@field beginnerOfTheDamage boolean|null
---@class RecoverStruct ---@class RecoverStruct
---@field who ServerPlayer ---@field who ServerPlayer

View File

@ -156,32 +156,34 @@ extension:addCards({
local ironChainEffect = fk.CreateTriggerSkill{ local ironChainEffect = fk.CreateTriggerSkill{
name = "iron_chain_effect", name = "iron_chain_effect",
global = true, global = true,
priority = 0, -- game rule priority = { [fk.BeforeHpChanged] = 10, [fk.DamageFinished] = 0 }, -- game rule
refresh_events = {fk.DamageFinished}, refresh_events = { fk.BeforeHpChanged, fk.DamageFinished },
can_refresh = function(self, event, target, player, data) can_refresh = function(self, event, target, player, data)
return target == player and data.damageType ~= fk.NormalDamage if event == fk.BeforeHpChanged then
return target == player and data.damageEvent and data.damageEvent.damageType ~= fk.NormalDamage and player.chained
else
return target == player and data.beginnerOfTheDamage and not data.chain
end
end, end,
on_refresh = function(self, event, target, player, data) on_refresh = function(self, event, target, player, data)
local room = player.room local room = player.room
if data.to.chained then if event == fk.BeforeHpChanged then
data.to:setChainState(false) data.damageEvent.beginnerOfTheDamage = true
player:setChainState(false)
else else
return local targets = table.filter(room:getAlivePlayers(), function(p)
end return p.chained
if data.chain then return end end)
for _, p in ipairs(targets) do
local targets = table.filter(room:getAlivePlayers(), function(p) room:sendLog{
return p.chained type = "#ChainDamage",
end) from = p.id
for _, p in ipairs(targets) do }
room:sendLog{ local dmg = table.simpleClone(data)
type = "#ChainDamage", dmg.to = p
from = p.id dmg.chain = true
} room:damage(dmg)
local dmg = table.simpleClone(data) end
dmg.to = p
dmg.chain = true
room:damage(dmg)
end end
end, end,
} }
@ -320,6 +322,30 @@ local gudingBlade = fk.CreateWeapon{
extension:addCard(gudingBlade) extension:addCard(gudingBlade)
local fanSkill = fk.CreateTriggerSkill{
name = "#fan_skill",
attached_equip = "fan",
events = { fk.AfterCardUseDeclared },
can_trigger = function(self, event, target, player, data)
return target == player and player:hasSkill(self.name) and data.card.name == "slash"
end,
on_use = function(_, _, _, _, data)
local fireSlash = Fk:cloneCard("fire__slash")
fireSlash:addSubcard(data.card)
data.card = fireSlash
end,
}
Fk:addSkill(fanSkill)
local fan = fk.CreateWeapon{
name = "fan",
suit = Card.Diamond,
number = 1,
attack_range = 4,
equip_skill = fanSkill,
}
extension:addCard(fan)
local vineSkill = fk.CreateTriggerSkill{ local vineSkill = fk.CreateTriggerSkill{
name = "#vine_skill", name = "#vine_skill",
attached_equip = "vine", attached_equip = "vine",
@ -380,7 +406,7 @@ local silverLion = fk.CreateArmor{
equip_skill = silverLionSkill, equip_skill = silverLionSkill,
on_uninstall = function(self, room, player) on_uninstall = function(self, room, player)
Armor.onUninstall(self, room, player) Armor.onUninstall(self, room, player)
if player:isWounded() then if player:isWounded() and self.equip_skill:isEffectable(player) then
room:broadcastPlaySound("./packages/maneuvering/audio/card/silver_lion") room:broadcastPlaySound("./packages/maneuvering/audio/card/silver_lion")
room:setEmotion(player, "./packages/maneuvering/image/anim/silver_lion") room:setEmotion(player, "./packages/maneuvering/image/anim/silver_lion")
room:recover{ room:recover{
@ -436,6 +462,8 @@ Fk:loadTranslationTable{
["fire_attack"] = "火攻", ["fire_attack"] = "火攻",
["supply_shortage"] = "兵粮寸断", ["supply_shortage"] = "兵粮寸断",
["guding_blade"] = "古锭刀", ["guding_blade"] = "古锭刀",
["fan"] = "朱雀羽扇",
["#fan_skill"] = "朱雀羽扇",
["vine"] = "藤甲", ["vine"] = "藤甲",
["silver_lion"] = "白银狮子", ["silver_lion"] = "白银狮子",
["hualiu"] = "骅骝", ["hualiu"] = "骅骝",

View File

@ -773,11 +773,62 @@ extension:addCards({
crossbow:clone(Card.Diamond, 1), crossbow:clone(Card.Diamond, 1),
}) })
fk.MarkArmorNullified = "mark__armor_nullified"
local armorInvalidity = fk.CreateInvaliditySkill {
name = "armor_invalidity_skill",
global = true,
invalidity_func = function(self, from, skill)
return
from:getMark(fk.MarkArmorNullified) > 0 and
from:getEquipment(Card.SubtypeArmor) ~= nil and
skill.attached_equip == Fk:getCardById(from:getEquipment(Card.SubtypeArmor)).name
end
}
Fk:addSkill(armorInvalidity)
local qingGangSkill = fk.CreateTriggerSkill{
name = "#qinggang_sword_skill",
attached_equip = "qinggang_sword",
frequency = Skill.Compulsory,
events = { fk.TargetSpecified },
can_trigger = function(self, event, target, player, data)
return target == player and player:hasSkill(self.name) and
data.card and data.card.trueName == "slash"
end,
on_use = function(self, event, target, player, data)
local room = player.room
room:addPlayerMark(room:getPlayerById(data.to), fk.MarkArmorNullified)
data.extra_data = data.extra_data or {}
data.extra_data.qinggangNullified = data.extra_data.qinggangNullified or {}
data.extra_data.qinggangNullified[tostring(data.to)] = (data.extra_data.qinggangNullified[tostring(data.to)] or 0) + 1
end,
refresh_events = { fk.CardUseFinished },
can_refresh = function(self, event, target, player, data)
return data.extra_data and data.extra_data.qinggangNullified
end,
on_refresh = function(self, event, target, player, data)
local room = player.room
for key, num in pairs(data.extra_data.qinggangNullified) do
local p = room:getPlayerById(tonumber(key))
if p:getMark(fk.MarkArmorNullified) > 0 then
room:removePlayerMark(p, fk.MarkArmorNullified, num)
end
end
data.qinggangNullified = nil
end,
}
Fk:addSkill(qingGangSkill)
local qingGang = fk.CreateWeapon{ local qingGang = fk.CreateWeapon{
name = "qinggang_sword", name = "qinggang_sword",
suit = Card.Spade, suit = Card.Spade,
number = 6, number = 6,
attack_range = 2, attack_range = 2,
equip_skill = qingGangSkill,
} }
extension:addCards({ extension:addCards({
@ -1035,7 +1086,7 @@ local eightDiagramSkill = fk.CreateTriggerSkill{
events = {fk.AskForCardUse, fk.AskForCardResponse}, events = {fk.AskForCardUse, fk.AskForCardResponse},
can_trigger = function(self, event, target, player, data) can_trigger = function(self, event, target, player, data)
return target == player and player:hasSkill(self.name) and return target == player and player:hasSkill(self.name) and
(data.cardName == "jink" or (data.pattern and Exppattern:Parse(data.pattern):matchExp("jink"))) (data.cardName == "jink" or (data.pattern and Exppattern:Parse(data.pattern):matchExp("jink|0|nosuit|none")))
end, end,
on_use = function(self, event, target, player, data) on_use = function(self, event, target, player, data)
local room = player.room local room = player.room