终结标记与界bugfix (#307)

-
正式移除了作为临时手段的-tmp标记,现在can_use和target_filter支持读取extra_data(card_filter暂时搁置)
-
规范了askForUseCard中card_name和pattern的关系,现在的格式将以pattern为主,若无pattern才会将card_name视为pattern
- 将withinDistanceLimit迁移至ActiveSkill内
- 添加了令卡牌无距离/次数限制的标记判断
- 添加放大了⑨倍的冰伤音效
- 优化了同将判断的逻辑,使其能够准确读取trueName
- 身份场主公选将后其他角色能看见主公技能(只是看见,无实际功能)
- 开局添加不存在的技能时会放出警报
- 修复了findParent在当前事件无parent时报错的bug
- 修复了人工洗牌后不刷新摸牌堆的bug
- 修复了getPile返回牌堆实例的bug
- 修复了getSkillNameList无法过滤主公技的bug
- 修复了死亡后武将牌没有圆角效果的bug
This commit is contained in:
YoumuKon 2024-01-25 03:13:57 +08:00 committed by GitHub
parent db651f572e
commit 21e4c65204
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 206 additions and 121 deletions

View File

@ -483,7 +483,7 @@ Item {
&& JSON.parse(Backend.callLuaFunction("GetPlayerHandcards", [Self.id])).includes(card)) {
const skills = JSON.parse(Backend.callLuaFunction("GetCardSpecialSkills", [card]));
if (JSON.parse(Backend.callLuaFunction("CanUseCard", [card, Self.id]))) {
if (JSON.parse(Backend.callLuaFunction("CanUseCard", [card, Self.id, JSON.stringify(roomScene.extra_data)]))) {
skills.unshift("_normal_use");
}
specialCardSkills.model = skills;

View File

@ -570,7 +570,7 @@ function enableTargets(card) { // card: int | { skill: string, subcards: int[] }
const id = photo.playerid;
const ret = JSON.parse(Backend.callLuaFunction(
"CanUseCardToTarget",
[card, id, selected_targets]
[card, id, selected_targets, JSON.stringify(roomScene.extra_data)]
));
photo.selectable = ret;
if (roomScene.extra_data instanceof Object) {
@ -603,7 +603,7 @@ function enableTargets(card) { // card: int | { skill: string, subcards: int[] }
)) && (roomScene.autoPending || !JSON.parse(Backend.callLuaFunction(
"CardProhibitedUse", [card])));
} else if (okButton.enabled && roomScene.state === "playing") {
okButton.enabled = JSON.parse(Backend.callLuaFunction("CanUseCard", [card, Self.id]));
okButton.enabled = JSON.parse(Backend.callLuaFunction("CanUseCard", [card, Self.id, JSON.stringify(roomScene.extra_data)]));
}
if (okButton.enabled) {
if (roomScene.extra_data instanceof Object) {
@ -648,7 +648,7 @@ function updateSelectedTargets(playerid, selected) {
const id = photo.playerid;
const ret = JSON.parse(Backend.callLuaFunction(
"CanUseCardToTarget",
[card, id, selected_targets]
[card, id, selected_targets, JSON.stringify(roomScene.extra_data)]
));
photo.selectable = ret;
if (roomScene.extra_data instanceof Object) {
@ -681,7 +681,7 @@ function updateSelectedTargets(playerid, selected) {
)) && (roomScene.autoPending || !JSON.parse(Backend.callLuaFunction(
"CardProhibitedUse", [card])));
} else if (okButton.enabled && roomScene.state === "playing") {
okButton.enabled = JSON.parse(Backend.callLuaFunction("CanUseCard", [card, Self.id]));
okButton.enabled = JSON.parse(Backend.callLuaFunction("CanUseCard", [card, Self.id, JSON.stringify(roomScene.extra_data)]));
}
if (okButton.enabled) {
if (roomScene.extra_data instanceof Object) {

View File

@ -223,14 +223,14 @@ RowLayout {
const ids = [], cards = handcardAreaItem.cards;
for (let i = 0; i < cards.length; i++) {
cards[i].prohibitReason = "";
if (JSON.parse(Backend.callLuaFunction("CanUseCard", [cards[i].cid, Self.id]))) {
if (JSON.parse(Backend.callLuaFunction("CanUseCard", [cards[i].cid, Self.id, JSON.stringify(roomScene.extra_data)]))) {
ids.push(cards[i].cid);
} else {
// cannot use? considering special_skills
const skills = JSON.parse(Backend.callLuaFunction("GetCardSpecialSkills", [cards[i].cid]));
for (let j = 0; j < skills.length; j++) {
const s = skills[j];
if (JSON.parse(Backend.callLuaFunction("ActiveCanUse", [s]))) {
if (JSON.parse(Backend.callLuaFunction("ActiveCanUse", [s, JSON.stringify(roomScene.extra_data)]))) {
ids.push(cards[i].cid);
break;
}
@ -475,7 +475,7 @@ RowLayout {
continue;
}
item.enabled = JSON.parse(Backend.callLuaFunction("ActiveCanUse", [item.orig]));
item.enabled = JSON.parse(Backend.callLuaFunction("ActiveCanUse", [item.orig, JSON.stringify(roomScene.extra_data)]));
}
}

View File

@ -247,14 +247,15 @@ Item {
}
OpacityMask {
id: photoMaskEffect
anchors.fill: photoMask
source: generalImgItem
maskSource: photoMask
}
Colorize {
anchors.fill: photoMask
source: generalImgItem
anchors.fill: photoMaskEffect
source: photoMaskEffect
saturation: 0
visible: root.dead || root.surrendered
}

BIN
audio/system/ice_damage.mp3 Normal file

Binary file not shown.

Binary file not shown.

View File

@ -251,8 +251,10 @@ end
---@param card string | integer
---@param player integer
function CanUseCard(card, player)
---@param extra_data_str string
function CanUseCard(card, player, extra_data_str)
local c ---@type Card
local extra_data = extra_data_str == "" and nil or json.decode(extra_data_str)
if type(card) == "number" then
c = Fk:getCardById(card)
else
@ -271,13 +273,13 @@ function CanUseCard(card, player)
end
player = ClientInstance:getPlayerById(player)
local ret = c.skill:canUse(player, c)
local ret = c.skill:canUse(player, c, extra_data)
ret = ret and not player:prohibitUse(c)
if ret then
local min_target = c.skill:getMinTargetNum()
if min_target > 0 then
for _, p in ipairs(ClientInstance.players) do
if c.skill:targetFilter(p.id, {}, {}, c) then
if c.skill:targetFilter(p.id, {}, {}, c, extra_data) then
return "true"
end
end
@ -311,7 +313,9 @@ end
---@param card string | integer
---@param to_select integer @ id of the target
---@param selected integer[] @ ids of selected targets
function CanUseCardToTarget(card, to_select, selected)
---@param extra_data_str string @ extra data
function CanUseCardToTarget(card, to_select, selected, extra_data_str)
local extra_data = extra_data_str == "" and nil or json.decode(extra_data_str)
if ClientInstance:getPlayerById(to_select).dead then
return "false"
end
@ -322,10 +326,10 @@ function CanUseCardToTarget(card, to_select, selected)
selected_cards = {card}
else
local t = json.decode(card)
return ActiveTargetFilter(t.skill, to_select, selected, t.subcards)
return ActiveTargetFilter(t.skill, to_select, selected, t.subcards, extra_data)
end
local ret = c.skill:targetFilter(to_select, selected, selected_cards, c)
local ret = c.skill:targetFilter(to_select, selected, selected_cards, c, extra_data)
ret = ret and not Self:isProhibited(Fk:currentRoom():getPlayerById(to_select), c)
return json.encode(ret)
end
@ -392,12 +396,13 @@ function GetSkillData(skill_name)
}
end
function ActiveCanUse(skill_name)
function ActiveCanUse(skill_name, extra_data_str)
local extra_data = extra_data_str == "" and nil or json.decode(extra_data_str)
local skill = Fk.skills[skill_name]
local ret = false
if skill then
if skill:isInstanceOf(ActiveSkill) then
ret = skill:canUse(Self)
ret = skill:canUse(Self, extra_data)
elseif skill:isInstanceOf(ViewAsSkill) then
ret = skill:enabledAtPlay(Self)
if ret then
@ -414,7 +419,7 @@ function ActiveCanUse(skill_name)
for _, n in ipairs(cnames) do
local c = Fk:cloneCard(n)
c.skillName = skill_name
ret = c.skill:canUse(Self, c)
ret = c.skill:canUse(Self, c, extra_data)
if ret then break end
end
end
@ -449,7 +454,7 @@ function ActiveCardFilter(skill_name, to_select, selected, selected_targets)
return json.encode(ret)
end
function ActiveTargetFilter(skill_name, to_select, selected, selected_cards)
function ActiveTargetFilter(skill_name, to_select, selected, selected_cards, extra_data)
local skill = Fk.skills[skill_name]
local ret = false
if skill then
@ -458,7 +463,7 @@ function ActiveTargetFilter(skill_name, to_select, selected, selected_cards)
elseif skill:isInstanceOf(ViewAsSkill) then
local card = skill:viewAs(selected_cards)
if card then
ret = card.skill:targetFilter(to_select, selected, selected_cards, card)
ret = card.skill:targetFilter(to_select, selected, selected_cards, card, extra_data)
ret = ret and not Self:isProhibited(Fk:currentRoom():getPlayerById(to_select), card)
end
end
@ -722,7 +727,7 @@ function PoxiPrompt(poxi_type, data, extra_data)
local poxi = Fk.poxi_methods[poxi_type]
if not poxi or not poxi.prompt then return "" end
if type(poxi.prompt) == "string" then return Fk:translate(poxi.prompt) end
return poxi.prompt(data, extra_data)
return Fk:translate(poxi.prompt(data, extra_data))
end
function PoxiFilter(poxi_type, to_select, selected, data, extra_data)

View File

@ -268,6 +268,7 @@ Fk:loadTranslationTable({
["thunder_damage"] = "Thunder",
["ice_damage"] = "Ice",
["hp_lost"] = "HP lost",
["lose_hp"] = "lose HP",
["phase_start"] = "Prepare phase",
["phase_judge"] = "Judge phase",

View File

@ -324,6 +324,7 @@ Fk:loadTranslationTable{
["thunder_damage"] = "雷属性",
["ice_damage"] = "冰属性",
["hp_lost"] = "体力流失",
["lose_hp"] = "失去体力",
["phase_start"] = "准备阶段",
["phase_judge"] = "判定阶段",

View File

@ -406,6 +406,9 @@ function Card:getMark(mark)
if (not self:isVirtual()) and next(self.mark) == nil then
self.mark = nil
end
if type(ret) == "table" then
ret = table.simpleClone(ret)
end
return ret
end

View File

@ -275,8 +275,8 @@ end
---@param name string @ 要查询的武将名字
---@return string[] @ 这个武将对应的同名武将列表
function Engine:getSameGenerals(name)
local tmp = name:split("__")
local tName = tmp[#tmp]
if not self.generals[name] then return {} end
local tName = self.generals[name].trueName
local ret = self.same_generals[tName] or {}
return table.filter(ret, function(g)
return g ~= name and self.generals[g] ~= nil and self:canUseGeneral(g)

View File

@ -10,7 +10,7 @@
2. Matcher ('|')
3. Matcher ','
Matcher ||||||id
Matcher ||||||id
'~' AJQK

View File

@ -94,12 +94,18 @@ function General:addRelatedSkill(skill)
end
--- 获取武将所有技能。
---@param include_lord bool
function General:getSkillNameList(include_lord)
local ret = table.map(self.skills, Util.NameMapper)
table.insertTable(ret, self.other_skills)
if not include_lord then
local ret = {}
local other_skills = table.map(self.other_skills, Util.Name2SkillMapper)
local skills = table.connect(self.skills, other_skills)
for _, skill in ipairs(skills) do
if include_lord or not skill.lordSkill then
table.insert(ret, skill.name)
end
end
-- table.insertTable(ret, self.other_skills)
return ret
end

View File

@ -215,7 +215,10 @@ end
---@param mark string @ 标记
---@return any
function Player:getMark(mark)
return (self.mark[mark] or 0)
local mark = self.mark[mark]
if not mark then return 0 end
if type(mark) == "table" then return table.simpleClone(mark) end
return mark
end
--- 判定角色是否拥有对应的Mark。
@ -363,13 +366,13 @@ function Player:getCardIds(playerAreas, specialName)
return cardIds
end
--- 通过名字检索获取玩家是否存在对应私人牌堆。
--- 通过名字检索获取玩家对应私人牌堆。
---@param name string @ 私人牌堆名
function Player:getPile(name)
return self.special_cards[name] or {}
return table.simpleClone(self.special_cards[name] or {})
end
--- 通过ID检索获取玩家是否存在对应私人牌堆。
--- 通过ID检索获取玩家对应私人牌堆。
---@param id integer @ 私人牌堆ID
---@return string?
function Player:getPileNameOfId(id)

View File

@ -27,7 +27,7 @@ end
--- Determine whether the skill can be used in playing phase
---@param player Player
---@param card Card @ helper
function ActiveSkill:canUse(player, card)
function ActiveSkill:canUse(player, card, extra_data)
return self:isEffectable(player)
end
@ -45,8 +45,9 @@ end
---@param to_select integer @ id of the target
---@param selected integer[] @ ids of selected targets
---@param selected_cards integer[] @ ids of selected cards
---@param extra_data any @ extra_data
---@param card Card @ helper
function ActiveSkill:targetFilter(to_select, selected, selected_cards, card)
function ActiveSkill:targetFilter(to_select, selected, selected_cards, card, extra_data)
return false
end
@ -142,6 +143,35 @@ function ActiveSkill:getDistanceLimit(player, card, to)
return ret
end
function ActiveSkill:withinDistanceLimit(player, isattack, card, to)
if to and to.dead then return false end
local status_skills = Fk:currentRoom().status_skills[TargetModSkill] or Util.DummyTable
if not card and self.name:endsWith("_skill") then
card = Fk:cloneCard(self.name:sub(1, #self.name - 6))
end
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)
local card_temp_suf = table.simpleClone(MarkEnum.CardTempMarkSuffix)
table.insert(temp_suf, 1, "")
table.insert(temp_suf, "-tmp")
table.insert(card_temp_suf, 1, "")
return (isattack and player:inMyAttackRange(to)) or
(player:distanceTo(to) > 0 and player:distanceTo(to) <= self:getDistanceLimit(player, card, to)) or
(card and table.find(card_temp_suf, function(s)
return card:getMark(MarkEnum.BypassDistancesLimit .. s) ~= 0
end)) or
(table.find(temp_suf, function(s)
return player:getMark(MarkEnum.BypassDistancesLimit .. s) ~= 0
end)) or
(to and (table.find(temp_suf, function(s)
return to:getMark(MarkEnum.BypassDistancesLimitTo .. s) ~= 0
end)))
end
--- Determine if selected cards and targets are valid for this skill
--- If returns true, the OK button should be enabled
--- only used in skill of players

View File

@ -35,41 +35,24 @@ function UsableSkill:withinTimesLimit(player, scope, card, card_name, to)
for _, skill in ipairs(status_skills) do
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)
local card_temp_suf = table.simpleClone(MarkEnum.CardTempMarkSuffix)
table.insert(temp_suf, 1, "")
table.insert(temp_suf, "-tmp")
table.insert(card_temp_suf, 1, "")
return player:usedCardTimes(card_name, scope) < self:getMaxUseTime(player, scope, card, to) or
(player:getMark(MarkEnum.BypassTimesLimit) ~= 0 or
table.find(temp_suf, function(s)
(card and table.find(card_temp_suf, function(s)
return card:getMark(MarkEnum.BypassTimesLimit .. s) ~= 0
end)) or
(table.find(temp_suf, function(s)
return player:getMark(MarkEnum.BypassTimesLimit .. s) ~= 0
end)) or
(to and (to:getMark(MarkEnum.BypassTimesLimitTo) ~= 0 or
table.find(temp_suf, function(s)
(to and (table.find(temp_suf, function(s)
return to:getMark(MarkEnum.BypassTimesLimitTo .. s) ~= 0
end)))
end
function UsableSkill:withinDistanceLimit(player, isattack, card, to)
if to and to.dead then return false end
local status_skills = Fk:currentRoom().status_skills[TargetModSkill] or Util.DummyTable
if not card and self.name:endsWith("_skill") then
card = Fk:cloneCard(self.name:sub(1, #self.name - 6))
end
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)) or
(player:distanceTo(to) > 0 and player:distanceTo(to) <= self:getDistanceLimit(player, card, to)) or
(player:getMark(MarkEnum.BypassDistancesLimit) ~= 0 or
table.find(temp_suf, function(s)
return player:getMark(MarkEnum.BypassDistancesLimit .. s) ~= 0
end)) or
(to and (to:getMark(MarkEnum.BypassDistancesLimitTo) ~= 0 or
table.find(temp_suf, function(s)
return to:getMark(MarkEnum.BypassDistancesLimitTo .. s) ~= 0
end)))
end
return UsableSkill

View File

@ -170,9 +170,9 @@ function fk.CreateTriggerSkill(spec)
end
---@class ActiveSkillSpec: UsableSkillSpec
---@field public can_use? fun(self: ActiveSkill, player: Player, card: Card): boolean?
---@field public can_use? fun(self: ActiveSkill, player: Player, card: Card, extra_data: any): boolean?
---@field public card_filter? fun(self: ActiveSkill, to_select: integer, selected: integer[], selected_targets: integer[]): boolean?
---@field public target_filter? fun(self: ActiveSkill, to_select: integer, selected: integer[], selected_cards: integer[], card: Card): boolean?
---@field public target_filter? fun(self: ActiveSkill, to_select: integer, selected: integer[], selected_cards: integer[], card: Card, extra_data: any): boolean?
---@field public feasible? fun(self: ActiveSkill, selected: integer[], selected_cards: integer[]): boolean?
---@field public on_use? fun(self: ActiveSkill, room: Room, cardUseEvent: CardUseStruct): boolean?
---@field public about_to_effect? fun(self: ActiveSkill, room: Room, cardEffectEvent: CardEffectEvent): boolean?

View File

@ -27,6 +27,7 @@ function RandomAI:useActiveSkill(skill, card)
-- local max = skill:getMaxTargetNum(player, card)
-- local min_card = skill:getMinCardNum()
-- local max_card = skill:getMaxCardNum()
-- FIXME: ViewAsSkill can be buggy here
for _ = 0, max_try_times do
if skill:feasible(selected_targets, selected_cards, self.player, card) then break end
local avail_targets = table.filter(room:getAlivePlayers(), function(p)
@ -121,6 +122,9 @@ random_cb["AskForUseActiveSkill"] = function(self, jsonData)
for k, v in pairs(extra_data) do
skill[k] = v
end
if skill:isInstanceOf(ViewAsSkill) then
return RandomAI.useVSSkill(skill)
end
return RandomAI.useActiveSkill(self, skill)
end

View File

@ -19,12 +19,12 @@ GameEvent.functions[GameEvent.ChangeProperty] = function(self)
if data.general and data.general ~= "" and data.general ~= player.general then
local originalGeneral = Fk.generals[player.general] or Fk.generals["blank_shibing"]
local originalSkills = originalGeneral and originalGeneral:getSkillNameList() or Util.DummyTable
local originalSkills = originalGeneral and originalGeneral:getSkillNameList(true) or Util.DummyTable
table.insertTableIfNeed(skills, table.map(originalSkills, function(e)
return "-" .. e
end))
local newGeneral = Fk.generals[data.general] or Fk.generals["blank_shibing"]
for _, name in ipairs(newGeneral:getSkillNameList()) do
for _, name in ipairs(newGeneral:getSkillNameList(data.isLord)) do
local s = Fk.skills[name]
if not s.relate_to_place or s.relate_to_place == "m" then
table.insertIfNeed(skills, name)
@ -45,14 +45,14 @@ GameEvent.functions[GameEvent.ChangeProperty] = function(self)
if data.deputyGeneral and data.deputyGeneral ~= player.deputyGeneral then
local originalDeputy = Fk.generals[player.deputyGeneral] or Fk.generals["blank_shibing"]
local originalSkills = originalDeputy and originalDeputy:getSkillNameList() or Util.DummyTable
local originalSkills = originalDeputy and originalDeputy:getSkillNameList(true) or Util.DummyTable
table.insertTableIfNeed(skills, table.map(originalSkills, function(e)
return "-" .. e
end))
if data.deputyGeneral ~= "" then
local newDeputy = Fk.generals[data.deputyGeneral] or Fk.generals["blank_shibing"]
for _, name in ipairs(newDeputy:getSkillNameList()) do
for _, name in ipairs(newDeputy:getSkillNameList(data.isLord)) do
local s = Fk.skills[name]
if not s.relate_to_place or s.relate_to_place == "d" then
table.insertIfNeed(skills, name)

View File

@ -85,10 +85,10 @@ end
function GameEvent:findParent(eventType, includeSelf)
if includeSelf and self.event == eventType then return self end
local e = self.parent
repeat
while e do
if e.event == eventType then return e end
e = e.parent
until not e
end
return nil
end

View File

@ -218,6 +218,10 @@ function GameLogic:attachSkillToPlayers()
local addRoleModSkills = function(player, skillName)
local skill = Fk.skills[skillName]
if not skill then
fk.qCritical("Skill: "..skillName.." doesn't exist!")
return
end
if skill.lordSkill and (player.role ~= "lord" or #room.players < 5) then
return
end

View File

@ -1035,7 +1035,7 @@ function Room:notifySkillInvoked(player, skill_name, skill_type)
self:doAnimate("InvokeUltSkill", {
name = skill_name,
player = player.id,
deputy = player.deputyGeneral and player.deputyGeneral ~= "" and table.contains(Fk.generals[player.deputyGeneral]:getSkillNameList(), skill_name),
deputy = player.deputyGeneral and player.deputyGeneral ~= "" and table.contains(Fk.generals[player.deputyGeneral]:getSkillNameList(true), skill_name),
})
self:delay(2000)
end
@ -1978,36 +1978,26 @@ end
---@param event_data? CardEffectEvent @ 事件信息
---@return CardUseStruct? @ 返回关于本次使用牌的数据,以便后续处理
function Room:askForUseCard(player, card_name, pattern, prompt, cancelable, extra_data, event_data)
pattern = pattern or card_name
if event_data and (event_data.disresponsive or table.contains(event_data.disresponsiveList or Util.DummyTable, player.id)) then
return nil
end
if event_data and event_data.prohibitedCardNames and card_name then
local splitedCardNames = card_name:split(",")
splitedCardNames = table.filter(splitedCardNames, function(name)
return not table.contains(event_data.prohibitedCardNames, name)
end)
if #splitedCardNames == 0 then
return nil
if event_data and event_data.prohibitedCardNames then
local exp = Exppattern:Parse(pattern)
for _, matcher in ipairs(exp.matchers) do
matcher.name = table.filter(matcher.name, function(name)
return not table.contains(event_data.prohibitedCardNames, name)
end)
if #matcher.name == 0 then return nil end
end
card_name = table.concat(splitedCardNames, ",")
pattern = tostring(exp)
end
if extra_data then
if extra_data.bypass_distances then
player.room:setPlayerMark(player, MarkEnum.BypassDistancesLimit .. "-tmp", 1) -- FIXME: 缺少直接传入无限制的手段
end
if extra_data.bypass_times == nil or extra_data.bypass_times then
player.room:setPlayerMark(player, MarkEnum.BypassTimesLimit .. "-tmp", 1) -- FIXME: 缺少直接传入无限制的手段
end
end
local command = "AskForUseCard"
self:notifyMoveFocus(player, card_name)
cancelable = (cancelable == nil) and true or cancelable
extra_data = extra_data or Util.DummyTable
pattern = pattern or card_name
prompt = prompt or ""
local askForUseCardData = {
@ -2020,8 +2010,6 @@ 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 .. "-tmp", 0) -- FIXME: 缺少直接传入无限制的手段
player.room:setPlayerMark(player, MarkEnum.BypassTimesLimit .. "-tmp", 0) -- FIXME: 缺少直接传入无限制的手段
return askForUseCardData.result
else
local useResult
@ -2036,8 +2024,6 @@ function Room:askForUseCard(player, card_name, pattern, prompt, cancelable, extr
Fk.currentResponsePattern = nil
if result ~= "" then
player.room:setPlayerMark(player, MarkEnum.BypassDistancesLimit .. "-tmp", 0) -- FIXME: 缺少直接传入无限制的手段
player.room:setPlayerMark(player, MarkEnum.BypassTimesLimit .. "-tmp", 0) -- FIXME: 缺少直接传入无限制的手段
useResult = self:handleUseCardReply(player, result)
if type(useResult) == "string" and useResult ~= "" then
@ -2045,12 +2031,8 @@ function Room:askForUseCard(player, card_name, pattern, prompt, cancelable, extr
end
end
until type(useResult) ~= "string"
player.room:setPlayerMark(player, MarkEnum.BypassDistancesLimit .. "-tmp", 0) -- FIXME: 缺少直接传入无限制的手段
player.room:setPlayerMark(player, MarkEnum.BypassTimesLimit .. "-tmp", 0) -- FIXME: 缺少直接传入无限制的手段
return useResult
end
player.room:setPlayerMark(player, MarkEnum.BypassDistancesLimit .. "-tmp", 0) -- FIXME: 缺少直接传入无限制的手段
player.room:setPlayerMark(player, MarkEnum.BypassTimesLimit .. "-tmp", 0) -- FIXME: 缺少直接传入无限制的手段
return nil
end
@ -3337,6 +3319,8 @@ function Room:shuffleDrawPile()
self.discard_pile = {}
table.shuffle(self.draw_pile)
self:doBroadcastNotify("UpdateDrawPile", #self.draw_pile)
self.logic:trigger(fk.AfterDrawPileShuffle, nil, {})
end

View File

@ -923,7 +923,7 @@ function ServerPlayer:revealGeneral(isDeputy, no_trigger)
end
local general = Fk.generals[generalName] or Fk.generals["blank_shibing"]
for _, s in ipairs(general:getSkillNameList()) do
for _, s in ipairs(general:getSkillNameList(true)) do
local skill = Fk.skills[s]
self:loseFakeSkill(skill)
end
@ -931,7 +931,7 @@ function ServerPlayer:revealGeneral(isDeputy, no_trigger)
local ret = true
if not ((isDeputy and self.general ~= "anjiang") or (not isDeputy and self.deputyGeneral ~= "anjiang")) then
local other = Fk.generals[self:getMark(isDeputy and "__heg_general" or "__heg_deputy")] or Fk.generals["blank_shibing"]
for _, sname in ipairs(other:getSkillNameList()) do
for _, sname in ipairs(other:getSkillNameList(true)) do
local s = Fk.skills[sname]
if s.frequency == Skill.Compulsory and s.relate_to_place ~= (isDeputy and "m" or "d") then
ret = false
@ -1017,7 +1017,7 @@ function ServerPlayer:revealBySkillName(skill_name)
if main then
if table.contains(Fk.generals[self:getMark("__heg_general")]
:getSkillNameList(), skill_name) then
:getSkillNameList(true), skill_name) then
self:revealGeneral(false)
return
end
@ -1025,7 +1025,7 @@ function ServerPlayer:revealBySkillName(skill_name)
if deputy then
if table.contains(Fk.generals[self:getMark("__heg_deputy")]
:getSkillNameList(), skill_name) then
:getSkillNameList(true), skill_name) then
self:revealGeneral(true)
return
end

View File

@ -109,13 +109,13 @@ local analepticSkill = fk.CreateActiveSkill{
prompt = "#analeptic_skill",
max_turn_use_time = 1,
mod_target_filter = function(self, to_select, _, _, card, _)
return self:withinTimesLimit(Fk:currentRoom():getPlayerById(to_select), Player.HistoryTurn, card, "analeptic", Fk:currentRoom():getPlayerById(to_select)) and
not table.find(Fk:currentRoom().alive_players, function(p)
return p.dying
end)
return not table.find(Fk:currentRoom().alive_players, function(p)
return p.dying
end)
end,
can_use = function(self, player, card)
return self:withinTimesLimit(player, Player.HistoryTurn, card, "analeptic", player)
can_use = function(self, player, card, extra_data)
return ((extra_data and (extra_data.bypass_times or extra_data.analepticRecover)) or
self:withinTimesLimit(player, Player.HistoryTurn, card, "analeptic", player))
end,
on_use = function(_, _, use)
if not use.tos or #TargetGroup:getRealTargets(use.tos) == 0 then
@ -291,8 +291,9 @@ local supplyShortageSkill = fk.CreateActiveSkill{
local from = Fk:currentRoom():getPlayerById(user)
return from ~= player and not (distance_limited and not self:withinDistanceLimit(from, false, card, player))
end,
target_filter = function(self, to_select, selected, _, card)
return #selected == 0 and self:modTargetFilter(to_select, selected, Self.id, card, true)
target_filter = function(self, to_select, selected, _, card, extra_data)
local count_distances = not (extra_data and extra_data.bypass_distances)
return #selected == 0 and self:modTargetFilter(to_select, selected, Self.id, card, count_distances)
end,
target_num = 1,
on_effect = function(self, room, effect)

View File

@ -207,7 +207,7 @@ local revealProhibited = fk.CreateInvaliditySkill {
end
local generalName = g == "m" and from:getMark("__heg_general") or from:getMark("__heg_deputy")
local general = Fk.generals[generalName]
if table.contains(general:getSkillNameList(), sname) then
if table.contains(general:getSkillNameList(true), sname) then
return true
end
end
@ -223,7 +223,7 @@ local revealSkill = fk.CreateActiveSkill{
local choiceList = {}
if (Self.general == "anjiang" and not Self:prohibitReveal()) then
local general = Fk.generals[Self:getMark("__heg_general")]
for _, sname in ipairs(general:getSkillNameList()) do
for _, sname in ipairs(general:getSkillNameList(true)) do
local s = Fk.skills[sname]
if s.frequency == Skill.Compulsory and s.relate_to_place ~= "m" then
table.insert(choiceList, "revealMain")
@ -233,7 +233,7 @@ local revealSkill = fk.CreateActiveSkill{
end
if (Self.deputyGeneral == "anjiang" and not Self:prohibitReveal(true)) then
local general = Fk.generals[Self:getMark("__heg_deputy")]
for _, sname in ipairs(general:getSkillNameList()) do
for _, sname in ipairs(general:getSkillNameList(true)) do
local s = Fk.skills[sname]
if s.frequency == Skill.Compulsory and s.relate_to_place ~= "d" then
table.insert(choiceList, "revealDeputy")

View File

@ -53,7 +53,7 @@ GameRule = fk.CreateTriggerSkill{
end)
if #cardNames == 0 then return end
local peach_use = room:askForUseCard(player, "peach", table.concat(cardNames, ",") , prompt)
local peach_use = room:askForUseCard(player, "peach", table.concat(cardNames, ",") , prompt, true, {analepticRecover = true})
if not peach_use then break end
peach_use.tos = { {dyingPlayer.id} }
if peach_use.card.trueName == "analeptic" then

View File

@ -1172,6 +1172,56 @@ local role_getlogic = function()
room:broadcastProperty(lord, "kingdom")
room:setDeputyGeneral(lord, deputy)
room:broadcastProperty(lord, "deputyGeneral")
-- 显示技能
local canAttachSkill = function(player, skillName)
local skill = Fk.skills[skillName]
if not skill then
fk.qCritical("Skill: "..skillName.." doesn't exist!")
return false
end
if skill.lordSkill and (player.role ~= "lord" or #room.players < 5) then
return false
end
if #skill.attachedKingdom > 0 and not table.contains(skill.attachedKingdom, player.kingdom) then
return false
end
return true
end
local lord_skills = {}
for _, s in ipairs(Fk.generals[lord.general].skills) do
if canAttachSkill(lord, s.name) then
table.insertIfNeed(lord_skills, s.name)
end
end
for _, sname in ipairs(Fk.generals[lord.general].other_skills) do
if canAttachSkill(lord, sname) then
table.insertIfNeed(lord_skills, sname)
end
end
local deputyGeneral = Fk.generals[lord.deputyGeneral]
if deputyGeneral then
for _, s in ipairs(deputyGeneral.skills) do
if canAttachSkill(lord, s.name) then
table.insertIfNeed(lord_skills, s.name)
end
end
for _, sname in ipairs(deputyGeneral.other_skills) do
if canAttachSkill(lord, sname) then
table.insertIfNeed(lord_skills, sname)
end
end
end
for _, skill in ipairs(lord_skills) do
room:doBroadcastNotify("AddSkill", json.encode{
lord.id,
skill
})
end
end
local nonlord = room:getOtherPlayers(lord, true)

View File

@ -20,8 +20,8 @@ local slashSkill = fk.CreateActiveSkill{
end,
max_phase_use_time = 1,
target_num = 1,
can_use = function(self, player, card)
return
can_use = function(self, player, card, extra_data)
return (extra_data and extra_data.bypass_times) or
table.find(Fk:currentRoom().alive_players, function(p)
return self:withinTimesLimit(player, Player.HistoryPhase, card, "slash", p)
end)
@ -31,11 +31,12 @@ local slashSkill = fk.CreateActiveSkill{
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)
target_filter = function(self, to_select, selected, _, card, extra_data)
local count_distances = not (extra_data and extra_data.bypass_distances)
if #selected < self:getMaxTargetNum(Self, card) then
local player = Fk:currentRoom():getPlayerById(to_select)
return self:modTargetFilter(to_select, selected, Self.id, card, true) and
(#selected > 0 or self:withinTimesLimit(Self, Player.HistoryPhase, card, "slash", player))
return self:modTargetFilter(to_select, selected, Self.id, card, count_distances) and
(#selected > 0 or (extra_data and extra_data.bypass_times) or self:withinTimesLimit(Self, Player.HistoryPhase, card, "slash", player))
end
end,
on_effect = function(self, room, effect)
@ -229,9 +230,10 @@ local snatchSkill = fk.CreateActiveSkill{
local from = Fk:currentRoom():getPlayerById(user)
return from ~= player and not (player:isAllNude() or (distance_limited and not self:withinDistanceLimit(from, false, card, player)))
end,
target_filter = function(self, to_select, selected, _, card)
target_filter = function(self, to_select, selected, _, card, extra_data)
local count_distances = not (extra_data and extra_data.bypass_distances)
if #selected < self:getMaxTargetNum(Self, card) then
return self:modTargetFilter(to_select, selected, Self.id, card, true)
return self:modTargetFilter(to_select, selected, Self.id, card, count_distances)
end
end,
target_num = 1,

View File

@ -90,6 +90,8 @@ local control = fk.CreateActiveSkill{
-- room:setPlayerMark(from, "@$b", {'slash','duel','axe'})
--room:askForMiniGame({from}, "test", "test", { [from.id] = {"Helloworld"} })
--print(from.client_reply)
-- p(Fk.generals[to.general]:getSkillNameList())
-- p(Fk.generals[to.general]:getSkillNameList(true))
if to:getMark("mouxushengcontrolled") == 0 then
room:addPlayerMark(to, "mouxushengcontrolled")
from:control(to)
@ -412,6 +414,11 @@ Fk:loadTranslationTable{
["$change_hero"] = "敌军色厉内荏,可筑假城以退敌!",
["~mouxusheng"] = "来世,愿再为我江东之臣……",
["heal_hp"] = "回复体力",
["lose_max_hp"] = "减少体力上限",
["heal_max_hp"] = "增加体力上限",
["revive"] = "复活",
}
return { extension }