Switch skill (#148)

- 实现转换技;
- 将特殊的标记名称注册在mark_enum.lua文件;
- 标记值在UI的显示支持解析数组;
- 将觉醒技的觉醒条件分离至canWake函数;
- 修复一系列bug;
- 在Room类新增从牌堆、弃牌堆中随机获取牌的方法。
This commit is contained in:
Ho-spair 2023-05-13 14:20:34 +08:00 committed by GitHub
parent 5e9505d18e
commit a7e3ad0f19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 298 additions and 45 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -525,7 +525,10 @@ end
---@param times integer ---@param times integer
local function updateLimitSkill(pid, skill, times) local function updateLimitSkill(pid, skill, times)
if not skill.visible then return end if not skill.visible then return end
if skill.frequency == Skill.Limited or skill.frequency == Skill.Wake then if skill:isSwitchSkill() then
times = ClientInstance:getPlayerById(pid):getSwitchSkillState(skill.switchSkillName) == fk.SwitchYang and 0 or 1
ClientInstance:notifyUI("UpdateLimitSkill", json.encode{ pid, skill.switchSkillName, times })
elseif skill.frequency == Skill.Limited or skill.frequency == Skill.Wake then
ClientInstance:notifyUI("UpdateLimitSkill", json.encode{ pid, skill.name, times }) ClientInstance:notifyUI("UpdateLimitSkill", json.encode{ pid, skill.name, times })
end end
end end

View File

@ -274,6 +274,7 @@ function GetSkillData(skill_name)
extension = skill.package.extensionName, extension = skill.package.extensionName,
freq = freq, freq = freq,
frequency = frequency, frequency = frequency,
switchSkillName = skill.switchSkillName,
} }
end end

View File

@ -193,6 +193,10 @@ FreeKill使用的是libgit2的C API与此同时使用Git完成拓展包的下
["$Winner"] = "%1 获胜", ["$Winner"] = "%1 获胜",
["$NoWinner"] = "平局!", ["$NoWinner"] = "平局!",
["Back To Lobby"] = "返回大厅", ["Back To Lobby"] = "返回大厅",
["basic_char"] = "",
["trick_char"] = "",
["equip_char"] = "",
} }
-- Game concepts -- Game concepts

View File

@ -284,6 +284,12 @@ local function getNumberStr(num)
return tostring(num) return tostring(num)
end end
--- 判断卡牌是否为普通锦囊牌
---@return boolean
function Card:isCommonTrick()
return self.type == Card.TypeTrick and self.sub_type ~= Card.SubtypeDelayedTrick
end
--- 为卡牌赋予Mark。 --- 为卡牌赋予Mark。
---@param mark string @ 标记 ---@param mark string @ 标记
---@param count integer @ 为标记赋予的数量 ---@param count integer @ 为标记赋予的数量
@ -333,6 +339,51 @@ function Card:getMarkNames()
return ret return ret
end end
---@param anotherCard Card
---@param diff boolean
---@return boolean
function Card:compareSuitWith(anotherCard, diff)
if table.contains({ self.suit, anotherCard.suit }, Card.NoSuit) then
return false
end
if diff then
return self.suit ~= anotherCard.suit
else
return self.suit == anotherCard.suit
end
end
---@param anotherCard Card
---@param diff boolean
---@return boolean
function Card:compareColorWith(anotherCard, diff)
if table.contains({ self.color, anotherCard.color }, Card.NoColor) then
return false
end
if diff then
return self.color ~= anotherCard.color
else
return self.color == anotherCard.color
end
end
---@param anotherCard Card
---@param diff boolean
---@return boolean
function Card:compareNumberWith(anotherCard, diff)
if self.number < 1 or anotherCard.number < 1 then
return false
end
if diff then
return self.number ~= anotherCard.number
else
return self.number == anotherCard.number
end
end
-- for sendLog -- for sendLog
--- 获取卡牌的文字信息并准备作为log发送。 --- 获取卡牌的文字信息并准备作为log发送。
function Card:toLogString() function Card:toLogString()

View File

@ -119,8 +119,8 @@ function Player:setGeneral(general, setHp, addSkills)
end end
function Player:getGeneralMaxHp() function Player:getGeneralMaxHp()
local general = Fk.generals[self:getMark("__heg_general") or self.general] local general = Fk.generals[type(self:getMark("__heg_general")) == "string" and self:getMark("__heg_general") or self.general]
local deputy = Fk.generals[self:getMark("__heg_deputy") or self.deputy] local deputy = Fk.generals[type(self:getMark("__heg_deputy")) == "string" and self:getMark("__heg_deputy") or self.deputy]
if not deputy then if not deputy then
return general.maxHp return general.maxHp
@ -727,4 +727,19 @@ function Player:prohibitDiscard(card)
return false return false
end end
---@field SwitchYang number @ 转换技状态阳
fk.SwitchYang = 0
---@field SwitchYin number @ 转换技状态阴
fk.SwitchYin = 1
---@param skillName string
---@return number
function Player:getSwitchSkillState(skillName, afterUse)
if afterUse then
return self:getMark(MarkEnum.SwithSkillPreName .. skillName) < 1 and fk.SwitchYin or fk.SwitchYang
else
return self:getMark(MarkEnum.SwithSkillPreName .. skillName) < 1 and fk.SwitchYang or fk.SwitchYin
end
end
return Player return Player

View File

@ -12,6 +12,7 @@
---@field public anim_type string @ 技能类型定义 ---@field public anim_type string @ 技能类型定义
---@field public related_skills Skill[] @ 和本技能相关的其他技能,有时候一个技能实际上是通过好几个技能拼接而实现的。 ---@field public related_skills Skill[] @ 和本技能相关的其他技能,有时候一个技能实际上是通过好几个技能拼接而实现的。
---@field public attached_equip string @ 属于什么装备的技能? ---@field public attached_equip string @ 属于什么装备的技能?
---@field public switchSkillName string
local Skill = class("Skill") local Skill = class("Skill")
---@alias Frequency integer ---@alias Frequency integer
@ -90,4 +91,8 @@ function Skill:addAttachedKingdom(kingdom)
table.insertIfNeed(self.attachedKingdom, kingdom) table.insertIfNeed(self.attachedKingdom, kingdom)
end end
function Skill:isSwitchSkill()
return self.switchSkillName and type(self.switchSkillName) == 'string' and self.switchSkillName ~= ""
end
return Skill return Skill

View File

@ -57,8 +57,14 @@ end
-- DO NOT modify this function -- DO NOT modify this function
function TriggerSkill:doCost(event, target, player, data) function TriggerSkill:doCost(event, target, player, data)
local ret = self:cost(event, target, player, data) local ret = self:cost(event, target, player, data)
local room = player.room
local cost_data_bak = self.cost_data
room.logic:trigger(fk.BeforeTriggerSkillUse, player, { skill = self, willUse = ret })
self.cost_data = cost_data_bak
if ret then if ret then
return player.room:useSkill(player, self, function() return room:useSkill(player, self, function()
return self:use(event, target, player, data) return self:use(event, target, player, data)
end) end)
end end
@ -90,4 +96,22 @@ end
---@return boolean ---@return boolean
function TriggerSkill:use(event, target, player, data) end function TriggerSkill:use(event, target, player, data) end
function TriggerSkill:canWake(event, target, player, data)
return true
end
---@param event Event @ TriggerEvent
---@param target ServerPlayer @ Player who triggered this event
---@param player ServerPlayer @ Player who is operating
---@param data any @ useful data of the event
---@return boolean
function TriggerSkill:enableToWake(event, target, player, data)
return
type(player:getMark(MarkEnum.StraightToWake)) == "table" and
table.find(player:getMark(MarkEnum.StraightToWake), function(skillName)
return self.name == skillName
end) or
self:canWake(event, target, player, data)
end
return TriggerSkill return TriggerSkill

View File

