Qing gang sword & zhu que fan (#85)
- 完成【青釭剑】效果 - 初步完成技能失效技 - 完成【朱雀羽扇】 - 修改“连环状态”传导逻辑 - 修改八卦阵匹配的pattern
This commit is contained in:
parent
44c932981b
commit
dfe3e8b2e7
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"] = "骅骝",
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue