Switch skill (#148)
- 实现转换技; - 将特殊的标记名称注册在mark_enum.lua文件; - 标记值在UI的显示支持解析数组; - 将觉醒技的觉醒条件分离至canWake函数; - 修复一系列bug; - 在Room类新增从牌堆、弃牌堆中随机获取牌的方法。
After Width: | Height: | Size: 70 B |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 9.4 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 3.4 KiB |
|
@ -525,7 +525,10 @@ end
|
|||
---@param times integer
|
||||
local function updateLimitSkill(pid, skill, times)
|
||||
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 })
|
||||
end
|
||||
end
|
||||
|
|
|
@ -274,6 +274,7 @@ function GetSkillData(skill_name)
|
|||
extension = skill.package.extensionName,
|
||||
freq = freq,
|
||||
frequency = frequency,
|
||||
switchSkillName = skill.switchSkillName,
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -193,6 +193,10 @@ FreeKill使用的是libgit2的C API,与此同时使用Git完成拓展包的下
|
|||
["$Winner"] = "%1 获胜",
|
||||
["$NoWinner"] = "平局!",
|
||||
["Back To Lobby"] = "返回大厅",
|
||||
|
||||
["basic_char"] = "基",
|
||||
["trick_char"] = "锦",
|
||||
["equip_char"] = "装",
|
||||
}
|
||||
|
||||
-- Game concepts
|
||||
|
|
|
@ -284,6 +284,12 @@ local function getNumberStr(num)
|
|||
return tostring(num)
|
||||
end
|
||||
|
||||
--- 判断卡牌是否为普通锦囊牌
|
||||
---@return boolean
|
||||
function Card:isCommonTrick()
|
||||
return self.type == Card.TypeTrick and self.sub_type ~= Card.SubtypeDelayedTrick
|
||||
end
|
||||
|
||||
--- 为卡牌赋予Mark。
|
||||
---@param mark string @ 标记
|
||||
---@param count integer @ 为标记赋予的数量
|
||||
|
@ -333,6 +339,51 @@ function Card:getMarkNames()
|
|||
return ret
|
||||
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
|
||||
--- 获取卡牌的文字信息并准备作为log发送。
|
||||
function Card:toLogString()
|
||||
|
|
|
@ -119,8 +119,8 @@ function Player:setGeneral(general, setHp, addSkills)
|
|||
end
|
||||
|
||||
function Player:getGeneralMaxHp()
|
||||
local general = Fk.generals[self:getMark("__heg_general") or self.general]
|
||||
local deputy = Fk.generals[self:getMark("__heg_deputy") or self.deputy]
|
||||
local general = Fk.generals[type(self:getMark("__heg_general")) == "string" and self:getMark("__heg_general") or self.general]
|
||||
local deputy = Fk.generals[type(self:getMark("__heg_deputy")) == "string" and self:getMark("__heg_deputy") or self.deputy]
|
||||
|
||||
if not deputy then
|
||||
return general.maxHp
|
||||
|
@ -727,4 +727,19 @@ function Player:prohibitDiscard(card)
|
|||
return false
|
||||
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
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
---@field public anim_type string @ 技能类型定义
|
||||
---@field public related_skills Skill[] @ 和本技能相关的其他技能,有时候一个技能实际上是通过好几个技能拼接而实现的。
|
||||
---@field public attached_equip string @ 属于什么装备的技能?
|
||||
---@field public switchSkillName string
|
||||
local Skill = class("Skill")
|
||||
|
||||
---@alias Frequency integer
|
||||
|
@ -90,4 +91,8 @@ function Skill:addAttachedKingdom(kingdom)
|
|||
table.insertIfNeed(self.attachedKingdom, kingdom)
|
||||
end
|
||||
|
||||
function Skill:isSwitchSkill()
|
||||
return self.switchSkillName and type(self.switchSkillName) == 'string' and self.switchSkillName ~= ""
|
||||
end
|
||||
|
||||
return Skill
|
||||
|
|
|
@ -57,8 +57,14 @@ end
|
|||
-- DO NOT modify this function
|
||||
function TriggerSkill:doCost(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
|
||||
return player.room:useSkill(player, self, function()
|
||||
return room:useSkill(player, self, function()
|
||||
return self:use(event, target, player, data)
|
||||
end)
|
||||
end
|
||||
|
@ -90,4 +96,22 @@ end
|
|||
---@return boolean
|
||||
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
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
-- 首先加载所有详细的技能类型、卡牌类型等等,以及时机列表
|
||||
dofile "lua/server/event.lua"
|
||||
dofile "lua/server/system_enum.lua"
|
||||
dofile "lua/server/mark_enum.lua"
|
||||
TriggerSkill = require "core.skill_type.trigger"
|
||||
ActiveSkill = require "core.skill_type.active"
|
||||
ViewAsSkill = require "core.skill_type.view_as"
|
||||
|
@ -32,6 +33,11 @@ local function readCommonSpecToSkill(skill, spec)
|
|||
assert(type(spec.attached_equip) == "string")
|
||||
skill.attached_equip = spec.attached_equip
|
||||
end
|
||||
|
||||
if spec.switch_skill_name then
|
||||
assert(type(spec.switch_skill_name) == "string")
|
||||
skill.switchSkillName = spec.switch_skill_name
|
||||
end
|
||||
end
|
||||
|
||||
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.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
|
||||
|
||||
if spec.on_cost then skill.cost = spec.on_cost end
|
||||
|
@ -197,7 +214,7 @@ end
|
|||
---@field public pattern string
|
||||
---@field public enabled_at_play 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
|
||||
---@return ViewAsSkill
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
---FreeKill's lua API
|
||||
fk = {}
|
||||
|
||||
---@class MarkEnum
|
||||
---Special marks
|
||||
MarkEnum = {}
|
||||
|
||||
---@class fk.SPlayerList
|
||||
SPlayerList = {}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ local function useActiveSkill(self, skill, card)
|
|||
filter_func = function() return false end
|
||||
end
|
||||
|
||||
if self.command == "PlayCard" and not skill:canUse(player) then
|
||||
if self.command == "PlayCard" and not skill:canUse(player, card) then
|
||||
return ""
|
||||
end
|
||||
|
||||
|
|
|
@ -95,5 +95,10 @@ fk.PindianResultConfirmed = 71
|
|||
fk.PindianFinished = 72
|
||||
|
||||
-- 73 = TurnEnd
|
||||
fk.AfterDrawPileShuffle = 74
|
||||
|
||||
fk.NumOfEvents = 74
|
||||
fk.BeforeTriggerSkillUse = 75
|
||||
|
||||
fk.BeforeDrawCard = 76
|
||||
|
||||
fk.NumOfEvents = 77
|
||||
|
|
|
@ -40,15 +40,12 @@ GameEvent.functions[GameEvent.Judge] = function(self)
|
|||
if self.logic:trigger(fk.FinishJudge, who, data) then
|
||||
self.logic:breakEvent()
|
||||
end
|
||||
if self:getCardArea(data.card.id) == Card.Processing then
|
||||
self:moveCardTo(data.card, Card.DiscardPile, nil, fk.ReasonPutIntoDiscardPile)
|
||||
end
|
||||
end
|
||||
|
||||
GameEvent.cleaners[GameEvent.Judge] = function(self)
|
||||
local data = table.unpack(self.data)
|
||||
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)
|
||||
end
|
||||
if not self.interrupted then return end
|
||||
|
|
|
@ -100,7 +100,7 @@ GameEvent.functions[GameEvent.MoveCards] = function(self)
|
|||
toAreaIds = self.void
|
||||
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
|
||||
self:setCardArea(info.cardId, data.toArea, data.to)
|
||||
if data.toArea == Card.DrawPile or realFromArea == Card.DrawPile then
|
||||
|
|
|
@ -414,8 +414,15 @@ function GameLogic:trigger(event, target, data, refresh_only)
|
|||
|
||||
local len = #skills
|
||||
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
|
||||
and room:getPlayerById(data.who).hp > 0)
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
-- SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
MarkEnum = {}
|
||||
|
||||
---@field StraightToWake string @ 跳过觉醒标记(值为技能名通过+连接)
|
||||
MarkEnum.StraightToWake = "_straight_to_wake"
|
||||
|
||||
MarkEnum.SwithSkillPreName = "__switcher_"
|
|
@ -195,8 +195,25 @@ end
|
|||
|
||||
--- 将房间中的玩家按照座位顺序重新排序。
|
||||
---@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
|
||||
|
||||
function Room:deadPlayerFilter(playerIds)
|
||||
|
@ -487,10 +504,10 @@ function Room:changeHero(player, new_general, full, isDeputy, sendLog)
|
|||
end
|
||||
|
||||
player.maxHp = player:getGeneralMaxHp()
|
||||
self:broadcastProperty(player, "hp")
|
||||
self:broadcastProperty(player, "maxHp")
|
||||
if full then
|
||||
player.hp = player.maxHp
|
||||
self:broadcastProperty(player, "maxHp")
|
||||
self:broadcastProperty(player, "hp")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1220,7 +1237,10 @@ end
|
|||
---@param cards integer[] @ 可以被观星的卡牌id列表
|
||||
---@param top_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 {}
|
||||
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], "限定区间设置错误:可用空间不能容纳所有牌。")
|
||||
end
|
||||
local command = "AskForGuanxing"
|
||||
self:notifyMoveFocus(player, command)
|
||||
self:notifyMoveFocus(player, customNotify or command)
|
||||
local data = {
|
||||
cards = cards,
|
||||
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 = {}
|
||||
end
|
||||
|
||||
for i = #top, 1, -1 do
|
||||
table.insert(self.draw_pile, 1, top[i])
|
||||
end
|
||||
for _, id in ipairs(bottom) do
|
||||
table.insert(self.draw_pile, id)
|
||||
if not noPut then
|
||||
for i = #top, 1, -1 do
|
||||
table.insert(self.draw_pile, 1, top[i])
|
||||
end
|
||||
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
|
||||
|
||||
self:sendLog{
|
||||
type = "#GuanxingResult",
|
||||
from = player.id,
|
||||
arg = #top,
|
||||
arg2 = #bottom,
|
||||
}
|
||||
return { top = top, bottom = bottom }
|
||||
end
|
||||
|
||||
--- 平时写DIY用不到的函数。
|
||||
|
@ -1567,7 +1591,7 @@ local onAim = function(room, cardUseEvent, aimEventCollaborators)
|
|||
return false
|
||||
end
|
||||
|
||||
room:sortPlayersByAction(cardUseEvent.tos)
|
||||
room:sortPlayersByAction(cardUseEvent.tos, true)
|
||||
local aimGroup = AimGroup:initAimGroup(TargetGroup:getRealTargets(cardUseEvent.tos))
|
||||
|
||||
local collaboratorsIndex = {}
|
||||
|
@ -1628,7 +1652,7 @@ local onAim = function(room, cardUseEvent, aimEventCollaborators)
|
|||
|
||||
local aimEventTargetGroup = aimStruct.targetGroup
|
||||
if aimEventTargetGroup then
|
||||
room:sortPlayersByAction(aimEventTargetGroup)
|
||||
room:sortPlayersByAction(aimEventTargetGroup, true)
|
||||
end
|
||||
|
||||
cardUseEvent.from = aimStruct.from
|
||||
|
@ -2030,6 +2054,17 @@ end
|
|||
---@param fromPlace string @ 摸牌的位置,"top" 或者 "bottom"
|
||||
---@return integer[] @ 摸到的牌
|
||||
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)
|
||||
self:moveCards({
|
||||
ids = topCards,
|
||||
|
@ -2408,6 +2443,8 @@ function Room:shuffleDrawPile()
|
|||
end
|
||||
self.discard_pile = {}
|
||||
table.shuffle(self.draw_pile)
|
||||
|
||||
self.logic:trigger(fk.AfterDrawPileShuffle, nil, {})
|
||||
end
|
||||
|
||||
--- 使用技能。先增加技能发动次数,再执行相应的函数。
|
||||
|
@ -2428,6 +2465,15 @@ function Room:useSkill(player, skill, effect_cb)
|
|||
self:notifySkillInvoked(player, skill.name)
|
||||
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)
|
||||
|
||||
if effect_cb then
|
||||
|
@ -2470,6 +2516,55 @@ function Room:getSubcardsByRule(card, fromAreas)
|
|||
return cardIds
|
||||
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)
|
||||
RoomInstance = Room:new(_room)
|
||||
end
|
||||
|
|
|
@ -141,6 +141,7 @@ fk.IceDamage = 4
|
|||
---@field public card Card
|
||||
---@field public reason string
|
||||
---@field public pattern string
|
||||
---@field public skipDrop boolean|null
|
||||
|
||||
---@class CardResponseEvent
|
||||
---@field public from integer
|
||||
|
@ -189,3 +190,13 @@ fk.ReasonResonpse = 10
|
|||
---@field public arg any
|
||||
---@field public arg2 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"
|
||||
|
|
|
@ -79,8 +79,8 @@ extension:addCards{
|
|||
local analepticSkill = fk.CreateActiveSkill{
|
||||
name = "analeptic_skill",
|
||||
max_turn_use_time = 1,
|
||||
can_use = function(self, player)
|
||||
return player:usedCardTimes("analeptic", Player.HistoryTurn) < self:getMaxUseTime(Self, Player.HistoryTurn)
|
||||
can_use = function(self, player, card)
|
||||
return player:usedCardTimes("analeptic", Player.HistoryTurn) < self:getMaxUseTime(Self, Player.HistoryTurn, card)
|
||||
end,
|
||||
on_use = function(self, room, use)
|
||||
if not use.tos or #TargetGroup:getRealTargets(use.tos) == 0 then
|
||||
|
@ -120,21 +120,22 @@ local analepticEffect = fk.CreateTriggerSkill{
|
|||
if event == fk.PreCardUse then
|
||||
return data.card.trueName == "slash" and player.drank > 0
|
||||
else
|
||||
return player.phase == Player.NotActive
|
||||
return target.phase == Player.NotActive
|
||||
end
|
||||
end,
|
||||
on_trigger = function(self, event, target, player, data)
|
||||
local room = player.room
|
||||
if event == fk.PreCardUse then
|
||||
data.additionalDamage = (data.additionalDamage or 0) + player.drank
|
||||
data.extra_data = data.extra_data or {}
|
||||
data.extra_data.drankBuff = player.drank
|
||||
player.drank = 0
|
||||
player.room:broadcastProperty(player, "drank")
|
||||
room:broadcastProperty(player, "drank")
|
||||
else
|
||||
for _, p in ipairs(player.room:getAlivePlayers(true)) do
|
||||
for _, p in ipairs(room:getAlivePlayers(true)) do
|
||||
if p.drank > 0 then
|
||||
p.drank = 0
|
||||
p.room:broadcastProperty(player, "drank")
|
||||
room:broadcastProperty(p, "drank")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -270,12 +271,12 @@ extension:addCards{
|
|||
local supplyShortageSkill = fk.CreateActiveSkill{
|
||||
name = "supply_shortage_skill",
|
||||
distance_limit = 1,
|
||||
target_filter = function(self, to_select, selected)
|
||||
target_filter = function(self, to_select, selected, _, card)
|
||||
if #selected == 0 then
|
||||
local player = Fk:currentRoom():getPlayerById(to_select)
|
||||
if Self ~= player then
|
||||
return not player:hasDelayedTrick("supply_shortage") and
|
||||
Self:distanceTo(player) <= self:getDistanceLimit(Self)
|
||||
Self:distanceTo(player) <= self:getDistanceLimit(Self, card)
|
||||
end
|
||||
end
|
||||
return false
|
||||
|
|
|
@ -41,8 +41,8 @@ Item {
|
|||
onSkillnameChanged: {
|
||||
let data = Backend.callLuaFunction("GetSkillData", [skillname]);
|
||||
data = JSON.parse(data);
|
||||
if (data.frequency) {
|
||||
skilltype = data.frequency;
|
||||
if (data.frequency || data.switchSkillName) {
|
||||
skilltype = data.switchSkillName ? 'switch' : data.frequency;
|
||||
visible = true;
|
||||
} else {
|
||||
visible = false;
|
||||
|
@ -59,6 +59,9 @@ Item {
|
|||
x.visible = true;
|
||||
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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ Item {
|
|||
width: childrenRect.width
|
||||
height: 22
|
||||
Text {
|
||||
text: Backend.translate(mark_name) + ' ' + Backend.translate(mark_extra)
|
||||
text: Backend.translate(mark_name) + ' ' + mark_extra
|
||||
font.family: fontLibian.name
|
||||
font.pixelSize: 22
|
||||
font.letterSpacing: -0.6
|
||||
|
@ -82,6 +82,8 @@ Item {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
data = (data instanceof Array ? data.map((markText) => Backend.translate(markText)).join(' ') : Backend.translate(data));
|
||||
if (modelItem)
|
||||
modelItem.mark_extra = data;
|
||||
else
|
||||
|
|
|
@ -878,7 +878,7 @@ callbacks["SetPlayerMark"] = function(jsonData) {
|
|||
let data = JSON.parse(jsonData);
|
||||
let player = getPhoto(data[0]);
|
||||
let mark = data[1];
|
||||
let value = data[2].toString();
|
||||
let value = data[2] instanceof Array ? data[2] : data[2].toString();
|
||||
if (value == 0) {
|
||||
player.markArea.removeMark(mark);
|
||||
} else {
|
||||
|
|