@ -7,6 +7,7 @@
-- 首先加载所有详细的技能类型、卡牌类型等等,以及时机列表 -- 首先加载所有详细的技能类型、卡牌类型等等,以及时机列表
dofile "lua/server/event.lua" dofile "lua/server/event.lua"
dofile "lua/server/system_enum.lua" dofile "lua/server/system_enum.lua"
dofile "lua/server/mark_enum.lua"
TriggerSkill = require "core.skill_type.trigger" TriggerSkill = require "core.skill_type.trigger"
ActiveSkill = require "core.skill_type.active" ActiveSkill = require "core.skill_type.active"
ViewAsSkill = require "core.skill_type.view_as" ViewAsSkill = require "core.skill_type.view_as"
@ -32,6 +33,11 @@ local function readCommonSpecToSkill(skill, spec)
assert(type(spec.attached_equip) == "string") assert(type(spec.attached_equip) == "string")
skill.attached_equip = spec.attached_equip skill.attached_equip = spec.attached_equip
end end
if spec.switch_skill_name then
assert(type(spec.switch_skill_name) == "string")
skill.switchSkillName = spec.switch_skill_name
end
end end
local function readUsableSpecToSkill(skill, spec) local function readUsableSpecToSkill(skill, spec)
@ -110,7 +116,18 @@ function fk.CreateTriggerSkill(spec)
if spec.on_trigger then skill.trigger = spec.on_trigger end if spec.on_trigger then skill.trigger = spec.on_trigger end
if spec.can_trigger then if spec.can_trigger then
skill.triggerable = spec.can_trigger if spec.frequency == Skill.Wake then
skill.triggerable = function(self, event, target, player, data)
return spec.can_trigger(self, event, target, player, data) and
skill:enableToWake(event, target, player, data)
end
else
skill.triggerable = spec.can_trigger
end
end
if skill.frequency == Skill.Wake and spec.can_wake then
skill.canWake = spec.can_wake
end end
if spec.on_cost then skill.cost = spec.on_cost end if spec.on_cost then skill.cost = spec.on_cost end
@ -197,7 +214,7 @@ end
---@field public pattern string ---@field public pattern string
---@field public enabled_at_play fun(self: ViewAsSkill, player: Player): boolean ---@field public enabled_at_play fun(self: ViewAsSkill, player: Player): boolean
---@field public enabled_at_response fun(self: ViewAsSkill, player: Player): boolean ---@field public enabled_at_response fun(self: ViewAsSkill, player: Player): boolean
---@field public before_use fun(self: ViewAsSkill, player: Player) ---@field public before_use fun(self: ViewAsSkill, player: ServerPlayer)
---@param spec ViewAsSkillSpec ---@param spec ViewAsSkillSpec
---@return ViewAsSkill ---@return ViewAsSkill

View File

@ -9,6 +9,10 @@
---FreeKill's lua API ---FreeKill's lua API
fk = {} fk = {}
---@class MarkEnum
---Special marks
MarkEnum = {}
---@class fk.SPlayerList ---@class fk.SPlayerList
SPlayerList = {} SPlayerList = {}

View File

@ -15,7 +15,7 @@ local function useActiveSkill(self, skill, card)
filter_func = function() return false end filter_func = function() return false end
end end
if self.command == "PlayCard" and not skill:canUse(player) then if self.command == "PlayCard" and not skill:canUse(player, card) then
return "" return ""
end end

View File

@ -95,5 +95,10 @@ fk.PindianResultConfirmed = 71
fk.PindianFinished = 72 fk.PindianFinished = 72
-- 73 = TurnEnd -- 73 = TurnEnd
fk.AfterDrawPileShuffle = 74
fk.NumOfEvents = 74 fk.BeforeTriggerSkillUse = 75
fk.BeforeDrawCard = 76
fk.NumOfEvents = 77

View File

@ -40,15 +40,12 @@ GameEvent.functions[GameEvent.Judge] = function(self)
if self.logic:trigger(fk.FinishJudge, who, data) then if self.logic:trigger(fk.FinishJudge, who, data) then
self.logic:breakEvent() self.logic:breakEvent()
end end
if self:getCardArea(data.card.id) == Card.Processing then
self:moveCardTo(data.card, Card.DiscardPile, nil, fk.ReasonPutIntoDiscardPile)
end
end end
GameEvent.cleaners[GameEvent.Judge] = function(self) GameEvent.cleaners[GameEvent.Judge] = function(self)
local data = table.unpack(self.data) local data = table.unpack(self.data)
local self = self.room local self = self.room
if self:getCardArea(data.card.id) == Card.Processing then if (self.interrupted or not data.skipDrop) and self:getCardArea(data.card.id) == Card.Processing then
self:moveCardTo(data.card, Card.DiscardPile, nil, fk.ReasonPutIntoDiscardPile) self:moveCardTo(data.card, Card.DiscardPile, nil, fk.ReasonPutIntoDiscardPile)
end end
if not self.interrupted then return end if not self.interrupted then return end

