bugfix (#328)
- 为findParent添加深度限制参数(默认无限制) - 搬运了damageByCardEffect - 修复了ex__choose_skill - 修复了华佗、吕蒙和古锭刀 - 添加势力映射,可以指定一个势力必须变成其他几个势力之一(需要神话再临包/OL包自行处理神将变将范围) - askForCardsChosen界限突破,改成了基于askForPoxi的格式 - 修复了空城虚拟杀可以方天的bug - 给强制平局添加了原因提醒 - 优化了移动牌的视觉逻辑
This commit is contained in:
parent
75d0ad55c8
commit
e840a3b322
|
@ -275,15 +275,30 @@ function moveCards(moves) {
|
||||||
const move = moves[i];
|
const move = moves[i];
|
||||||
const from = getAreaItem(move.fromArea, move.from);
|
const from = getAreaItem(move.fromArea, move.from);
|
||||||
const to = getAreaItem(move.toArea, move.to);
|
const to = getAreaItem(move.toArea, move.to);
|
||||||
if (!from || !to || from === to)
|
if (!from || !to || (from === to && move.fromArea !== Card.DiscardPile))
|
||||||
continue;
|
continue;
|
||||||
const items = from.remove(move.ids, move.fromSpecialName);
|
const items = from.remove(move.ids, move.fromSpecialName);
|
||||||
if (items.length > 0)
|
if (to === tablePile) {
|
||||||
to.add(items, move.specialName);
|
let vanished = items.filter(c => c.cid === -1);
|
||||||
to.updateCardPosition(true);
|
if (vanished.length > 0) {
|
||||||
|
drawPile.add(vanished, move.specialName);
|
||||||
|
drawPile.updateCardPosition(true);
|
||||||
|
}
|
||||||
|
vanished = items.filter(c => c.cid !== -1);
|
||||||
|
if (vanished.length > 0) {
|
||||||
|
to.add(vanished, move.specialName);
|
||||||
|
to.updateCardPosition(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (items.length > 0)
|
||||||
|
to.add(items, move.specialName);
|
||||||
|
to.updateCardPosition(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function resortHandcards() {
|
function resortHandcards() {
|
||||||
if (!dashboard.handcardArea.cards.length) {
|
if (!dashboard.handcardArea.cards.length) {
|
||||||
return;
|
return;
|
||||||
|
@ -1174,9 +1189,9 @@ callbacks["AskForPoxi"] = (jsonData) => {
|
||||||
roomScene.popupBox.sourceComponent =
|
roomScene.popupBox.sourceComponent =
|
||||||
Qt.createComponent("../RoomElement/PoxiBox.qml");
|
Qt.createComponent("../RoomElement/PoxiBox.qml");
|
||||||
const box = roomScene.popupBox.item;
|
const box = roomScene.popupBox.item;
|
||||||
|
box.extra_data = JSON.stringify(extra_data);
|
||||||
box.poxi_type = type;
|
box.poxi_type = type;
|
||||||
box.card_data = data;
|
box.card_data = data;
|
||||||
box.extra_data = extra_data;
|
|
||||||
box.cancelable = cancelable;
|
box.cancelable = cancelable;
|
||||||
for (let d of data) {
|
for (let d of data) {
|
||||||
const arr = [];
|
const arr = [];
|
||||||
|
@ -1185,6 +1200,7 @@ callbacks["AskForPoxi"] = (jsonData) => {
|
||||||
ids.forEach(id => arr.push(lcall("GetCardData", id)));
|
ids.forEach(id => arr.push(lcall("GetCardData", id)));
|
||||||
box.addCustomCards(d[0], arr);
|
box.addCustomCards(d[0], arr);
|
||||||
}
|
}
|
||||||
|
box.refreshPrompt();
|
||||||
|
|
||||||
roomScene.popupBox.moveToCenter();
|
roomScene.popupBox.moveToCenter();
|
||||||
box.cardsSelected.connect((ids) => {
|
box.cardsSelected.connect((ids) => {
|
||||||
|
|
|
@ -2,12 +2,13 @@
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
import Fk
|
||||||
import Fk.Pages
|
import Fk.Pages
|
||||||
|
|
||||||
GraphicsBox {
|
GraphicsBox {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
title.text: lcall("PoxiPrompt", poxi_type, card_data, extra_data)
|
title.text: Util.processPrompt(lcall("PoxiPrompt", poxi_type, card_data, extra_data))
|
||||||
|
|
||||||
// TODO: Adjust the UI design in case there are more than 7 cards
|
// TODO: Adjust the UI design in case there are more than 7 cards
|
||||||
width: 70 + 700
|
width: 70 + 700
|
||||||
|
@ -71,7 +72,7 @@ GraphicsBox {
|
||||||
number: model.number || 0
|
number: model.number || 0
|
||||||
autoBack: false
|
autoBack: false
|
||||||
known: model.cid !== -1
|
known: model.cid !== -1
|
||||||
selectable: root.selected_ids.includes(model.cid) ||
|
selectable: chosenInBox ||
|
||||||
lcall("PoxiFilter", root.poxi_type, model.cid, root.selected_ids,
|
lcall("PoxiFilter", root.poxi_type, model.cid, root.selected_ids,
|
||||||
root.card_data, root.extra_data);
|
root.card_data, root.extra_data);
|
||||||
|
|
||||||
|
@ -84,6 +85,7 @@ GraphicsBox {
|
||||||
root.selected_ids.splice(root.selected_ids.indexOf(cid), 1);
|
root.selected_ids.splice(root.selected_ids.indexOf(cid), 1);
|
||||||
}
|
}
|
||||||
root.selected_ids = root.selected_ids;
|
root.selected_ids = root.selected_ids;
|
||||||
|
refreshPrompt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,7 +125,7 @@ GraphicsBox {
|
||||||
let ret;
|
let ret;
|
||||||
for (let i = 0; i < cardModel.count; i++) {
|
for (let i = 0; i < cardModel.count; i++) {
|
||||||
let item = cardModel.get(i);
|
let item = cardModel.get(i);
|
||||||
if (item.areaName == name) {
|
if (item.areaName === name) {
|
||||||
ret = item;
|
ret = item;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -149,4 +151,8 @@ GraphicsBox {
|
||||||
area.append(cards);
|
area.append(cards);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function refreshPrompt() {
|
||||||
|
root.title.text = Util.processPrompt(lcall("PoxiPrompt", poxi_type, card_data, extra_data))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -744,6 +744,7 @@ end
|
||||||
|
|
||||||
function PoxiPrompt(poxi_type, data, extra_data)
|
function PoxiPrompt(poxi_type, data, extra_data)
|
||||||
local poxi = Fk.poxi_methods[poxi_type]
|
local poxi = Fk.poxi_methods[poxi_type]
|
||||||
|
extra_data = extra_data and json.decode(extra_data)
|
||||||
if not poxi or not poxi.prompt then return "" end
|
if not poxi or not poxi.prompt then return "" end
|
||||||
if type(poxi.prompt) == "string" then return Fk:translate(poxi.prompt) end
|
if type(poxi.prompt) == "string" then return Fk:translate(poxi.prompt) end
|
||||||
return Fk:translate(poxi.prompt(data, extra_data))
|
return Fk:translate(poxi.prompt(data, extra_data))
|
||||||
|
@ -751,12 +752,14 @@ end
|
||||||
|
|
||||||
function PoxiFilter(poxi_type, to_select, selected, data, extra_data)
|
function PoxiFilter(poxi_type, to_select, selected, data, extra_data)
|
||||||
local poxi = Fk.poxi_methods[poxi_type]
|
local poxi = Fk.poxi_methods[poxi_type]
|
||||||
|
extra_data = extra_data and json.decode(extra_data)
|
||||||
if not poxi then return "false" end
|
if not poxi then return "false" end
|
||||||
return json.encode(poxi.card_filter(to_select, selected, data, extra_data))
|
return json.encode(poxi.card_filter(to_select, selected, data, extra_data))
|
||||||
end
|
end
|
||||||
|
|
||||||
function PoxiFeasible(poxi_type, selected, data, extra_data)
|
function PoxiFeasible(poxi_type, selected, data, extra_data)
|
||||||
local poxi = Fk.poxi_methods[poxi_type]
|
local poxi = Fk.poxi_methods[poxi_type]
|
||||||
|
extra_data = extra_data and json.decode(extra_data)
|
||||||
if not poxi then return "false" end
|
if not poxi then return "false" end
|
||||||
return json.encode(poxi.feasible(selected, data, extra_data))
|
return json.encode(poxi.feasible(selected, data, extra_data))
|
||||||
end
|
end
|
||||||
|
|
|
@ -250,6 +250,12 @@ Fk:loadTranslationTable({
|
||||||
-- ["Trusting ..."] = "托管中 ...",
|
-- ["Trusting ..."] = "托管中 ...",
|
||||||
-- ["Observing ..."] = "旁观中 ...",
|
-- ["Observing ..."] = "旁观中 ...",
|
||||||
|
|
||||||
|
["#NoCardDraw"] = "Card Pile is empty",
|
||||||
|
["#NoGeneralDraw"] = "General Pile is empty",
|
||||||
|
["#NoEventDraw"] = "All game events terminated",
|
||||||
|
["#NoEnoughGeneralDraw"] = "No enough generals! (%arg/%arg2)",
|
||||||
|
["#TimeOutDraw"] = "It's over 9999 Round!",
|
||||||
|
|
||||||
["$GameOver"] = "Game Over",
|
["$GameOver"] = "Game Over",
|
||||||
["$Winner"] = "Winner is %1",
|
["$Winner"] = "Winner is %1",
|
||||||
["$NoWinner"] = "Draw!",
|
["$NoWinner"] = "Draw!",
|
||||||
|
|
|
@ -307,6 +307,12 @@ FreeKill使用的是libgit2的C API,与此同时使用Git完成拓展包的下
|
||||||
["resting..."] = "休整中",
|
["resting..."] = "休整中",
|
||||||
["rest round num"] = "轮次",
|
["rest round num"] = "轮次",
|
||||||
|
|
||||||
|
["#NoCardDraw"] = "牌堆被摸空了",
|
||||||
|
["#NoGeneralDraw"] = "武将牌堆被摸空了",
|
||||||
|
["#NoEventDraw"] = "没有可执行的事件",
|
||||||
|
["#NoEnoughGeneralDraw"] = "武将数不足!(%arg/%arg2)",
|
||||||
|
["#TimeOutDraw"] = "轮数已经突破极限!",
|
||||||
|
|
||||||
["$GameOver"] = "游戏结束",
|
["$GameOver"] = "游戏结束",
|
||||||
["$Winner"] = "%1 获胜",
|
["$Winner"] = "%1 获胜",
|
||||||
["$NoWinner"] = "平局!",
|
["$NoWinner"] = "平局!",
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
---@field public currentResponseReason string @ 要求用牌的原因(如濒死,被特定牌指定,使用特定技能···)
|
---@field public currentResponseReason string @ 要求用牌的原因(如濒死,被特定牌指定,使用特定技能···)
|
||||||
---@field public filtered_cards table<integer, Card> @ 被锁视技影响的卡牌
|
---@field public filtered_cards table<integer, Card> @ 被锁视技影响的卡牌
|
||||||
---@field public printed_cards table<integer, Card> @ 被某些房间现场打印的卡牌,id都是负数且从-2开始
|
---@field public printed_cards table<integer, Card> @ 被某些房间现场打印的卡牌,id都是负数且从-2开始
|
||||||
|
---@field private kingdoms string[] @ 总势力
|
||||||
|
---@field private kingdom_map table<string, string[]> @ 势力映射表
|
||||||
---@field private _custom_events any[] @ 自定义事件列表
|
---@field private _custom_events any[] @ 自定义事件列表
|
||||||
---@field public poxi_methods table<string, PoxiSpec> @ “魄袭”框操作方法表
|
---@field public poxi_methods table<string, PoxiSpec> @ “魄袭”框操作方法表
|
||||||
---@field public qml_marks table<string, QmlMarkSpec> @ 自定义Qml标记的表
|
---@field public qml_marks table<string, QmlMarkSpec> @ 自定义Qml标记的表
|
||||||
|
@ -67,6 +69,7 @@ function Engine:initialize()
|
||||||
self.game_modes = {}
|
self.game_modes = {}
|
||||||
self.game_mode_disabled = {}
|
self.game_mode_disabled = {}
|
||||||
self.kingdoms = {}
|
self.kingdoms = {}
|
||||||
|
self.kingdom_map = {}
|
||||||
self._custom_events = {}
|
self._custom_events = {}
|
||||||
self.poxi_methods = {}
|
self.poxi_methods = {}
|
||||||
self.qml_marks = {}
|
self.qml_marks = {}
|
||||||
|
@ -271,6 +274,30 @@ function Engine:addGenerals(generals)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- 为一个势力添加势力映射
|
||||||
|
---
|
||||||
|
--- 这意味着原势力登场时必须改变为添加的几个势力之一(须存在)
|
||||||
|
---@param kingdom string @ 原势力
|
||||||
|
---@param kingdoms string[] @ 需要映射到的势力
|
||||||
|
function Engine:appendKingdomMap(kingdom, kingdoms)
|
||||||
|
local ret = self.kingdom_map[kingdom] or {}
|
||||||
|
table.insertTableIfNeed(ret, kingdoms)
|
||||||
|
self.kingdom_map[kingdom] = ret
|
||||||
|
end
|
||||||
|
|
||||||
|
---获得一个势力所映射到的势力,若没有,返回空集
|
||||||
|
---@param kingdom string @ 原势力
|
||||||
|
---@return string[] @ 可用势力列表,可能是空的
|
||||||
|
function Engine:getKingdomMap(kingdom)
|
||||||
|
local ret = {}
|
||||||
|
for _, k in ipairs(self.kingdom_map[kingdom] or {}) do
|
||||||
|
if table.contains(self.kingdoms, k) then
|
||||||
|
table.insertIfNeed(ret, k)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
--- 判断一个武将是否在本房间可用。
|
--- 判断一个武将是否在本房间可用。
|
||||||
---@param g string @ 武将名
|
---@param g string @ 武将名
|
||||||
function Engine:canUseGeneral(g)
|
function Engine:canUseGeneral(g)
|
||||||
|
|
|
@ -874,7 +874,7 @@ end
|
||||||
---@param card Card @ 特定牌
|
---@param card Card @ 特定牌
|
||||||
---@param extra_data? UseExtraData @ 额外数据
|
---@param extra_data? UseExtraData @ 额外数据
|
||||||
function Player:canUse(card, extra_data)
|
function Player:canUse(card, extra_data)
|
||||||
return card.skill:canUse(self, card, extra_data)
|
return not self:prohibitUse(card) and card.skill:canUse(self, card, extra_data)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- 确认玩家是否可以对特定玩家使用特定牌。
|
--- 确认玩家是否可以对特定玩家使用特定牌。
|
||||||
|
|
|
@ -57,7 +57,7 @@ end
|
||||||
---@param selected? integer[] @ ids of selected targets
|
---@param selected? integer[] @ ids of selected targets
|
||||||
---@param user? integer @ id of the userdata
|
---@param user? integer @ id of the userdata
|
||||||
---@param card? Card @ helper
|
---@param card? Card @ helper
|
||||||
---@param distance_limited boolean @ is limited by distance
|
---@param distance_limited? boolean @ is limited by distance
|
||||||
function ActiveSkill:modTargetFilter(to_select, selected, user, card, distance_limited)
|
function ActiveSkill:modTargetFilter(to_select, selected, user, card, distance_limited)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
|
@ -235,6 +235,7 @@ end
|
||||||
---@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, response: boolean): boolean?
|
---@field public enabled_at_response? fun(self: ViewAsSkill, player: Player, response: boolean): boolean?
|
||||||
---@field public before_use? fun(self: ViewAsSkill, player: ServerPlayer, use: CardUseStruct): string?
|
---@field public before_use? fun(self: ViewAsSkill, player: ServerPlayer, use: CardUseStruct): string?
|
||||||
|
---@field public after_use? fun(self: ViewAsSkill, player: ServerPlayer, use: CardUseStruct): string?
|
||||||
---@field public prompt? string|fun(self: ActiveSkill, selected: integer[], selected_cards: integer[]): string
|
---@field public prompt? string|fun(self: ActiveSkill, selected: integer[], selected_cards: integer[]): string
|
||||||
|
|
||||||
---@param spec ViewAsSkillSpec
|
---@param spec ViewAsSkillSpec
|
||||||
|
|
|
@ -148,6 +148,10 @@ GameEvent.functions[GameEvent.Round] = function(self)
|
||||||
room:doBroadcastNotify("UpdateRoundNum", roundCount)
|
room:doBroadcastNotify("UpdateRoundNum", roundCount)
|
||||||
-- 强行平局 防止can_trigger报错导致瞬间几十万轮卡炸服务器
|
-- 强行平局 防止can_trigger报错导致瞬间几十万轮卡炸服务器
|
||||||
if roundCount >= 9999 then
|
if roundCount >= 9999 then
|
||||||
|
room:sendLog{
|
||||||
|
type = "#TimeOutDraw",
|
||||||
|
toast = true,
|
||||||
|
}
|
||||||
room:gameOver("")
|
room:gameOver("")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -354,6 +358,7 @@ GameEvent.functions[GameEvent.Phase] = function(self)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
) - player:getMaxCards()
|
) - player:getMaxCards()
|
||||||
|
room:broadcastProperty(player, "MaxCards")
|
||||||
if discardNum > 0 then
|
if discardNum > 0 then
|
||||||
room:askForDiscard(player, discardNum, discardNum, false, "game_rule", false)
|
room:askForDiscard(player, discardNum, discardNum, false, "game_rule", false)
|
||||||
end
|
end
|
||||||
|
|
|
@ -84,17 +84,32 @@ function GameEvent:prependExitFunc(f)
|
||||||
table.insert(self.extra_exit_funcs, 1, f)
|
table.insert(self.extra_exit_funcs, 1, f)
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameEvent:findParent(eventType, includeSelf)
|
-- 找第一个与当前事件有继承关系的特定事件
|
||||||
|
---@param eventType integer @ 事件类型
|
||||||
|
---@param includeSelf bool @ 是否包括本事件
|
||||||
|
---@param depth? integer @ 搜索深度
|
||||||
|
---@return GameEvent?
|
||||||
|
function GameEvent:findParent(eventType, includeSelf, depth)
|
||||||
if includeSelf and self.event == eventType then return self end
|
if includeSelf and self.event == eventType then return self end
|
||||||
|
if depth == 0 then return nil end
|
||||||
local e = self.parent
|
local e = self.parent
|
||||||
|
local l = 1
|
||||||
while e do
|
while e do
|
||||||
if e.event == eventType then return e end
|
if e.event == eventType then return e end
|
||||||
|
if depth and l >= depth then break end
|
||||||
e = e.parent
|
e = e.parent
|
||||||
|
l = l + 1
|
||||||
end
|
end
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
-- 找n个id介于from和to之间的事件。
|
-- 找n个id介于from和to之间的事件。
|
||||||
|
---@param events GameEvent[] @ 事件数组
|
||||||
|
---@param from integer @ 起始id
|
||||||
|
---@param to integer @ 终止id
|
||||||
|
---@param n integer @ 最多找多少个
|
||||||
|
---@param func fun(e: GameEvent): boolean? @ 过滤用的函数
|
||||||
|
---@return GameEvent[] @ 找到的符合条件的所有事件,最多n个但不保证有n个
|
||||||
local function bin_search(events, from, to, n, func)
|
local function bin_search(events, from, to, n, func)
|
||||||
local left = 1
|
local left = 1
|
||||||
local right = #events
|
local right = #events
|
||||||
|
|
|
@ -447,6 +447,10 @@ function GameLogic:start()
|
||||||
end
|
end
|
||||||
|
|
||||||
if not e then -- 没有事件,按理说不应该,平局处理
|
if not e then -- 没有事件,按理说不应该,平局处理
|
||||||
|
self.room:sendLog{
|
||||||
|
type = "#NoEventDraw",
|
||||||
|
toast = true,
|
||||||
|
}
|
||||||
self.room:gameOver("")
|
self.room:gameOver("")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -744,6 +748,21 @@ function GameLogic:getActualDamageEvents(n, func, scope, end_id)
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--检测最近的伤害事件是否由执行牌的效果触发,即通常描述的使用牌对目标角色造成伤害
|
||||||
|
---@param is_exact? bool @ 是否进一步判定使用者和来源是否一致(默认为true)
|
||||||
|
---@return bool
|
||||||
|
function GameLogic:damageByCardEffect(is_exact)
|
||||||
|
is_exact = (is_exact == nil) and true or is_exact
|
||||||
|
local d_event = self:getCurrentEvent():findParent(GameEvent.Damage, true)
|
||||||
|
if d_event == nil then return false end
|
||||||
|
local damage = d_event.data[1]
|
||||||
|
if damage.chain or damage.card == nil then return false end
|
||||||
|
local c_event = d_event:findParent(GameEvent.CardEffect, false, 2)
|
||||||
|
if c_event == nil then return false end
|
||||||
|
return damage.card == c_event.data[1].card and
|
||||||
|
(not is_exact or d_event.data[1].from.id == c_event.data[1].from)
|
||||||
|
end
|
||||||
|
|
||||||
function GameLogic:dumpEventStack(detailed)
|
function GameLogic:dumpEventStack(detailed)
|
||||||
local top = self:getCurrentEvent()
|
local top = self:getCurrentEvent()
|
||||||
local i = self.game_event_stack.p
|
local i = self.game_event_stack.p
|
||||||
|
|
|
@ -56,6 +56,7 @@ dofile "lua/server/ai/init.lua"
|
||||||
gameevent.lua (游戏事件的执行逻辑,以及各种事件的执行方法)
|
gameevent.lua (游戏事件的执行逻辑,以及各种事件的执行方法)
|
||||||
game_rule.lua (基础游戏规则,包括执行阶段、决胜负等)
|
game_rule.lua (基础游戏规则,包括执行阶段、决胜负等)
|
||||||
aux_skills.lua (某些交互方法是套壳askForUseActiveSkill,就是在这定义的)
|
aux_skills.lua (某些交互方法是套壳askForUseActiveSkill,就是在这定义的)
|
||||||
|
aux_poxi.lua (有了Poxi之后,一些交互方法改成了以各种PoxiMethod为基础的交互)
|
||||||
]]----------------------------------------------------------------------
|
]]----------------------------------------------------------------------
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
@ -431,6 +432,10 @@ function Room:getNCards(num, from)
|
||||||
if #self.draw_pile < num then
|
if #self.draw_pile < num then
|
||||||
self:shuffleDrawPile()
|
self:shuffleDrawPile()
|
||||||
if #self.draw_pile < num then
|
if #self.draw_pile < num then
|
||||||
|
self:sendLog{
|
||||||
|
type = "#NoCardDraw",
|
||||||
|
toast = true,
|
||||||
|
}
|
||||||
self:gameOver("")
|
self:gameOver("")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -605,14 +610,16 @@ function Room:changeHero(player, new_general, full, isDeputy, sendLog, maxHpChan
|
||||||
|
|
||||||
kingdomChange = (kingdomChange == nil) and true or kingdomChange
|
kingdomChange = (kingdomChange == nil) and true or kingdomChange
|
||||||
local kingdom = (isDeputy or not kingdomChange) and player.kingdom or new.kingdom
|
local kingdom = (isDeputy or not kingdomChange) and player.kingdom or new.kingdom
|
||||||
if not isDeputy and kingdomChange and (new.kingdom == "god" or new.subkingdom) then
|
if not isDeputy and kingdomChange then
|
||||||
local allKingdoms = {}
|
local allKingdoms = {}
|
||||||
if new.kingdom == "god" then
|
if new.subkingdom then
|
||||||
allKingdoms = table.filter({"wei", "shu", "wu", "qun", "jin"}, function(k) return table.contains(Fk.kingdoms, k) end)
|
|
||||||
elseif new.subkingdom then
|
|
||||||
allKingdoms = { new.kingdom, new.subkingdom }
|
allKingdoms = { new.kingdom, new.subkingdom }
|
||||||
|
else
|
||||||
|
allKingdoms = Fk:getKingdomMap(new.kingdom)
|
||||||
|
end
|
||||||
|
if #allKingdoms > 0 then
|
||||||
|
kingdom = self:askForChoice(player, allKingdoms, "AskForKingdom", "#ChooseInitialKingdom")
|
||||||
end
|
end
|
||||||
kingdom = self:askForChoice(player, allKingdoms, "AskForKingdom", "#ChooseInitialKingdom")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
execGameEvent(GameEvent.ChangeProperty,
|
execGameEvent(GameEvent.ChangeProperty,
|
||||||
|
@ -1372,10 +1379,10 @@ function Room:askForChooseCardsAndPlayers(player, minCardNum, maxCardNum, target
|
||||||
|
|
||||||
local data = {
|
local data = {
|
||||||
targets = targets,
|
targets = targets,
|
||||||
max_target_num = maxTargetNum,
|
max_t_num = maxTargetNum,
|
||||||
min_target_num = minTargetNum,
|
min_t_num = minTargetNum,
|
||||||
max_card_num = maxCardNum,
|
max_c_num = maxCardNum,
|
||||||
min_card_num = minCardNum,
|
min_c_num = minCardNum,
|
||||||
pattern = pattern,
|
pattern = pattern,
|
||||||
skillName = skillName,
|
skillName = skillName,
|
||||||
-- include_equip = includeEquip, -- FIXME: 预定一个破坏性更新
|
-- include_equip = includeEquip, -- FIXME: 预定一个破坏性更新
|
||||||
|
@ -1501,6 +1508,10 @@ function Room:getNGenerals(n, position)
|
||||||
end
|
end
|
||||||
|
|
||||||
if #generals < 1 then
|
if #generals < 1 then
|
||||||
|
self:sendLog{
|
||||||
|
type = "#NoGeneralDraw",
|
||||||
|
toast = true,
|
||||||
|
}
|
||||||
self:gameOver("")
|
self:gameOver("")
|
||||||
end
|
end
|
||||||
return generals
|
return generals
|
||||||
|
@ -1594,24 +1605,25 @@ end
|
||||||
function Room:askForChooseKingdom(players)
|
function Room:askForChooseKingdom(players)
|
||||||
players = players or self.alive_players
|
players = players or self.alive_players
|
||||||
local specialKingdomPlayers = table.filter(players, function(p)
|
local specialKingdomPlayers = table.filter(players, function(p)
|
||||||
return p.kingdom == "god" or Fk.generals[p.general].subkingdom
|
return Fk.generals[p.general].subkingdom or #Fk:getKingdomMap(p.kingdom) > 0
|
||||||
end)
|
end)
|
||||||
|
|
||||||
if #specialKingdomPlayers > 0 then
|
if #specialKingdomPlayers > 0 then
|
||||||
local choiceMap = {}
|
local choiceMap = {}
|
||||||
for _, p in ipairs(specialKingdomPlayers) do
|
for _, p in ipairs(specialKingdomPlayers) do
|
||||||
local allKingdoms = {}
|
local allKingdoms = {}
|
||||||
if p.kingdom == "god" then
|
local curGeneral = Fk.generals[p.general]
|
||||||
allKingdoms = table.filter({"wei", "shu", "wu", "qun", "jin"}, function(k) return table.contains(Fk.kingdoms, k) end)
|
if curGeneral.subkingdom then
|
||||||
else
|
|
||||||
local curGeneral = Fk.generals[p.general]
|
|
||||||
allKingdoms = { curGeneral.kingdom, curGeneral.subkingdom }
|
allKingdoms = { curGeneral.kingdom, curGeneral.subkingdom }
|
||||||
|
else
|
||||||
|
allKingdoms = Fk:getKingdomMap(p.kingdom)
|
||||||
end
|
end
|
||||||
|
if #allKingdoms > 0 then
|
||||||
|
choiceMap[p.id] = allKingdoms
|
||||||
|
|
||||||
choiceMap[p.id] = allKingdoms
|
local data = json.encode({ allKingdoms, allKingdoms, "AskForKingdom", "#ChooseInitialKingdom" })
|
||||||
|
p.request_data = data
|
||||||
local data = json.encode({ allKingdoms, allKingdoms, "AskForKingdom", "#ChooseInitialKingdom" })
|
end
|
||||||
p.request_data = data
|
|
||||||
end
|
end
|
||||||
|
|
||||||
self:notifyMoveFocus(players, "AskForKingdom")
|
self:notifyMoveFocus(players, "AskForKingdom")
|
||||||
|
@ -1674,57 +1686,6 @@ function Room:askForCardChosen(chooser, target, flag, reason, prompt)
|
||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
--- 完全类似askForCardChosen,但是可以选择多张牌。
|
|
||||||
--- 相应的,返回的是id的数组而不是单个id。
|
|
||||||
---@param chooser ServerPlayer @ 要被询问的人
|
|
||||||
---@param target ServerPlayer @ 被选牌的人
|
|
||||||
---@param min integer @ 最小选牌数
|
|
||||||
---@param max integer @ 最大选牌数
|
|
||||||
---@param flag any @ 用"hej"三个字母的组合表示能选择哪些区域, h 手牌区, e - 装备区, j - 判定区
|
|
||||||
---@param reason string @ 原因,一般是技能名
|
|
||||||
---@param prompt? string @ 提示信息
|
|
||||||
---@return integer[] @ 选择的id
|
|
||||||
function Room:askForCardsChosen(chooser, target, min, max, flag, reason, prompt)
|
|
||||||
if min == 1 and max == 1 then
|
|
||||||
return { self:askForCardChosen(chooser, target, flag, reason) }
|
|
||||||
end
|
|
||||||
|
|
||||||
local command = "AskForCardsChosen"
|
|
||||||
prompt = prompt or ""
|
|
||||||
self:notifyMoveFocus(chooser, command)
|
|
||||||
local data = {target.id, min, max, flag, reason, prompt}
|
|
||||||
local result = self:doRequest(chooser, command, json.encode(data))
|
|
||||||
|
|
||||||
local ret
|
|
||||||
if result ~= "" then
|
|
||||||
ret = json.decode(result)
|
|
||||||
else
|
|
||||||
local areas = {}
|
|
||||||
local handcards
|
|
||||||
if type(flag) == "string" then
|
|
||||||
if string.find(flag, "h") then table.insert(areas, Player.Hand) end
|
|
||||||
if string.find(flag, "e") then table.insert(areas, Player.Equip) end
|
|
||||||
if string.find(flag, "j") then table.insert(areas, Player.Judge) end
|
|
||||||
handcards = target:getCardIds(areas)
|
|
||||||
else
|
|
||||||
handcards = {}
|
|
||||||
for _, t in ipairs(flag.card_data) do
|
|
||||||
table.insertTable(handcards, t[2])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if #handcards == 0 then return {} end
|
|
||||||
ret = table.random(handcards, math.min(min, #handcards))
|
|
||||||
end
|
|
||||||
|
|
||||||
local new_ret = table.filter(ret, function(id) return id ~= -1 end)
|
|
||||||
local hand_num = #ret - #new_ret
|
|
||||||
if hand_num > 0 then
|
|
||||||
table.insertTable(new_ret, table.random(target:getCardIds(Player.Hand), hand_num))
|
|
||||||
end
|
|
||||||
|
|
||||||
return new_ret
|
|
||||||
end
|
|
||||||
|
|
||||||
--- 谋askForCardsChosen,需使用Fk:addPoxiMethod定义好方法
|
--- 谋askForCardsChosen,需使用Fk:addPoxiMethod定义好方法
|
||||||
---
|
---
|
||||||
--- 选卡规则和返回值啥的全部自己想办法解决,data填入所有卡的列表(类似ui.card_data)
|
--- 选卡规则和返回值啥的全部自己想办法解决,data填入所有卡的列表(类似ui.card_data)
|
||||||
|
@ -1756,6 +1717,103 @@ function Room:askForPoxi(player, poxi_type, data, extra_data, cancelable)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- 完全类似askForCardChosen,但是可以选择多张牌。
|
||||||
|
--- 相应的,返回的是id的数组而不是单个id。
|
||||||
|
---@param chooser ServerPlayer @ 要被询问的人
|
||||||
|
---@param target ServerPlayer @ 被选牌的人
|
||||||
|
---@param min integer @ 最小选牌数
|
||||||
|
---@param max integer @ 最大选牌数
|
||||||
|
---@param flag any @ 用"hej"三个字母的组合表示能选择哪些区域, h 手牌区, e - 装备区, j - 判定区
|
||||||
|
---可以通过flag.card_data = {{牌堆1名, 牌堆1ID表},...}来定制能选择的牌
|
||||||
|
---@param reason string @ 原因,一般是技能名
|
||||||
|
---@param prompt? string @ 提示信息
|
||||||
|
---@return integer[] @ 选择的id
|
||||||
|
function Room:askForCardsChosen(chooser, target, min, max, flag, reason, prompt)
|
||||||
|
if min == 1 and max == 1 then
|
||||||
|
return { self:askForCardChosen(chooser, target, flag, reason) }
|
||||||
|
end
|
||||||
|
|
||||||
|
-- local command = "AskForCardsChosen"
|
||||||
|
-- prompt = prompt or ""
|
||||||
|
-- self:notifyMoveFocus(chooser, command)
|
||||||
|
-- local data = {target.id, min, max, flag, reason, prompt}
|
||||||
|
-- local result = self:doRequest(chooser, command, json.encode(data))
|
||||||
|
|
||||||
|
-- local ret
|
||||||
|
-- if result ~= "" then
|
||||||
|
-- ret = json.decode(result)
|
||||||
|
-- else
|
||||||
|
-- local areas = {}
|
||||||
|
-- local handcards
|
||||||
|
-- if type(flag) == "string" then
|
||||||
|
-- if string.find(flag, "h") then table.insert(areas, Player.Hand) end
|
||||||
|
-- if string.find(flag, "e") then table.insert(areas, Player.Equip) end
|
||||||
|
-- if string.find(flag, "j") then table.insert(areas, Player.Judge) end
|
||||||
|
-- handcards = target:getCardIds(areas)
|
||||||
|
-- else
|
||||||
|
-- handcards = {}
|
||||||
|
-- for _, t in ipairs(flag.card_data) do
|
||||||
|
-- table.insertTable(handcards, t[2])
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
-- if #handcards == 0 then return {} end
|
||||||
|
-- ret = table.random(handcards, math.min(min, #handcards))
|
||||||
|
-- end
|
||||||
|
|
||||||
|
-- local new_ret = table.filter(ret, function(id) return id ~= -1 end)
|
||||||
|
-- local hand_num = #ret - #new_ret
|
||||||
|
-- if hand_num > 0 then
|
||||||
|
-- table.insertTable(new_ret, table.random(target:getCardIds(Player.Hand), hand_num))
|
||||||
|
-- end
|
||||||
|
|
||||||
|
-- return new_ret
|
||||||
|
local areas = {}
|
||||||
|
local cards
|
||||||
|
local data = {
|
||||||
|
to = target.id,
|
||||||
|
min = min,
|
||||||
|
max = max,
|
||||||
|
skillName = reason,
|
||||||
|
prompt = prompt,
|
||||||
|
}
|
||||||
|
if type(flag) == "string" then
|
||||||
|
if string.find(flag, "h") then table.insert(areas, Player.Hand) end
|
||||||
|
if string.find(flag, "e") then table.insert(areas, Player.Equip) end
|
||||||
|
if string.find(flag, "j") then table.insert(areas, Player.Judge) end
|
||||||
|
cards = target:getCardIds(areas)
|
||||||
|
else
|
||||||
|
cards = {}
|
||||||
|
for _, t in ipairs(flag.card_data) do
|
||||||
|
table.insertTable(cards, t[2])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #cards <= min then return table.random(cards, math.min(min, #cards)) end
|
||||||
|
local cards_data = {}
|
||||||
|
if type(flag) == "string" then
|
||||||
|
if string.find(flag, "h") and #target:getCardIds(Player.Hand) > 0 then
|
||||||
|
local handcards = {}
|
||||||
|
for _, _ in ipairs(target:getCardIds(Player.Hand)) do
|
||||||
|
table.insert(handcards, -1)
|
||||||
|
end
|
||||||
|
table.insert(cards_data, {"$Hand", handcards})
|
||||||
|
end
|
||||||
|
if string.find(flag, "e") and #target:getCardIds(Player.Equip) > 0 then table.insert(cards_data, {"$Equip", target:getCardIds(Player.Equip)}) end
|
||||||
|
if string.find(flag, "j") and #target:getCardIds(Player.Judge) > 0 then table.insert(cards_data, {"$Judge", target:getCardIds(Player.Judge)}) end
|
||||||
|
local ret = self:askForPoxi(chooser, "AskForCardsChosen", cards_data, data, false)
|
||||||
|
local new_ret = table.filter(ret, function(id) return id ~= -1 end)
|
||||||
|
local hidden_num = #ret - #new_ret
|
||||||
|
if hidden_num > 0 then
|
||||||
|
table.insertTable(new_ret, table.random(target:getCardIds(Player.Hand), hidden_num))
|
||||||
|
end
|
||||||
|
return new_ret
|
||||||
|
else
|
||||||
|
for _, t in ipairs(flag.card_data) do
|
||||||
|
table.insert(cards_data, t)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return self:askForPoxi(chooser, "AskForCardsChosen", cards_data, data, false)
|
||||||
|
end
|
||||||
|
|
||||||
--- 询问一名玩家从众多选项中选择一个。
|
--- 询问一名玩家从众多选项中选择一个。
|
||||||
---@param player ServerPlayer @ 要询问的玩家
|
---@param player ServerPlayer @ 要询问的玩家
|
||||||
---@param choices string[] @ 可选选项列表
|
---@param choices string[] @ 可选选项列表
|
||||||
|
@ -3027,7 +3085,7 @@ end
|
||||||
function Room:obtainCard(player, cid, unhide, reason, proposer)
|
function Room:obtainCard(player, cid, unhide, reason, proposer)
|
||||||
if type(cid) ~= "number" then
|
if type(cid) ~= "number" then
|
||||||
assert(cid and type(cid) == "table")
|
assert(cid and type(cid) == "table")
|
||||||
if cid:isInstanceOf(Card) then
|
if cid[1] == nil then
|
||||||
cid = cid:isVirtual() and cid.subcards or {cid.id}
|
cid = cid:isVirtual() and cid.subcards or {cid.id}
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
|
|
@ -114,7 +114,7 @@ local analepticSkill = fk.CreateActiveSkill{
|
||||||
end)
|
end)
|
||||||
end,
|
end,
|
||||||
can_use = function(self, player, card, extra_data)
|
can_use = function(self, player, card, extra_data)
|
||||||
return ((extra_data and (extra_data.bypass_times or extra_data.analepticRecover)) or
|
return not player:isProhibited(player, card) and ((extra_data and (extra_data.bypass_times or extra_data.analepticRecover)) or
|
||||||
self:withinTimesLimit(player, Player.HistoryTurn, card, "analeptic", player))
|
self:withinTimesLimit(player, Player.HistoryTurn, card, "analeptic", player))
|
||||||
end,
|
end,
|
||||||
on_use = function(_, _, use)
|
on_use = function(_, _, use)
|
||||||
|
@ -333,9 +333,17 @@ local gudingSkill = fk.CreateTriggerSkill{
|
||||||
frequency = Skill.Compulsory,
|
frequency = Skill.Compulsory,
|
||||||
events = {fk.DamageCaused},
|
events = {fk.DamageCaused},
|
||||||
can_trigger = function(self, _, target, player, data)
|
can_trigger = function(self, _, target, player, data)
|
||||||
return target == player and player:hasSkill(self) and
|
local logic = player.room.logic
|
||||||
data.to:isKongcheng() and data.card and data.card.trueName == "slash" and
|
if target == player and player:hasSkill(self) and
|
||||||
not data.chain
|
data.to:isKongcheng() and data.card and data.card.trueName == "slash" and not data.chain then
|
||||||
|
local event = logic:getCurrentEvent()
|
||||||
|
if event == nil then return false end
|
||||||
|
event = event.parent
|
||||||
|
if event == nil or event.event ~= GameEvent.SkillEffect then return false end
|
||||||
|
event = event.parent
|
||||||
|
if event == nil or event.event ~= GameEvent.CardEffect then return false end
|
||||||
|
return data.card == event.data[1].card and data.from.id == event.data[1].from
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
on_use = function(_, _, _, _, data)
|
on_use = function(_, _, _, _, data)
|
||||||
data.damage = data.damage + 1
|
data.damage = data.damage + 1
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
-- SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
Fk:addPoxiMethod{
|
||||||
|
name = "AskForCardsChosen",
|
||||||
|
card_filter = function(to_select, selected, data, extra_data)
|
||||||
|
return #selected < extra_data.max
|
||||||
|
end,
|
||||||
|
feasible = function(selected, data, extra_data)
|
||||||
|
return #selected >= extra_data.min and #selected <= extra_data.max
|
||||||
|
end,
|
||||||
|
prompt = function(data, extra_data)
|
||||||
|
if extra_data.prompt then
|
||||||
|
return extra_data.prompt
|
||||||
|
else
|
||||||
|
local ret = Fk:translate("#AskForChooseCards")
|
||||||
|
ret = ret:gsub("%%1", Fk:translate(extra_data.skillName or "AskForCardsChosen"))
|
||||||
|
ret = ret:gsub("%%2", Fk:translate(extra_data.min))
|
||||||
|
ret = ret:gsub("%%3", Fk:translate(extra_data.max))
|
||||||
|
return ret .. ":" ..extra_data.to
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
}
|
|
@ -95,7 +95,7 @@ local choosePlayersSkill = fk.CreateActiveSkill{
|
||||||
local exChooseSkill = fk.CreateActiveSkill{
|
local exChooseSkill = fk.CreateActiveSkill{
|
||||||
name = "ex__choose_skill",
|
name = "ex__choose_skill",
|
||||||
card_filter = function(self, to_select, selected)
|
card_filter = function(self, to_select, selected)
|
||||||
if #selected >= self.max_card_num then return false end
|
if #selected >= self.max_c_num then return false end
|
||||||
|
|
||||||
if Fk:currentRoom():getCardArea(to_select) == Card.PlayerSpecial then
|
if Fk:currentRoom():getCardArea(to_select) == Card.PlayerSpecial then
|
||||||
if not string.find(self.pattern or "", self.expand_pile or "") then return false end
|
if not string.find(self.pattern or "", self.expand_pile or "") then return false end
|
||||||
|
@ -114,11 +114,15 @@ local exChooseSkill = fk.CreateActiveSkill{
|
||||||
return checkpoint
|
return checkpoint
|
||||||
end,
|
end,
|
||||||
target_filter = function(self, to_select, selected, cards)
|
target_filter = function(self, to_select, selected, cards)
|
||||||
if self.pattern ~= "" and #cards < self.min_card_num then return end
|
if #cards < self.min_c_num then return end
|
||||||
if #selected < self.max_target_num then
|
if #selected < self.max_t_num then
|
||||||
return table.contains(self.targets, to_select)
|
return table.contains(self.targets, to_select)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
min_target_num = function(self) return self.min_t_num end,
|
||||||
|
max_target_num = function(self) return self.max_t_num end,
|
||||||
|
min_card_num = function(self) return self.min_c_num end,
|
||||||
|
max_card_num = function(self) return self.max_c_num end,
|
||||||
}
|
}
|
||||||
|
|
||||||
local maxCardsSkill = fk.CreateMaxCardsSkill{
|
local maxCardsSkill = fk.CreateMaxCardsSkill{
|
||||||
|
|
|
@ -4,6 +4,7 @@ local extension = Package:new("standard")
|
||||||
extension.metadata = require "packages.standard.metadata"
|
extension.metadata = require "packages.standard.metadata"
|
||||||
dofile "packages/standard/game_rule.lua"
|
dofile "packages/standard/game_rule.lua"
|
||||||
dofile "packages/standard/aux_skills.lua"
|
dofile "packages/standard/aux_skills.lua"
|
||||||
|
dofile "packages/standard/aux_poxi.lua"
|
||||||
|
|
||||||
local jianxiong = fk.CreateTriggerSkill{
|
local jianxiong = fk.CreateTriggerSkill{
|
||||||
name = "jianxiong",
|
name = "jianxiong",
|
||||||
|
@ -699,29 +700,26 @@ local keji = fk.CreateTriggerSkill{
|
||||||
can_trigger = function(self, event, target, player, data)
|
can_trigger = function(self, event, target, player, data)
|
||||||
if target == player and player:hasSkill(self) and data.to == Player.Discard then
|
if target == player and player:hasSkill(self) and data.to == Player.Discard then
|
||||||
local room = player.room
|
local room = player.room
|
||||||
local logic = room.logic
|
local play_ids = {}
|
||||||
local e = logic:getCurrentEvent():findParent(GameEvent.Turn, true)
|
player.room.logic:getEventsOfScope(GameEvent.Phase, 1, function (e)
|
||||||
if e == nil then return false end
|
if e.data[2] == Player.Play and e.end_id then
|
||||||
local end_id = e.id
|
table.insert(play_ids, {e.id, e.end_id})
|
||||||
local events = logic.event_recorder[GameEvent.UseCard] or Util.DummyTable
|
|
||||||
for i = #events, 1, -1 do
|
|
||||||
e = events[i]
|
|
||||||
if e.id <= end_id then break end
|
|
||||||
local use = e.data[1]
|
|
||||||
if use.from == player.id and use.card.trueName == "slash" then
|
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
end
|
return false
|
||||||
events = logic.event_recorder[GameEvent.RespondCard] or Util.DummyTable
|
end, Player.HistoryTurn)
|
||||||
for i = #events, 1, -1 do
|
if #play_ids == 0 then return true end
|
||||||
e = events[i]
|
local function PlayCheck (e)
|
||||||
if e.id <= end_id then break end
|
local in_play = false
|
||||||
local resp = e.data[1]
|
for _, ids in ipairs(play_ids) do
|
||||||
if resp.from == player.id and resp.card.trueName == "slash" then
|
if e.id > ids[1] and e.id < ids[2] then
|
||||||
return false
|
in_play = true
|
||||||
|
break
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
return in_play and e.data[1].from == player.id and e.data[1].card.trueName == "slash"
|
||||||
end
|
end
|
||||||
return true
|
return #player.room.logic:getEventsOfScope(GameEvent.UseCard, 1, PlayCheck, Player.HistoryTurn) == 0
|
||||||
|
and #player.room.logic:getEventsOfScope(GameEvent.RespondCard, 1, PlayCheck, Player.HistoryTurn) == 0
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
on_use = function(self, event, target, player, data)
|
on_use = function(self, event, target, player, data)
|
||||||
|
@ -989,9 +987,10 @@ local qingnang = fk.CreateActiveSkill{
|
||||||
on_use = function(self, room, effect)
|
on_use = function(self, room, effect)
|
||||||
local from = room:getPlayerById(effect.from)
|
local from = room:getPlayerById(effect.from)
|
||||||
room:throwCard(effect.cards, self.name, from, from)
|
room:throwCard(effect.cards, self.name, from, from)
|
||||||
if from:isAlive() and from:isWounded() then
|
local to = room:getPlayerById(effect.tos[1])
|
||||||
|
if to:isAlive() and to:isWounded() then
|
||||||
room:recover({
|
room:recover({
|
||||||
who = room:getPlayerById(effect.tos[1]),
|
who = to,
|
||||||
num = 1,
|
num = 1,
|
||||||
recoverBy = from,
|
recoverBy = from,
|
||||||
skillName = self.name
|
skillName = self.name
|
||||||
|
@ -1117,12 +1116,20 @@ local role_getlogic = function()
|
||||||
|
|
||||||
if lord ~= nil then
|
if lord ~= nil then
|
||||||
room.current = lord
|
room.current = lord
|
||||||
|
local a1 = #room.general_pile
|
||||||
|
local a2 = #room.players * generalNum + lord_num
|
||||||
|
if a1 < a2 then
|
||||||
|
room:sendLog{
|
||||||
|
type = "#NoEnoughGeneralDraw",
|
||||||
|
arg = a1,
|
||||||
|
arg2 = a2,
|
||||||
|
toast = true,
|
||||||
|
}
|
||||||
|
room:gameOver("")
|
||||||
|
end
|
||||||
local generals = table.connect(room:findGenerals(function(g)
|
local generals = table.connect(room:findGenerals(function(g)
|
||||||
return table.find(Fk.generals[g].skills, function(s) return s.lordSkill end)
|
return table.find(Fk.generals[g].skills, function(s) return s.lordSkill end)
|
||||||
end, lord_num), room:getNGenerals(generalNum))
|
end, lord_num), room:getNGenerals(generalNum))
|
||||||
if #room.general_pile < (#room.players - 1) * generalNum then
|
|
||||||
room:gameOver("")
|
|
||||||
end
|
|
||||||
lord_generals = room:askForGeneral(lord, generals, n)
|
lord_generals = room:askForGeneral(lord, generals, n)
|
||||||
local lord_general, deputy
|
local lord_general, deputy
|
||||||
if type(lord_generals) == "table" then
|
if type(lord_generals) == "table" then
|
||||||
|
|
|
@ -1086,7 +1086,7 @@ local halberdSkill = fk.CreateTargetModSkill{
|
||||||
if player:hasSkill(self) and skill.trueName == "slash_skill" then
|
if player:hasSkill(self) and skill.trueName == "slash_skill" then
|
||||||
local cards = card:isVirtual() and card.subcards or {card.id}
|
local cards = card:isVirtual() and card.subcards or {card.id}
|
||||||
local handcards = player:getCardIds(Player.Hand)
|
local handcards = player:getCardIds(Player.Hand)
|
||||||
if #cards == #handcards and table.every(cards, function(id) return table.contains(handcards, id) end) then
|
if #handcards > 0 and #cards == #handcards and table.every(cards, function(id) return table.contains(handcards, id) end) then
|
||||||
return 2
|
return 2
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -83,6 +83,7 @@ local control = fk.CreateActiveSkill{
|
||||||
-- p(room:askForYiji(from, from:getCardIds(Player.Hand), table.map(effect.tos, Util.Id2PlayerMapper), self.name, 2, 10, nil, false, nil, false, 3, true))
|
-- p(room:askForYiji(from, from:getCardIds(Player.Hand), table.map(effect.tos, Util.Id2PlayerMapper), self.name, 2, 10, nil, false, nil, false, 3, true))
|
||||||
for _, pid in ipairs(effect.tos) do
|
for _, pid in ipairs(effect.tos) do
|
||||||
local to = room:getPlayerById(pid)
|
local to = room:getPlayerById(pid)
|
||||||
|
-- p(room:askForCardsChosen(from, to, 2, 3, "hej", self.name))
|
||||||
-- p(room:askForPoxi(from, "test", {
|
-- p(room:askForPoxi(from, "test", {
|
||||||
-- { "你自己", from:getCardIds "h" },
|
-- { "你自己", from:getCardIds "h" },
|
||||||
-- { "对方", to:getCardIds "h" },
|
-- { "对方", to:getCardIds "h" },
|
||||||
|
|
Loading…
Reference in New Issue