diff --git a/Fk/Pages/RoomLogic.js b/Fk/Pages/RoomLogic.js index bc13e719..6c9b155f 100644 --- a/Fk/Pages/RoomLogic.js +++ b/Fk/Pages/RoomLogic.js @@ -551,6 +551,12 @@ function updateSelectedTargets(playerid, selected) { [card, id, selected_targets] )); photo.selectable = ret; + if (roomScene.extra_data instanceof Object) { + const exclusived = roomScene.extra_data.exclusive_targets; + if (exclusived instanceof Array) { + if (exclusived.indexOf(id) === -1) photo.selectable = false; + } + } }) okButton.enabled = JSON.parse(Backend.callLuaFunction( @@ -835,9 +841,15 @@ callbacks["AskForGuanxing"] = (jsonData) => { box.areaLimits = [min_bottom_cards]; box.areaNames = [Backend.translate(bottom_area_name)]; } else { - box.areaCapacities = [max_top_cards, max_bottom_cards]; - box.areaLimits = [min_top_cards, min_bottom_cards]; - box.areaNames = [Backend.translate(top_area_name), Backend.translate(bottom_area_name)]; + if (max_bottom_cards === 0) { + box.areaCapacities = [max_top_cards]; + box.areaLimits = [min_top_cards]; + box.areaNames = [Backend.translate(top_area_name)]; + } else { + box.areaCapacities = [max_top_cards, max_bottom_cards]; + box.areaLimits = [min_top_cards, min_bottom_cards]; + box.areaNames = [Backend.translate(top_area_name), Backend.translate(bottom_area_name)]; + } } box.cards = cards; box.arrangeCards(); @@ -906,7 +918,7 @@ callbacks["AskForChoice"] = (jsonData) => { box.skill_name = skill_name; box.all_options = all_choices; box.accepted.connect(() => { - replyToServer(choices[box.result]); + replyToServer(all_choices[box.result]); }); } diff --git a/Fk/SkillInteraction/SkillCombo.qml b/Fk/SkillInteraction/SkillCombo.qml index e85f6cb4..97eb8c4a 100644 --- a/Fk/SkillInteraction/SkillCombo.qml +++ b/Fk/SkillInteraction/SkillCombo.qml @@ -45,7 +45,7 @@ MetroButton { box.options = choices; box.all_options = all_choices; box.accepted.connect(() => { - answer = choices[box.result]; + answer = all_choices[box.result]; }); } diff --git a/lua/client/i18n/zh_CN.lua b/lua/client/i18n/zh_CN.lua index 4bc9b00f..09259db6 100644 --- a/lua/client/i18n/zh_CN.lua +++ b/lua/client/i18n/zh_CN.lua @@ -276,8 +276,8 @@ Fk:loadTranslationTable{ ["phase_finish"] = "结束阶段", ["chained"] = "横置", - ["un-chained"] = "竖置", - ["reset-general"] = "重置", + ["un-chained"] = "重置", + ["reset-general"] = "复原", ["yang"] = "阳", ["yin"] = "阴", @@ -391,7 +391,6 @@ Fk:loadTranslationTable{ ["#GuanxingResult"] = "%from 的观星结果为 %arg 上 %arg2 下", ["#ChainStateChange"] = "%from %arg 了武将牌", ["#ChainDamage"] = "%from 处于连环状态,将受到传导的伤害", - ["#ResetGeneral"] = "%from 复原了武将牌", } -- card footnote diff --git a/lua/core/game_mode.lua b/lua/core/game_mode.lua index a554b8cf..c297d678 100644 --- a/lua/core/game_mode.lua +++ b/lua/core/game_mode.lua @@ -61,4 +61,10 @@ function GameMode:surrenderFunc(playedTime) return {} end +---@param room Room @ 游戏房间 +---@return boolean +function GameMode:countInFunc(room) + return true +end + return GameMode diff --git a/lua/core/skill_type/active.lua b/lua/core/skill_type/active.lua index f6101f97..c9d61fb9 100644 --- a/lua/core/skill_type/active.lua +++ b/lua/core/skill_type/active.lua @@ -50,6 +50,17 @@ function ActiveSkill:targetFilter(to_select, selected, selected_cards, card) return false end +--- Determine whether a target can be selected by this skill(in modifying targets) +--- only used in skill of players +---@param to_select integer @ id of the target +---@param selected integer[] @ ids of selected targets +---@param user integer @ id of the userdata +---@param card Card @ helper +---@param distance_limited boolean @ is limited by distance +function ActiveSkill:modTargetFilter(to_select, selected, user, card, distance_limited) + return false +end + function ActiveSkill:getMinTargetNum() local ret if self.target_num then ret = self.target_num diff --git a/lua/core/skill_type/usable_skill.lua b/lua/core/skill_type/usable_skill.lua index c1e79248..84374b55 100644 --- a/lua/core/skill_type/usable_skill.lua +++ b/lua/core/skill_type/usable_skill.lua @@ -35,13 +35,15 @@ function UsableSkill:withinTimesLimit(player, scope, card, card_name, to) if skill:bypassTimesCheck(player, self, scope, card, to) then return true end end card_name = card_name or card.trueName + local temp_suf = table.simpleClone(MarkEnum.TempMarkSuffix) + table.insert(temp_suf, "-tmp") return player:usedCardTimes(card_name, scope) < self:getMaxUseTime(player, scope, card, to) or (player:getMark(MarkEnum.BypassTimesLimit) ~= 0 or - table.find(MarkEnum.TempMarkSuffix, function(s) + table.find(temp_suf, function(s) return player:getMark(MarkEnum.BypassTimesLimit .. s) ~= 0 end)) or (to:getMark(MarkEnum.BypassTimesLimitTo) ~= 0 or - table.find(MarkEnum.TempMarkSuffix, function(s) + table.find(temp_suf, function(s) return to:getMark(MarkEnum.BypassTimesLimitTo .. s) ~= 0 end)) end @@ -55,13 +57,15 @@ function UsableSkill:withinDistanceLimit(player, isattack, card, to) for _, skill in ipairs(status_skills) do if skill:bypassDistancesCheck(player, self, card, to) then return true end end + local temp_suf = table.simpleClone(MarkEnum.TempMarkSuffix) + table.insert(temp_suf, "-tmp") return isattack and player:inMyAttackRange(to, self:getDistanceLimit(player, card, to)) or player:distanceTo(to) <= self:getDistanceLimit(player, card, to) or (player:getMark(MarkEnum.BypassDistancesLimit) ~= 0 or - table.find(MarkEnum.TempMarkSuffix, function(s) + table.find(temp_suf, function(s) return player:getMark(MarkEnum.BypassDistancesLimit .. s) ~= 0 end)) or (to:getMark(MarkEnum.BypassDistancesLimitTo) ~= 0 or - table.find(MarkEnum.TempMarkSuffix, function(s) + table.find(temp_suf, function(s) return to:getMark(MarkEnum.BypassDistancesLimitTo .. s) ~= 0 end)) end diff --git a/lua/core/util.lua b/lua/core/util.lua index d8c35711..a2bef8c1 100644 --- a/lua/core/util.lua +++ b/lua/core/util.lua @@ -103,6 +103,47 @@ Util.NameMapper = function(e) return e.name end Util.Name2GeneralMapper = function(e) return Fk.generals[e] end Util.Name2SkillMapper = function(e) return Fk.skills[e] end +-- for card preset +Util.GlobalCanUse = function(self, player, card) + local room = Fk:currentRoom() + for _, p in ipairs(room.alive_players) do + if not (card and player:isProhibited(p, card)) then + return true + end + end +end + +Util.AoeCanUse = function(self, player, card) + local room = Fk:currentRoom() + for _, p in ipairs(room.alive_players) do + if p ~= player and not (card and player:isProhibited(p, card)) then + return true + end + end +end + +Util.GlobalOnUse = function(self, room, cardUseEvent) + if not cardUseEvent.tos or #TargetGroup:getRealTargets(cardUseEvent.tos) == 0 then + cardUseEvent.tos = {} + for _, player in ipairs(room:getAlivePlayers()) do + if not room:getPlayerById(cardUseEvent.from):isProhibited(player, cardUseEvent.card) then + TargetGroup:pushTargets(cardUseEvent.tos, player.id) + end + end + end +end + +Util.AoeOnUse = function(self, room, cardUseEvent) + if not cardUseEvent.tos or #TargetGroup:getRealTargets(cardUseEvent.tos) == 0 then + cardUseEvent.tos = {} + for _, player in ipairs(room:getOtherPlayers(room:getPlayerById(cardUseEvent.from))) do + if not room:getPlayerById(cardUseEvent.from):isProhibited(player, cardUseEvent.card) then + TargetGroup:pushTargets(cardUseEvent.tos, player.id) + end + end + end +end + ---@generic T ---@param self T[] ---@return T[] diff --git a/lua/fk_ex.lua b/lua/fk_ex.lua index b5bf30f7..935f4e47 100644 --- a/lua/fk_ex.lua +++ b/lua/fk_ex.lua @@ -170,6 +170,7 @@ end ---@field public about_to_effect fun(self: ActiveSkill, room: Room, cardEffectEvent: CardEffectEvent): boolean|nil ---@field public on_effect fun(self: ActiveSkill, room: Room, cardEffectEvent: CardEffectEvent): boolean|nil ---@field public on_nullified fun(self: ActiveSkill, room: Room, cardEffectEvent: CardEffectEvent): boolean|nil +---@field public mod_target_filter fun(self: ActiveSkill, to_select: integer, selected: integer[], user: integer, card: Card, distance_limited: boolean): boolean|nil ---@field public prompt fun(self: ActiveSkill, selected: integer[], selected_cards: integer[]): string ---@param spec ActiveSkillSpec @@ -186,6 +187,7 @@ function fk.CreateActiveSkill(spec) 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.mod_target_filter then skill.modTargetFilter = spec.mod_target_filter end if spec.feasible then print(spec.name .. ": feasible is deprecated. Use target_num and card_num instead.") skill.feasible = spec.feasible @@ -274,7 +276,7 @@ end ---@return DistanceSkill function fk.CreateDistanceSkill(spec) assert(type(spec.name) == "string") - assert(type(spec.correct_func) == "function") + assert(type(spec.correct_func) == "function" or type(spec.fixed_func) == "function") local skill = DistanceSkill:new(spec.name) readStatusSpecToSkill(skill, spec) @@ -556,5 +558,9 @@ function fk.CreateGameMode(spec) assert(type(spec.surrender_func) == "function") ret.surrenderFunc = spec.surrender_func end + if spec.is_counted then + assert(type(spec.is_counted) == "function") + ret.countInFunc = spec.is_counted + end return ret end diff --git a/lua/server/events/gameflow.lua b/lua/server/events/gameflow.lua index dc62a3cb..58bf2017 100644 --- a/lua/server/events/gameflow.lua +++ b/lua/server/events/gameflow.lua @@ -155,7 +155,7 @@ GameEvent.functions[GameEvent.Round] = function(self) GameEvent(GameEvent.Turn):exec() if room.game_finished then break end room.current = room.current:getNextAlive() - until p.seat > p:getNextAlive().seat + until p.seat >= p:getNextAlive().seat logic:trigger(fk.RoundEnd, p) end diff --git a/lua/server/gamelogic.lua b/lua/server/gamelogic.lua index b2230be8..6b325e97 100644 --- a/lua/server/gamelogic.lua +++ b/lua/server/gamelogic.lua @@ -105,23 +105,7 @@ function GameLogic:chooseGenerals() end room:setPlayerGeneral(lord, lord_general, true) - if lord.kingdom == "god" or Fk.generals[lord_general].subkingdom then - local allKingdoms = {} - if lord.kingdom == "god" then - allKingdoms = table.simpleClone(Fk.kingdoms) - - local exceptedKingdoms = { "god" } - for _, kingdom in ipairs(exceptedKingdoms) do - table.removeOne(allKingdoms, kingdom) - end - else - local curGeneral = Fk.generals[lord_general] - allKingdoms = { curGeneral.kingdom, curGeneral.subkingdom } - end - - lord.kingdom = room:askForChoice(lord, allKingdoms, "AskForKingdom", "#ChooseInitialKingdom") - room:broadcastProperty(lord, "kingdom") - end + room:askForChooseKingdom({lord}) room:broadcastProperty(lord, "general") room:setDeputyGeneral(lord, deputy) room:broadcastProperty(lord, "deputyGeneral") diff --git a/lua/server/mark_enum.lua b/lua/server/mark_enum.lua index e36c9da9..1b014f77 100644 --- a/lua/server/mark_enum.lua +++ b/lua/server/mark_enum.lua @@ -19,18 +19,18 @@ MarkEnum.MinusMaxCards = "MinusMaxCards" --于本回合内减少标记值数量的手牌上限 MarkEnum.MinusMaxCardsInTurn = "MinusMaxCards-turn" ---使用牌无次数限制,可带清除标记后缀 +---使用牌无次数限制,可带清除标记后缀(-tmp为请求专用) MarkEnum.BypassTimesLimit = "BypassTimesLimit" ---使用牌无距离限制,可带清除标记后缀 +---使用牌无距离限制,可带清除标记后缀(-tmp为请求专用) MarkEnum.BypassDistancesLimit = "BypassDistancesLimit" ---对其使用牌无次数限制,可带清除标记后缀 +---对其使用牌无次数限制,可带清除标记后缀 MarkEnum.BypassTimesLimitTo = "BypassTimesLimitTo" ---对其使用牌无距离限制,可带清除标记后缀 +---对其使用牌无距离限制,可带清除标记后缀 MarkEnum.BypassDistancesLimitTo = "BypassDistancesLimitTo" ---非锁定技失效,可带清除标记后缀 +---非锁定技失效,可带清除标记后缀 MarkEnum.UncompulsoryInvalidity = "UncompulsoryInvalidity" ---各种清除标记后缀 +---各种清除标记后缀 MarkEnum.TempMarkSuffix = { "-phase", "-turn", "-round" } ---卡牌标记版本的清除标记后缀 diff --git a/lua/server/room.lua b/lua/server/room.lua index 839d9d4e..7dc58ac2 100644 --- a/lua/server/room.lua +++ b/lua/server/room.lua @@ -1453,6 +1453,60 @@ function Room:askForSkillInvoke(player, skill_name, data, prompt) return invoked end +--枚举法为使用牌重选目标(无距离限制) +---@param player ServerPlayer @ 执行的玩家 +---@param targets ServerPlayer[] @ 可选的目标范围 +---@param num integer @ 可选的目标数 +---@param can_minus boolean @ 是否可减少 +---@param distance_limited boolean @ 是否受距离限制 +---@param prompt string @ 提示信息 +---@param skillName string @ 技能名 +---@param data CardUseStruct @ 使用数据 +function Room:askForAddTarget(player, targets, num, can_minus, distance_limited, prompt, skillName, data) + num = num or 1 + can_minus = can_minus or false + prompt = prompt or "" + skillName = skillName or "" + local room = player.room + local tos = {} + local orig_tos = table.simpleClone(AimGroup:getAllTargets(data.tos)) + if can_minus and #orig_tos > 1 then --默认不允许减目标至0 + tos = table.map(table.filter(targets, function(p) + return table.contains(AimGroup:getAllTargets(data.tos), p.id) end), Util.IdMapper) + end + for _, p in ipairs(targets) do + if not table.contains(AimGroup:getAllTargets(data.tos), p.id) and not room:getPlayerById(data.from):isProhibited(p, data.card) then + if data.card.skill:modTargetFilter(p.id, orig_tos, player.id, data.card, distance_limited) then + table.insertIfNeed(tos, p.id) + end + end + end + if #tos > 0 then + tos = room:askForChoosePlayers(player, tos, 1, num, prompt, skillName, true) + --借刀……! + if data.card.name ~= "collateral" then + return tos + else + local result = {} + for _, id in ipairs(tos) do + local to = room:getPlayerById(id) + local target = room:askForChoosePlayers(player, table.map(table.filter(room:getOtherPlayers(player), function(v) + return to:inMyAttackRange(v) end), function(p) return p.id end), 1, 1, + "#collateral-choose::"..to.id..":"..data.card:toLogString(), "collateral_skill", true) + if #target > 0 then + table.insert(result, {id, target[1]}) + end + end + if #result > 0 then + return result + else + return {} + end + end + end + return {} +end + -- TODO: guanxing type --- 询问玩家对若干牌进行观星。 --- @@ -1462,7 +1516,7 @@ end ---@param top_limit integer[]|nil @ 置于牌堆顶的牌的限制(下限,上限),不填写则不限 ---@param bottom_limit integer[]|nil @ 置于牌堆底的牌的限制(下限,上限),不填写则不限 ---@param customNotify string|null @ 自定义读条操作提示 ---@param prompt string|null @ 观星框的标题(暂时雪藏) +---param prompt string|null @ 观星框的标题(暂时雪藏) ---@param noPut boolean|null @ 是否进行放置牌操作 ---@param areaNames string[]|null @ 左侧提示信息 ---@return table<"top"|"bottom", integer[]> @@ -1666,10 +1720,10 @@ function Room:askForUseCard(player, card_name, pattern, prompt, cancelable, extr if extra_data then if extra_data.bypass_distances then - player.room:setPlayerMark(player, MarkEnum.BypassDistancesLimit, 1) + player.room:setPlayerMark(player, MarkEnum.BypassDistancesLimit .. "-tmp", 1) end - if extra_data.bypass_times then - player.room:setPlayerMark(player, MarkEnum.BypassTimesLimit, 1) + if extra_data.bypass_times == nil or extra_data.bypass_times then + player.room:setPlayerMark(player, MarkEnum.BypassTimesLimit .. "-tmp", 1) end end local command = "AskForUseCard" @@ -1689,8 +1743,8 @@ function Room:askForUseCard(player, card_name, pattern, prompt, cancelable, extr self.logic:trigger(fk.AskForCardUse, player, askForUseCardData) if askForUseCardData.result and type(askForUseCardData.result) == 'table' then - player.room:setPlayerMark(player, MarkEnum.BypassDistancesLimit, 0) - player.room:setPlayerMark(player, MarkEnum.BypassTimesLimit, 0) + player.room:setPlayerMark(player, MarkEnum.BypassDistancesLimit .. "-tmp", 0) + player.room:setPlayerMark(player, MarkEnum.BypassTimesLimit .. "-tmp", 0) return askForUseCardData.result else local data = {card_name, pattern, prompt, cancelable, extra_data} @@ -1700,13 +1754,13 @@ function Room:askForUseCard(player, card_name, pattern, prompt, cancelable, extr Fk.currentResponsePattern = nil if result ~= "" then - player.room:setPlayerMark(player, MarkEnum.BypassDistancesLimit, 0) - player.room:setPlayerMark(player, MarkEnum.BypassTimesLimit, 0) + player.room:setPlayerMark(player, MarkEnum.BypassDistancesLimit .. "-tmp", 0) + player.room:setPlayerMark(player, MarkEnum.BypassTimesLimit .. "-tmp", 0) return self:handleUseCardReply(player, result) end end - player.room:setPlayerMark(player, MarkEnum.BypassDistancesLimit, 0) - player.room:setPlayerMark(player, MarkEnum.BypassTimesLimit, 0) + player.room:setPlayerMark(player, MarkEnum.BypassDistancesLimit .. "-tmp", 0) + player.room:setPlayerMark(player, MarkEnum.BypassTimesLimit .. "-tmp", 0) return nil end @@ -2970,10 +3024,6 @@ end ---@param room Room local function shouldUpdateWinRate(room) - if room.settings.gameMode == "heg_mode" then return false end - if room.settings.gameMode == "aaa_role_mode" and #room.players < 5 then - return false - end if room.settings.enableFreeAssign then return false end @@ -2983,7 +3033,7 @@ local function shouldUpdateWinRate(room) for _, p in ipairs(room.players) do if p.id < 0 then return false end end - return true + return Fk.game_modes[room.settings.gameMode]:countInFunc(room) end --- 结束一局游戏。 diff --git a/lua/server/serverplayer.lua b/lua/server/serverplayer.lua index 3abc0ef5..50284ed2 100644 --- a/lua/server/serverplayer.lua +++ b/lua/server/serverplayer.lua @@ -661,8 +661,9 @@ end function ServerPlayer:reset() self.room:sendLog{ - type = "#ResetGeneral", + type = "#ChainStateChange", from = self.id, + arg = "reset-general" } self:setChainState(false) if not self.faceup then self:turnOver() end diff --git a/packages/maneuvering/init.lua b/packages/maneuvering/init.lua index 2bfcc73d..9ed84281 100644 --- a/packages/maneuvering/init.lua +++ b/packages/maneuvering/init.lua @@ -9,6 +9,7 @@ local thunderSlashSkill = fk.CreateActiveSkill{ max_phase_use_time = 1, target_num = 1, can_use = slash.skill.canUse, + mod_target_filter = slash.skill.modTargetFilter, target_filter = slash.skill.targetFilter, on_effect = function(self, room, effect) local to = effect.to @@ -47,6 +48,7 @@ local fireSlashSkill = fk.CreateActiveSkill{ max_phase_use_time = 1, target_num = 1, can_use = slash.skill.canUse, + mod_target_filter = slash.skill.modTargetFilter, target_filter = slash.skill.targetFilter, on_effect = function(self, room, effect) local to = effect.to @@ -79,8 +81,14 @@ extension:addCards{ local analepticSkill = fk.CreateActiveSkill{ name = "analeptic_skill", max_turn_use_time = 1, + mod_target_filter = function(self, to_select, selected, user, card, distance_limited) + return self:withinTimesLimit(Fk:currentRoom():getPlayerById(to_select), Player.HistoryTurn, card, "analeptic", Fk:currentRoom():getPlayerById(to_select)) and + not table.find(Fk:currentRoom().players, function(p) + return p.dying + end) + end, can_use = function(self, player, card) - return self:withinTimesLimit(player, Player.HistoryTurn, card, "analeptic", player) + return self:modTargetFilter(player.id, Util.DummyTable, player.id, card) end, on_use = function(self, room, use) if not use.tos or #TargetGroup:getRealTargets(use.tos) == 0 then @@ -171,6 +179,9 @@ local ironChainCardSkill = fk.CreateActiveSkill{ name = "iron_chain_skill", min_target_num = 1, max_target_num = 2, + mod_target_filter = function(self, to_select, selected, user, card, distance_limited) + return true + end, target_filter = function() return true end, on_effect = function(self, room, cardEffectEvent) local to = room:getPlayerById(cardEffectEvent.to) @@ -196,9 +207,12 @@ extension:addCards{ local fireAttackSkill = fk.CreateActiveSkill{ name = "fire_attack_skill", target_num = 1, - target_filter = function(self, to_select) + mod_target_filter = function(self, to_select, selected, user, card, distance_limited) return not Fk:currentRoom():getPlayerById(to_select):isKongcheng() end, + target_filter = function(self, to_select) + return self:modTargetFilter(to_select) + end, on_effect = function(self, room, cardEffectEvent) local from = room:getPlayerById(cardEffectEvent.from) local to = room:getPlayerById(cardEffectEvent.to) diff --git a/packages/standard/hegemony.lua b/packages/standard/hegemony.lua index 0c22a6a8..c877e820 100644 --- a/packages/standard/hegemony.lua +++ b/packages/standard/hegemony.lua @@ -362,6 +362,7 @@ heg = fk.CreateGameMode{ maxPlayer = 8, rule = heg_rule, logic = heg_getlogic, + countInFunc = Util.FalseFunc } Fk:loadTranslationTable{ diff --git a/packages/standard/i18n/zh_CN.lua b/packages/standard/i18n/zh_CN.lua index e964c4e4..0cfb6354 100644 --- a/packages/standard/i18n/zh_CN.lua +++ b/packages/standard/i18n/zh_CN.lua @@ -52,7 +52,7 @@ Fk:loadTranslationTable{ ["xuchu"] = "许褚", ["~xuchu"] = "冷,好冷啊……", - ["$luoyi1"] = "破!", + ["$luoyi1"] = "脱!", ["$luoyi2"] = "谁来与我大战三百回合?", ["luoyi"] = "裸衣", [":luoyi"] = "摸牌阶段,你可以少摸一张牌,若如此做,本回合你使用【杀】或【决斗】对目标角色造成伤害时,此伤害+1。", diff --git a/packages/standard/init.lua b/packages/standard/init.lua index 6dfecee3..650de385 100644 --- a/packages/standard/init.lua +++ b/packages/standard/init.lua @@ -1075,6 +1075,9 @@ local role_mode = fk.CreateGameMode{ name = "aaa_role_mode", -- just to let it at the top of list minPlayer = 2, maxPlayer = 8, + countInFunc = function(self, room) + return #room.players >= 5 + end, surrender_func = function(self, playedTime) local roleCheck = false local roleText = "" diff --git a/packages/standard_cards/i18n/zh_CN.lua b/packages/standard_cards/i18n/zh_CN.lua index f53dd4dc..8bd9ec4d 100644 --- a/packages/standard_cards/i18n/zh_CN.lua +++ b/packages/standard_cards/i18n/zh_CN.lua @@ -16,7 +16,7 @@ Fk:loadTranslationTable{ ["diamond"] = "方块", ["suit"] = "花色", ["color"] = "颜色", - ["figure"] = "点数", + ["number"] = "点数", ["basic_char"] = "基", ["trick_char"] = "锦", diff --git a/packages/standard_cards/init.lua b/packages/standard_cards/init.lua index 1e5edb46..8e2aa7cb 100644 --- a/packages/standard_cards/init.lua +++ b/packages/standard_cards/init.lua @@ -3,46 +3,6 @@ local extension = Package:new("standard_cards", Package.CardPack) extension.metadata = require "packages.standard_cards.metadata" -local global_can_use = function(self, player, card) - local room = Fk:currentRoom() - for _, p in ipairs(room.alive_players) do - if not (card and player:isProhibited(p, card)) then - return true - end - end -end - -local aoe_can_use = function(self, player, card) - local room = Fk:currentRoom() - for _, p in ipairs(room.alive_players) do - if p ~= player and not (card and player:isProhibited(p, card)) then - return true - end - end -end - -local global_on_use = function(self, room, cardUseEvent) - if not cardUseEvent.tos or #TargetGroup:getRealTargets(cardUseEvent.tos) == 0 then - cardUseEvent.tos = {} - for _, player in ipairs(room:getAlivePlayers()) do - if not room:getPlayerById(cardUseEvent.from):isProhibited(player, cardUseEvent.card) then - TargetGroup:pushTargets(cardUseEvent.tos, player.id) - end - end - end -end - -local aoe_on_use = function(self, room, cardUseEvent) - if not cardUseEvent.tos or #TargetGroup:getRealTargets(cardUseEvent.tos) == 0 then - cardUseEvent.tos = {} - for _, player in ipairs(room:getOtherPlayers(room:getPlayerById(cardUseEvent.from))) do - if not room:getPlayerById(cardUseEvent.from):isProhibited(player, cardUseEvent.card) then - TargetGroup:pushTargets(cardUseEvent.tos, player.id) - end - end - end -end - local slashSkill = fk.CreateActiveSkill{ name = "slash_skill", max_phase_use_time = 1, @@ -53,10 +13,15 @@ local slashSkill = fk.CreateActiveSkill{ return self:withinTimesLimit(player, Player.HistoryPhase, card, "slash", p) end) end, + mod_target_filter = function(self, to_select, selected, user, card, distance_limited) + local player = Fk:currentRoom():getPlayerById(to_select) + local from = Fk:currentRoom():getPlayerById(user) + return from ~= player and not (distance_limited and not self:withinDistanceLimit(from, true, card, player)) + end, target_filter = function(self, to_select, selected, _, card) if #selected < self:getMaxTargetNum(Self, card) then local player = Fk:currentRoom():getPlayerById(to_select) - return Self ~= player and self:withinDistanceLimit(Self, true, card, player) and + return self:modTargetFilter(to_select, selected, Self.id, true, card) and (#selected > 0 or self:withinTimesLimit(Self, Player.HistoryPhase, card, "slash", player)) end end, @@ -158,6 +123,12 @@ extension:addCards({ local peachSkill = fk.CreateActiveSkill{ name = "peach_skill", + mod_target_filter = function(self, to_select) + return Fk:currentRoom():getPlayerById(to_select):isWounded() and + not table.find(Fk:currentRoom().players, function(p) + return p.dying + end) + end, can_use = function(self, player) return player:isWounded() end, @@ -201,10 +172,13 @@ extension:addCards({ local dismantlementSkill = fk.CreateActiveSkill{ name = "dismantlement_skill", target_num = 1, + mod_target_filter = function(self, to_select, selected, user) + local player = Fk:currentRoom():getPlayerById(to_select) + return Fk:currentRoom():getPlayerById(user) ~= player and not player:isAllNude() + end, target_filter = function(self, to_select, selected) if #selected < self:getMaxTargetNum(Self) then - local player = Fk:currentRoom():getPlayerById(to_select) - return Self ~= player and not player:isAllNude() + return self:modTargetFilter(to_select, selected, Self.id) end end, on_effect = function(self, room, effect) @@ -236,13 +210,14 @@ extension:addCards({ local snatchSkill = fk.CreateActiveSkill{ name = "snatch_skill", distance_limit = 1, + mod_target_filter = function(self, to_select, selected, user, card, distance_limited) + local player = Fk:currentRoom():getPlayerById(to_select) + local from = Fk:currentRoom():getPlayerById(user) + return from ~= player and not (player:isAllNude() or (distance_limited and not self:withinDistanceLimit(from, true, card, player))) + end, target_filter = function(self, to_select, selected, _, card) if #selected == 0 then - local player = Fk:currentRoom():getPlayerById(to_select) - return - Self ~= player and - self:withinDistanceLimit(Self, false, card, player) and -- for no distance limit for snatch - not player:isAllNude() + return self:modTargetFilter(to_select, selected, Self.id, card, true) end end, target_num = 1, @@ -272,10 +247,12 @@ extension:addCards({ local duelSkill = fk.CreateActiveSkill{ name = "duel_skill", + mod_target_filter = function(self, to_select, selected, user) + return user ~= to_select + end, target_filter = function(self, to_select, selected) if #selected == 0 then - local player = Fk:currentRoom():getPlayerById(to_select) - return Self ~= player + return self:modTargetFilter(to_select, selected, Self.id) end end, target_num = 1, @@ -355,6 +332,10 @@ extension:addCards({ local collateralSkill = fk.CreateActiveSkill{ name = "collateral_skill", + mod_target_filter = function(self, to_select, selected, user, card, distance_limited) + local player = Fk:currentRoom():getPlayerById(to_select) + return user ~= player.id and player:getEquipment(Card.SubtypeWeapon) + end, target_filter = function(self, to_select, selected) local player = Fk:currentRoom():getPlayerById(to_select) if #selected == 0 then @@ -399,6 +380,9 @@ extension:addCards({ local exNihiloSkill = fk.CreateActiveSkill{ name = "ex_nihilo_skill", + mod_target_filter = function(self, to_select, selected, user, card, distance_limited) + return true + end, on_use = function(self, room, cardUseEvent) if not cardUseEvent.tos or #TargetGroup:getRealTargets(cardUseEvent.tos) == 0 then cardUseEvent.tos = { { cardUseEvent.from } } @@ -453,8 +437,11 @@ extension:addCards({ local savageAssaultSkill = fk.CreateActiveSkill{ name = "savage_assault_skill", - can_use = aoe_can_use, - on_use = aoe_on_use, + can_use = Util.AoeCanUse, + on_use = Util.AoeOnUse, + mod_target_filter = function(self, to_select, selected, user, card, distance_limited) + return user ~= to_select + end, on_effect = function(self, room, effect) local cardResponded = room:askForResponse(room:getPlayerById(effect.to), 'slash', nil, nil, false, nil, effect) @@ -493,8 +480,11 @@ extension:addCards({ local archeryAttackSkill = fk.CreateActiveSkill{ name = "archery_attack_skill", - can_use = aoe_can_use, - on_use = aoe_on_use, + can_use = Util.AoeCanUse, + on_use = Util.AoeOnUse, + mod_target_filter = function(self, to_select, selected, user, card, distance_limited) + return user ~= to_select + end, on_effect = function(self, room, effect) local cardResponded = room:askForResponse(room:getPlayerById(effect.to), 'jink', nil, nil, false, nil, effect) @@ -531,8 +521,11 @@ extension:addCards({ local godSalvationSkill = fk.CreateActiveSkill{ name = "god_salvation_skill", - can_use = global_can_use, - on_use = global_on_use, + can_use = Util.GlobalCanUse, + on_use = Util.GlobalOnUse, + mod_target_filter = function(self, to_select, selected, user, card, distance_limited) + return true + end, about_to_effect = function(self, room, effect) if not room:getPlayerById(effect.to):isWounded() then return true @@ -566,8 +559,11 @@ extension:addCards({ local amazingGraceSkill = fk.CreateActiveSkill{ name = "amazing_grace_skill", - can_use = global_can_use, - on_use = global_on_use, + can_use = Util.GlobalCanUse, + on_use = Util.GlobalOnUse, + mod_target_filter = function(self, to_select, selected, user, card, distance_limited) + return true + end, on_effect = function(self, room, effect) local to = room:getPlayerById(effect.to) if not (effect.extra_data and effect.extra_data.AGFilled) then