View File

@ -100,7 +100,7 @@ GameEvent.functions[GameEvent.MoveCards] = function(self)
toAreaIds = self.void toAreaIds = self.void
end end
table.insert(toAreaIds, toAreaIds == Card.DrawPile and 1 or #toAreaIds + 1, info.cardId) table.insert(toAreaIds, data.toArea == Card.DrawPile and 1 or #toAreaIds + 1, info.cardId)
end end
self:setCardArea(info.cardId, data.toArea, data.to) self:setCardArea(info.cardId, data.toArea, data.to)
if data.toArea == Card.DrawPile or realFromArea == Card.DrawPile then if data.toArea == Card.DrawPile or realFromArea == Card.DrawPile then

View File

@ -414,8 +414,15 @@ function GameLogic:trigger(event, target, data, refresh_only)
local len = #skills local len = #skills
broken = skill:trigger(event, target, player, data) broken = skill:trigger(event, target, player, data)
table.insertTable(skill_names, table.map(
table.slice(skills, len - #skills), function(s) return s.name end)) table.insertTable(
skill_names,
table.map(table.filter(table.slice(skills, len - #skills), function(s)
return
s.priority_table[event] == prio and
s:triggerable(event, target, player, data)
end), function(s) return s.name end)
)
broken = broken or (event == fk.AskForPeaches broken = broken or (event == fk.AskForPeaches
and room:getPlayerById(data.who).hp > 0) and room:getPlayerById(data.who).hp > 0)

8
lua/server/mark_enum.lua Normal file
View File

@ -0,0 +1,8 @@
-- SPDX-License-Identifier: GPL-3.0-or-later
MarkEnum = {}
---@field StraightToWake string @ 跳过觉醒标记(值为技能名通过+连接)
MarkEnum.StraightToWake = "_straight_to_wake"
MarkEnum.SwithSkillPreName = "__switcher_"

View File

@ -195,8 +195,25 @@ end
--- 将房间中的玩家按照座位顺序重新排序。 --- 将房间中的玩家按照座位顺序重新排序。
---@param playerIds integer[] @ 玩家id列表这个数组会被这个函数排序 ---@param playerIds integer[] @ 玩家id列表这个数组会被这个函数排序
function Room:sortPlayersByAction(playerIds) function Room:sortPlayersByAction(playerIds, isTargetGroup)
table.sort(playerIds, function(prev, next)
local prevSeat = self:getPlayerById(isTargetGroup and prev[1] or prev).seat
local nextSeat = self:getPlayerById(isTargetGroup and next[1] or next).seat
return prevSeat < nextSeat
end)
if
self.current and
table.find(isTargetGroup and TargetGroup:getRealTargets(playerIds) or playerIds, function(id)
return self:getPlayerById(id).seat >= self.current.seat
end)
then
while self:getPlayerById(isTargetGroup and playerIds[1][1] or playerIds[1]).seat < self.current.seat do
local toPlayerId = table.remove(playerIds, 1)
table.insert(playerIds, toPlayerId)
end
end
end end
function Room:deadPlayerFilter(playerIds) function Room:deadPlayerFilter(playerIds)
@ -487,10 +504,10 @@ function Room:changeHero(player, new_general, full, isDeputy, sendLog)
end end
player.maxHp = player:getGeneralMaxHp() player.maxHp = player:getGeneralMaxHp()
self:broadcastProperty(player, "hp") self:broadcastProperty(player, "maxHp")
if full then if full then
player.hp = player.maxHp player.hp = player.maxHp
self:broadcastProperty(player, "maxHp") self:broadcastProperty(player, "hp")
end end
end end
@ -1220,7 +1237,10 @@ end
---@param cards integer[] @ 可以被观星的卡牌id列表 ---@param cards integer[] @ 可以被观星的卡牌id列表
---@param top_limit integer[] @ 置于牌堆顶的牌的限制(下限,上限),不填写则不限 ---@param top_limit integer[] @ 置于牌堆顶的牌的限制(下限,上限),不填写则不限
---@param bottom_limit integer[] @ 置于牌堆顶的牌的限制(下限,上限),不填写则不限 ---@param bottom_limit integer[] @ 置于牌堆顶的牌的限制(下限,上限),不填写则不限
function Room:askForGuanxing(player, cards, top_limit, bottom_limit) ---@param customNotify string|null @ 自定义读条操作提示
---@param noPut boolean|null @ 是否进行放置牌操作
---@return table<top|bottom, cardId[]>
function Room:askForGuanxing(player, cards, top_limit, bottom_limit, customNotify, noPut)
-- 这一大堆都是来提前报错的 -- 这一大堆都是来提前报错的
top_limit = top_limit or {} top_limit = top_limit or {}
bottom_limit = bottom_limit or {} bottom_limit = bottom_limit or {}
@ -1236,7 +1256,7 @@ function Room:askForGuanxing(player, cards, top_limit, bottom_limit)
assert(#cards >= top_limit[1] + bottom_limit[1] and #cards <= top_limit[2] + bottom_limit[2], "限定区间设置错误:可用空间不能容纳所有牌。") assert(#cards >= top_limit[1] + bottom_limit[1] and #cards <= top_limit[2] + bottom_limit[2], "限定区间设置错误:可用空间不能容纳所有牌。")
end end
local command = "AskForGuanxing" local command = "AskForGuanxing"
self:notifyMoveFocus(player, command) self:notifyMoveFocus(player, customNotify or command)
local data = { local data = {
cards = cards, cards = cards,
min_top_cards = top_limit and top_limit[1] or 0, min_top_cards = top_limit and top_limit[1] or 0,
@ -1261,19 +1281,23 @@ function Room:askForGuanxing(player, cards, top_limit, bottom_limit)
bottom = {} bottom = {}
end end
for i = #top, 1, -1 do if not noPut then
table.insert(self.draw_pile, 1, top[i]) for i = #top, 1, -1 do
end table.insert(self.draw_pile, 1, top[i])
for _, id in ipairs(bottom) do end
table.insert(self.draw_pile, id) for _, id in ipairs(bottom) do
table.insert(self.draw_pile, id)
end
self:sendLog{
type = "#GuanxingResult",
from = player.id,
arg = #top,
arg2 = #bottom,
}
end end
self:sendLog{ return { top = top, bottom = bottom }
type = "#GuanxingResult",
from = player.id,
arg = #top,
arg2 = #bottom,
}
end end
--- 平时写DIY用不到的函数。 --- 平时写DIY用不到的函数。
@ -1567,7 +1591,7 @@ local onAim = function(room, cardUseEvent, aimEventCollaborators)
return false return false
end end
room:sortPlayersByAction(cardUseEvent.tos) room:sortPlayersByAction(cardUseEvent.tos, true)
local aimGroup = AimGroup:initAimGroup(TargetGroup:getRealTargets(cardUseEvent.tos)) local aimGroup = AimGroup:initAimGroup(TargetGroup:getRealTargets(cardUseEvent.tos))
local collaboratorsIndex = {} local collaboratorsIndex = {}
@ -1628,7 +1652,7 @@ local onAim = function(room, cardUseEvent, aimEventCollaborators)
local aimEventTargetGroup = aimStruct.targetGroup local aimEventTargetGroup = aimStruct.targetGroup
if aimEventTargetGroup then if aimEventTargetGroup then
room:sortPlayersByAction(aimEventTargetGroup) room:sortPlayersByAction(aimEventTargetGroup, true)
end end
cardUseEvent.from = aimStruct.from cardUseEvent.from = aimStruct.from
@ -2030,6 +2054,17 @@ end
---@param fromPlace string @ 摸牌的位置,"top" 或者 "bottom" ---@param fromPlace string @ 摸牌的位置,"top" 或者 "bottom"
---@return integer[] @ 摸到的牌 ---@return integer[] @ 摸到的牌
function Room:drawCards(player, num, skillName, fromPlace) function Room:drawCards(player, num, skillName, fromPlace)
local drawData = {
who = player,
num = num,
skillName = skillName,
fromPlace = fromPlace,
}
self.logic:trigger(fk.BeforeDrawCard, player, drawData)
num = drawData.num
fromPlace = drawData.fromPlace
local topCards = self:getNCards(num, fromPlace) local topCards = self:getNCards(num, fromPlace)
self:moveCards({ self:moveCards({
ids = topCards, ids = topCards,
@ -2408,6 +2443,8 @@ function Room:shuffleDrawPile()
end end
self.discard_pile = {} self.discard_pile = {}
table.shuffle(self.draw_pile) table.shuffle(self.draw_pile)
self.logic:trigger(fk.AfterDrawPileShuffle, nil, {})
end end
--- 使用技能。先增加技能发动次数,再执行相应的函数。 --- 使用技能。先增加技能发动次数,再执行相应的函数。
@ -2428,6 +2465,15 @@ function Room:useSkill(player, skill, effect_cb)
self:notifySkillInvoked(player, skill.name) self:notifySkillInvoked(player, skill.name)
end end
end end
if skill:isSwitchSkill() then
local switchSkillName = skill.switchSkillName
self:setPlayerMark(
player,
MarkEnum.SwithSkillPreName .. switchSkillName,
player:getSwitchSkillState(switchSkillName, true)
)
end
player:addSkillUseHistory(skill.name) player:addSkillUseHistory(skill.name)
if effect_cb then if effect_cb then
@ -2470,6 +2516,55 @@ function Room:getSubcardsByRule(card, fromAreas)
return cardIds return cardIds
end end
---@param pattern string
---@param num number|null
---@param fromPile number|null
---@return cardId[]
function Room:getCardFromPileByRule(pattern, num, fromPile)
num = num or 1
local pileToSearch = fromPile == Card.DiscardPile and self.discard_pile or self.draw_pile
local cardPack = {}
if num < 3 then
for i = 1, num do
local randomIndex = math.random(1, #pileToSearch)
local curIndex = randomIndex
repeat
local curCardId = pileToSearch[curIndex]
if Fk:getCardById(curCardId):matchPattern(pattern) and not table.contains(cardPack, curCardId) then
table.insert(cardPack, pileToSearch[curIndex])
break
end
curIndex = curIndex + 1
if curIndex > #pileToSearch then
curIndex = 1
end
until curIndex == randomIndex
if #cardPack < num then
break
end
end
else
local matchedIds = {}
for _, id in ipairs(pileToSearch) do
if Fk:getCardById(id):matchPattern(pattern) then
table.insert(matchedIds, id)
end
end
local loopTimes = math.min(num, #matchedIds)
for i = 1, loopTimes do
local randomCardId = matchedIds[math.random(1, #matchedIds)]
table.insert(cardPack, randomCardId)
table.removeOne(matchedIds, randomCardId)
end
end
return cardPack
end
function CreateRoom(_room) function CreateRoom(_room)
RoomInstance = Room:new(_room) RoomInstance = Room:new(_room)
end end

View File

@ -141,6 +141,7 @@ fk.IceDamage = 4
---@field public card Card ---@field public card Card
---@field public reason string ---@field public reason string
---@field public pattern string ---@field public pattern string
---@field public skipDrop boolean|null
---@class CardResponseEvent ---@class CardResponseEvent
---@field public from integer ---@field public from integer
@ -189,3 +190,13 @@ fk.ReasonResonpse = 10
---@field public arg any ---@field public arg any
---@field public arg2 any ---@field public arg2 any
---@field public arg3 any ---@field public arg3 any
---@class SkillUseStruct
---@field public skill Skill
---@field public willUse boolean
---@class DrawCardStruct
---@field public who ServerPlayer
---@field public num number
---@field public skillName string
---@field public fromPlace "top"|"bottom"

View File

@ -79,8 +79,8 @@ extension:addCards{
local analepticSkill = fk.CreateActiveSkill{ local analepticSkill = fk.CreateActiveSkill{
name = "analeptic_skill", name = "analeptic_skill",
max_turn_use_time = 1, max_turn_use_time = 1,
can_use = function(self, player) can_use = function(self, player, card)
return player:usedCardTimes("analeptic", Player.HistoryTurn) < self:getMaxUseTime(Self, Player.HistoryTurn) return player:usedCardTimes("analeptic", Player.HistoryTurn) < self:getMaxUseTime(Self, Player.HistoryTurn, card)
end, end,
on_use = function(self, room, use) on_use = function(self, room, use)
if not use.tos or #TargetGroup:getRealTargets(use.tos) == 0 then if not use.tos or #TargetGroup:getRealTargets(use.tos) == 0 then
@ -120,21 +120,22 @@ local analepticEffect = fk.CreateTriggerSkill{
if event == fk.PreCardUse then if event == fk.PreCardUse then
return data.card.trueName == "slash" and player.drank > 0 return data.card.trueName == "slash" and player.drank > 0
else else
return player.phase == Player.NotActive return target.phase == Player.NotActive
end end
end, end,
on_trigger = function(self, event, target, player, data) on_trigger = function(self, event, target, player, data)
local room = player.room
if event == fk.PreCardUse then if event == fk.PreCardUse then
data.additionalDamage = (data.additionalDamage or 0) + player.drank data.additionalDamage = (data.additionalDamage or 0) + player.drank
data.extra_data = data.extra_data or {} data.extra_data = data.extra_data or {}
data.extra_data.drankBuff = player.drank data.extra_data.drankBuff = player.drank
player.drank = 0 player.drank = 0
player.room:broadcastProperty(player, "drank") room:broadcastProperty(player, "drank")
else else
for _, p in ipairs(player.room:getAlivePlayers(true)) do for _, p in ipairs(room:getAlivePlayers(true)) do
if p.drank > 0 then if p.drank > 0 then
p.drank = 0 p.drank = 0
p.room:broadcastProperty(player, "drank") room:broadcastProperty(p, "drank")
end end
end end
end end
@ -270,12 +271,12 @@ extension:addCards{
local supplyShortageSkill = fk.CreateActiveSkill{ local supplyShortageSkill = fk.CreateActiveSkill{
name = "supply_shortage_skill", name = "supply_shortage_skill",
distance_limit = 1, distance_limit = 1,
target_filter = function(self, to_select, selected) target_filter = function(self, to_select, selected, _, card)
if #selected == 0 then if #selected == 0 then
local player = Fk:currentRoom():getPlayerById(to_select) local player = Fk:currentRoom():getPlayerById(to_select)
if Self ~= player then if Self ~= player then
return not player:hasDelayedTrick("supply_shortage") and return not player:hasDelayedTrick("supply_shortage") and
Self:distanceTo(player) <= self:getDistanceLimit(Self) Self:distanceTo(player) <= self:getDistanceLimit(Self, card)
end end
end end
return false return false

View File

@ -41,8 +41,8 @@ Item {
onSkillnameChanged: { onSkillnameChanged: {
let data = Backend.callLuaFunction("GetSkillData", [skillname]); let data = Backend.callLuaFunction("GetSkillData", [skillname]);
data = JSON.parse(data); data = JSON.parse(data);
if (data.frequency) { if (data.frequency || data.switchSkillName) {
skilltype = data.frequency; skilltype = data.switchSkillName ? 'switch' : data.frequency;
visible = true; visible = true;
} else { } else {
visible = false; visible = false;
@ -59,6 +59,9 @@ Item {
x.visible = true; x.visible = true;
bg.source = SkinBank.LIMIT_SKILL_DIR + "limit-used"; bg.source = SkinBank.LIMIT_SKILL_DIR + "limit-used";
} }
} else if (skilltype === 'switch') {
visible = true;
bg.source = SkinBank.LIMIT_SKILL_DIR + (usedtimes < 1 ? 'switch' : 'switch-yin');
} }
} }
} }

View File

@ -33,7 +33,7 @@ Item {
width: childrenRect.width width: childrenRect.width
height: 22 height: 22
Text { Text {
text: Backend.translate(mark_name) + ' ' + Backend.translate(mark_extra) text: Backend.translate(mark_name) + ' ' + mark_extra
font.family: fontLibian.name font.family: fontLibian.name
font.pixelSize: 22 font.pixelSize: 22
font.letterSpacing: -0.6 font.letterSpacing: -0.6
@ -82,6 +82,8 @@ Item {
break; break;
} }
} }
data = (data instanceof Array ? data.map((markText) => Backend.translate(markText)).join(' ') : Backend.translate(data));
if (modelItem) if (modelItem)
modelItem.mark_extra = data; modelItem.mark_extra = data;
else else

View File

@ -878,7 +878,7 @@ callbacks["SetPlayerMark"] = function(jsonData) {
let data = JSON.parse(jsonData); let data = JSON.parse(jsonData);
let player = getPhoto(data[0]); let player = getPhoto(data[0]);
let mark = data[1]; let mark = data[1];
let value = data[2].toString(); let value = data[2] instanceof Array ? data[2] : data[2].toString();
if (value == 0) { if (value == 0) {
player.markArea.removeMark(mark); player.markArea.removeMark(mark);
} else { } else {