Skip nullification (#227)
- 完善移动场上一张牌移动虚拟牌及选框中显示逻辑,并增加排除特定卡牌id的参数; - 多目标锦囊牌询问无懈时新增“本轮忽略”功能; - 修复传导伤害额外传导自身的问题。
This commit is contained in:
parent
acda9f4eb8
commit
8ca9f9154c
|
@ -42,6 +42,7 @@ Item {
|
|||
property bool respond_play: false
|
||||
property bool autoPending: false
|
||||
property var extra_data: ({})
|
||||
property var skippedUseEventId: []
|
||||
|
||||
Image {
|
||||
source: config.roomBg
|
||||
|
@ -571,6 +572,16 @@ Item {
|
|||
spacing: 20
|
||||
visible: false
|
||||
|
||||
Button {
|
||||
id: skipNullificationButton
|
||||
text: Backend.translate("SkipNullification")
|
||||
visible: !!extra_data.useEventId && !skippedUseEventId.find(id => id === extra_data.useEventId)
|
||||
onClicked: {
|
||||
skippedUseEventId.push(extra_data.useEventId);
|
||||
Logic.doCancelButton();
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: okButton
|
||||
text: Backend.translate("OK")
|
||||
|
|
|
@ -999,20 +999,22 @@ callbacks["AskForCardsChosen"] = (jsonData) => {
|
|||
|
||||
callbacks["AskForMoveCardInBoard"] = (jsonData) => {
|
||||
const data = JSON.parse(jsonData);
|
||||
const { cards, cardsPosition, generalNames } = data;
|
||||
const { cards, cardsPosition, generalNames, playerIds } = data;
|
||||
|
||||
roomScene.state = "replying";
|
||||
roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/MoveCardInBoardBox.qml");
|
||||
|
||||
const boxCards = [];
|
||||
cards.forEach(id => {
|
||||
const d = Backend.callLuaFunction("GetCardData", [id]);
|
||||
const cardPos = cardsPosition[cards.findIndex(cid => cid === id)];
|
||||
const d = Backend.callLuaFunction("GetCardData", [id, playerIds[cardPos]]);
|
||||
boxCards.push(JSON.parse(d));
|
||||
});
|
||||
|
||||
const box = roomScene.popupBox.item;
|
||||
box.cards = boxCards;
|
||||
box.cardsPosition = cardsPosition;
|
||||
box.playerIds = playerIds;
|
||||
box.generalNames = generalNames.map(name => {
|
||||
const namesSplited = name.split('/');
|
||||
return namesSplited.length > 1 ? namesSplited.map(nameSplited => Backend.translate(nameSplited)).join('/') : Backend.translate(name)
|
||||
|
@ -1127,7 +1129,13 @@ callbacks["AskForUseCard"] = (jsonData) => {
|
|||
const prompt = data[2];
|
||||
const extra_data = data[4];
|
||||
if (extra_data != null) {
|
||||
roomScene.extra_data = extra_data;
|
||||
if (extra_data.effectTo !== Self.id && roomScene.skippedUseEventId.find(id => id === extra_data.useEventId)) {
|
||||
doCancelButton();
|
||||
return;
|
||||
} else {
|
||||
console.log(extra_data);
|
||||
roomScene.extra_data = extra_data;
|
||||
}
|
||||
}
|
||||
|
||||
if (prompt === "") {
|
||||
|
|
|
@ -9,6 +9,7 @@ GraphicsBox {
|
|||
property var cards: []
|
||||
property var cardsPosition: []
|
||||
property var generalNames: []
|
||||
property var playerIds: []
|
||||
property var result
|
||||
property int padding: 25
|
||||
|
||||
|
@ -64,7 +65,7 @@ GraphicsBox {
|
|||
Text {
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
anchors.centerIn: parent
|
||||
text: Backend.translate(JSON.parse(Backend.callLuaFunction("GetCardData", [modelData.cid])).subtype)
|
||||
text: Backend.translate(modelData.subtype)
|
||||
color: "#90765F"
|
||||
font.family: fontLibian.name
|
||||
font.pixelSize: 16
|
||||
|
@ -100,6 +101,7 @@ GraphicsBox {
|
|||
name: modelData.name
|
||||
suit: modelData.suit
|
||||
number: modelData.number
|
||||
virt_name: modelData.virt_name || ''
|
||||
|
||||
selectable: !result || result.item === this
|
||||
onClicked: {
|
||||
|
|
|
@ -76,7 +76,7 @@ local cardSubtypeStrings = {
|
|||
[Card.SubtypeTreasure] = "treasure",
|
||||
}
|
||||
|
||||
function GetCardData(id)
|
||||
function GetCardData(id, virtualCardForm)
|
||||
local card = Fk:getCardById(id)
|
||||
if card == nil then return json.encode{
|
||||
cid = id,
|
||||
|
@ -106,6 +106,13 @@ function GetCardData(id)
|
|||
ret.name = orig.name
|
||||
ret.virt_name = card.name
|
||||
end
|
||||
if virtualCardForm then
|
||||
local virtualCard = ClientInstance:getPlayerById(virtualCardForm):getVirualEquip(id)
|
||||
if virtualCard then
|
||||
ret.virt_name = virtualCard.name
|
||||
ret.subtype = cardSubtypeStrings[virtualCard.sub_type]
|
||||
end
|
||||
end
|
||||
return json.encode(ret)
|
||||
end
|
||||
|
||||
|
|
|
@ -137,6 +137,7 @@ FreeKill使用的是libgit2的C API,与此同时使用Git完成拓展包的下
|
|||
|
||||
["Exit Lobby"] = "退出大厅",
|
||||
|
||||
["SkipNullification"] = "本轮忽略",
|
||||
["OK"] = "确定",
|
||||
["Cancel"] = "取消",
|
||||
["End"] = "结束",
|
||||
|
|
|
@ -856,7 +856,7 @@ function Player:canMoveCardInBoardTo(to, id)
|
|||
return false
|
||||
end
|
||||
|
||||
local card = Fk:getCardById(id)
|
||||
local card = self:getVirualEquip(id) or Fk:getCardById(id)
|
||||
assert(card.type == Card.TypeEquip or card.sub_type == Card.SubtypeDelayedTrick)
|
||||
|
||||
if card.type == Card.TypeEquip then
|
||||
|
@ -868,12 +868,13 @@ function Player:canMoveCardInBoardTo(to, id)
|
|||
end
|
||||
end
|
||||
|
||||
function Player:canMoveCardsInBoardTo(to, flag)
|
||||
function Player:canMoveCardsInBoardTo(to, flag, excludeIds)
|
||||
if self == to then
|
||||
return false
|
||||
end
|
||||
|
||||
assert(flag == nil or flag == "e" or flag == "j")
|
||||
excludeIds = type(excludeIds) == "table" and excludeIds or {}
|
||||
|
||||
local areas = {}
|
||||
if flag == "e" then
|
||||
|
@ -885,7 +886,7 @@ function Player:canMoveCardsInBoardTo(to, flag)
|
|||
end
|
||||
|
||||
for _, cardId in ipairs(self:getCardIds(areas)) do
|
||||
if self:canMoveCardInBoardTo(to, cardId) then
|
||||
if not table.contains(excludeIds, cardId) and self:canMoveCardInBoardTo(to, cardId) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
|
|
@ -191,7 +191,7 @@ GameEvent.exit_funcs[GameEvent.Damage] = function(self)
|
|||
room.logic:trigger(fk.DamageFinished, damageStruct.to, damageStruct)
|
||||
|
||||
if damageStruct.beginnerOfTheDamage and not damageStruct.chain then
|
||||
local targets = table.filter(room:getAlivePlayers(), function(p)
|
||||
local targets = table.filter(room:getOtherPlayers(damageStruct.to), function(p)
|
||||
return p.chained
|
||||
end)
|
||||
for _, p in ipairs(targets) do
|
||||
|
@ -225,7 +225,7 @@ GameEvent.functions[GameEvent.LoseHp] = function(self)
|
|||
self.logic:breakEvent(false)
|
||||
end
|
||||
|
||||
if not self:changeHp(player, -num, "loseHp", skillName) then
|
||||
if not self:changeHp(player, -data.num, "loseHp", skillName) then
|
||||
self.logic:breakEvent(false)
|
||||
end
|
||||
|
||||
|
|
|
@ -62,12 +62,10 @@ GameEvent.functions[GameEvent.MoveCards] = function(self)
|
|||
for _, info in ipairs(data.moveInfo) do
|
||||
local realFromArea = self:getCardArea(info.cardId)
|
||||
local playerAreas = { Player.Hand, Player.Equip, Player.Judge, Player.Special }
|
||||
local virtualEquip
|
||||
|
||||
if table.contains(playerAreas, realFromArea) and data.from then
|
||||
local from = self:getPlayerById(data.from)
|
||||
from:removeCards(realFromArea, { info.cardId }, info.fromSpecialName)
|
||||
virtualEquip = from:getVirualEquip(info.cardId)
|
||||
|
||||
elseif realFromArea ~= Card.Unknown then
|
||||
local fromAreaIds = {}
|
||||
|
@ -86,7 +84,6 @@ GameEvent.functions[GameEvent.MoveCards] = function(self)
|
|||
|
||||
if table.contains(playerAreas, data.toArea) and data.to then
|
||||
local to = self:getPlayerById(data.to)
|
||||
if virtualEquip then to:addVirtualEquip(virtualEquip) end
|
||||
to:addCards(data.toArea, { info.cardId }, data.specialName)
|
||||
|
||||
else
|
||||
|
|
|
@ -790,6 +790,20 @@ function Room:notifyMoveCards(players, card_moves, forceVisible)
|
|||
return false
|
||||
end
|
||||
|
||||
for _, info in ipairs(move.moveInfo) do
|
||||
local realFromArea = self:getCardArea(info.cardId)
|
||||
local playerAreas = { Player.Hand, Player.Equip, Player.Judge, Player.Special }
|
||||
local virtualEquip
|
||||
|
||||
if table.contains(playerAreas, realFromArea) and move.from then
|
||||
virtualEquip = self:getPlayerById(move.from):getVirualEquip(info.cardId)
|
||||
end
|
||||
|
||||
if table.contains(playerAreas, move.toArea) and move.to and virtualEquip then
|
||||
self:getPlayerById(move.to):addVirtualEquip(virtualEquip)
|
||||
end
|
||||
end
|
||||
|
||||
-- forceVisible make the move visible
|
||||
-- FIXME: move.moveInfo is an array, fix this
|
||||
move.moveVisible = move.moveVisible or (forceVisible)
|
||||
|
@ -1840,26 +1854,29 @@ end
|
|||
---@param skillName string @ 技能名
|
||||
---@param flag string|null @ 限定可移动的区域,值为nil(装备区和判定区)、‘e’或‘j’
|
||||
---@param moveFrom ServerPlayer|null @ 是否只是目标1移动给目标2
|
||||
---@return table<"card"|"from"|"to"> @ 选择的卡牌、起点玩家id和终点玩家id列表
|
||||
function Room:askForMoveCardInBoard(player, targetOne, targetTwo, skillName, flag, moveFrom)
|
||||
---@param excludeIds CardId[]|null @ 本次不可移动的卡牌id
|
||||
---@return table<"card"|"from"|"to">|null @ 选择的卡牌、起点玩家id和终点玩家id列表
|
||||
function Room:askForMoveCardInBoard(player, targetOne, targetTwo, skillName, flag, moveFrom, excludeIds)
|
||||
if flag then
|
||||
assert(flag == "e" or flag == "j")
|
||||
end
|
||||
|
||||
excludeIds = type(excludeIds) == "table" and excludeIds or {}
|
||||
|
||||
local cards = {}
|
||||
local cardsPosition = {}
|
||||
|
||||
if not flag or flag == "e" then
|
||||
if not moveFrom or moveFrom == targetOne then
|
||||
for _, equipId in ipairs(targetOne:getCardIds(Player.Equip)) do
|
||||
if targetOne:canMoveCardInBoardTo(targetTwo, equipId) then
|
||||
if not table.contains(excludeIds, equipId) and targetOne:canMoveCardInBoardTo(targetTwo, equipId) then
|
||||
table.insert(cards, equipId)
|
||||
end
|
||||
end
|
||||
end
|
||||
if not moveFrom or moveFrom == targetTwo then
|
||||
for _, equipId in ipairs(targetTwo:getCardIds(Player.Equip)) do
|
||||
if targetTwo:canMoveCardInBoardTo(targetOne, equipId) then
|
||||
if not table.contains(excludeIds, equipId) and targetTwo:canMoveCardInBoardTo(targetOne, equipId) then
|
||||
table.insert(cards, equipId)
|
||||
end
|
||||
end
|
||||
|
@ -1882,7 +1899,7 @@ function Room:askForMoveCardInBoard(player, targetOne, targetTwo, skillName, fla
|
|||
if not flag or flag == "j" then
|
||||
if not moveFrom or moveFrom == targetOne then
|
||||
for _, trickId in ipairs(targetOne:getCardIds(Player.Judge)) do
|
||||
if targetOne:canMoveCardInBoardTo(targetTwo, trickId) then
|
||||
if not table.contains(excludeIds, trickId) and targetOne:canMoveCardInBoardTo(targetTwo, trickId) then
|
||||
table.insert(cards, trickId)
|
||||
table.insert(cardsPosition, 0)
|
||||
end
|
||||
|
@ -1890,7 +1907,7 @@ function Room:askForMoveCardInBoard(player, targetOne, targetTwo, skillName, fla
|
|||
end
|
||||
if not moveFrom or moveFrom == targetTwo then
|
||||
for _, trickId in ipairs(targetTwo:getCardIds(Player.Judge)) do
|
||||
if targetTwo:canMoveCardInBoardTo(targetOne, trickId) then
|
||||
if not table.contains(excludeIds, trickId) and targetTwo:canMoveCardInBoardTo(targetOne, trickId) then
|
||||
table.insert(cards, trickId)
|
||||
table.insert(cardsPosition, 1)
|
||||
end
|
||||
|
@ -1905,7 +1922,12 @@ function Room:askForMoveCardInBoard(player, targetOne, targetTwo, skillName, fla
|
|||
local firstGeneralName = targetOne.general + (targetOne.deputyGeneral ~= "" and ("/" .. targetOne.deputyGeneral) or "")
|
||||
local secGeneralName = targetTwo.general + (targetTwo.deputyGeneral ~= "" and ("/" .. targetTwo.deputyGeneral) or "")
|
||||
|
||||
local data = { cards = cards, cardsPosition = cardsPosition, generalNames = { firstGeneralName, secGeneralName } }
|
||||
local data = {
|
||||
cards = cards,
|
||||
cardsPosition = cardsPosition,
|
||||
generalNames = { firstGeneralName, secGeneralName },
|
||||
playerIds = { targetOne.id, targetTwo.id }
|
||||
}
|
||||
local command = "AskForMoveCardInBoard"
|
||||
self:notifyMoveFocus(player, command)
|
||||
local result = self:doRequest(player, command, json.encode(data))
|
||||
|
@ -1917,8 +1939,8 @@ function Room:askForMoveCardInBoard(player, targetOne, targetTwo, skillName, fla
|
|||
result = json.decode(result)
|
||||
end
|
||||
|
||||
local cardToMove = Fk:getCardById(result.cardId)
|
||||
local from, to = result.pos == 0 and targetOne, targetTwo or targetTwo, targetOne
|
||||
local cardToMove = self:getCardOwner(result.cardId):getVirualEquip(result.cardId) or Fk:getCardById(result.cardId)
|
||||
self:moveCardTo(
|
||||
cardToMove,
|
||||
cardToMove.type == Card.TypeEquip and Player.Equip or Player.Judge,
|
||||
|
@ -1940,16 +1962,18 @@ end
|
|||
---@param flag string|null @ 限定可移动的区域,值为nil(装备区和判定区)、‘e’或‘j’
|
||||
---@param no_indicate boolean|nil @ 是否不显示指示线
|
||||
---@return integer[] @ 选择的玩家id列表,可能为空
|
||||
function Room:askForChooseToMoveCardInBoard(player, prompt, skillName, cancelable, flag, no_indicate)
|
||||
function Room:askForChooseToMoveCardInBoard(player, prompt, skillName, cancelable, flag, no_indicate, excludeIds)
|
||||
if flag then
|
||||
assert(flag == "e" or flag == "j")
|
||||
end
|
||||
cancelable = (cancelable == nil) and true or cancelable
|
||||
no_indicate = (no_indicate == nil) and true or no_indicate
|
||||
excludeIds = type(excludeIds) == "table" and excludeIds or {}
|
||||
|
||||
local data = {
|
||||
flag = flag,
|
||||
skillName = skillName,
|
||||
excludeIds = excludeIds,
|
||||
}
|
||||
local _, ret = self:askForUseActiveSkill(
|
||||
player,
|
||||
|
@ -1966,7 +1990,7 @@ function Room:askForChooseToMoveCardInBoard(player, prompt, skillName, cancelabl
|
|||
if cancelable then
|
||||
return {}
|
||||
else
|
||||
return self:canMoveCardInBoard(flag)
|
||||
return self:canMoveCardInBoard(flag, excludeIds)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -2371,7 +2395,15 @@ function Room:handleCardEffect(event, cardEffectEvent)
|
|||
elseif cardEffectEvent.from then
|
||||
prompt = "#AskForNullificationWithoutTo:" .. cardEffectEvent.from .. "::" .. cardEffectEvent.card.name
|
||||
end
|
||||
local use = self:askForNullification(players, nil, nil, prompt)
|
||||
|
||||
local extra_data
|
||||
if #TargetGroup:getRealTargets(cardEffectEvent.tos) > 1 then
|
||||
local parentUseEvent = self.logic:getCurrentEvent():findParent(GameEvent.UseCard)
|
||||
if parentUseEvent then
|
||||
extra_data = { useEventId = parentUseEvent.id, effectTo = cardEffectEvent.to }
|
||||
end
|
||||
end
|
||||
local use = self:askForNullification(players, nil, nil, prompt, true, extra_data)
|
||||
if use then
|
||||
use.toCard = cardEffectEvent.card
|
||||
use.responseToEvent = cardEffectEvent
|
||||
|
@ -3062,18 +3094,20 @@ end
|
|||
|
||||
---@param flag string|null
|
||||
---@param players ServerPlayer[]|null
|
||||
---@param excludeIds CardId[]|null
|
||||
---@return PlayerId[] @ 可能为空
|
||||
function Room:canMoveCardInBoard(flag, players)
|
||||
function Room:canMoveCardInBoard(flag, players, excludeIds)
|
||||
if flag then
|
||||
assert(flag == "e" or flag == "j")
|
||||
end
|
||||
|
||||
players = players or self.alive_players
|
||||
excludeIds = type(excludeIds) == "table" and excludeIds or {}
|
||||
|
||||
local targets = {}
|
||||
table.find(players, function(p)
|
||||
local canMoveTo = table.find(players, function(another)
|
||||
return p ~= another and p:canMoveCardsInBoardTo(another, flag)
|
||||
return p ~= another and p:canMoveCardsInBoardTo(another, flag, excludeIds)
|
||||
end)
|
||||
|
||||
if canMoveTo then
|
||||
|
|
|
@ -99,10 +99,19 @@ local choosePlayersToMoveCardInBoardSkill = fk.CreateActiveSkill{
|
|||
target_filter = function(self, to_select, selected, cards)
|
||||
local target = Fk:currentRoom():getPlayerById(to_select)
|
||||
if #selected > 0 then
|
||||
return Fk:currentRoom():getPlayerById(selected[1]):canMoveCardsInBoardTo(target, self.flag)
|
||||
return Fk:currentRoom():getPlayerById(selected[1]):canMoveCardsInBoardTo(target, self.flag, self.excludeIds)
|
||||
end
|
||||
|
||||
return #target:getCardIds({ Player.Equip, Player.Judge }) > 0
|
||||
local fromAreas = { Player.Equip, Player.Judge }
|
||||
if self.flag == "e" then
|
||||
fromAreas = { Player.Equip }
|
||||
elseif self.flag == "j" then
|
||||
fromAreas = { Player.Judge }
|
||||
end
|
||||
|
||||
return #table.filter(target:getCardIds(fromAreas), function(id)
|
||||
return not table.contains((type(self.excludeIds) == "table" and self.excludeIds or {}), id)
|
||||
end) > 0
|
||||
end,
|
||||
}
|
||||
|
||||
|
|
|
@ -1092,8 +1092,22 @@ local role_mode = fk.CreateGameMode{
|
|||
roleTable = roleTable[#Fk:currentRoom().players]
|
||||
|
||||
if Self.role == "renegade" then
|
||||
roleCheck = #Fk:currentRoom().alive_players == 2
|
||||
roleText = "only you and me"
|
||||
local rebelNum = #table.filter(roleTable, function(role)
|
||||
return role == "rebel"
|
||||
end)
|
||||
|
||||
for _, p in ipairs(Fk:currentRoom().players) do
|
||||
if p.role == "rebel" then
|
||||
if not p.dead then
|
||||
break
|
||||
else
|
||||
rebelNum = rebelNum - 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
roleCheck = rebelNum == 0
|
||||
roleText = "left lord and loyalist alive"
|
||||
elseif Self.role == "rebel" then
|
||||
local rebelNum = #table.filter(roleTable, function(role)
|
||||
return role == "rebel"
|
||||
|
@ -1162,7 +1176,7 @@ local role_mode = fk.CreateGameMode{
|
|||
extension:addGameMode(role_mode)
|
||||
Fk:loadTranslationTable{
|
||||
["time limitation: 5 sec"] = "游戏时长达到5秒(测试用)",
|
||||
["only you and me"] = "仅剩你和主公存活",
|
||||
["left lord and loyalist alive"] = "仅剩你和主忠方存活",
|
||||
["left one rebel alive"] = "反贼仅剩你存活且不存在存活内奸",
|
||||
["left you alive"] = "主忠方仅剩你存活且其他阵营仅剩一方",
|
||||
["loyalist never surrender"] = "忠臣永不投降!",
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
|
@ -1,6 +1,7 @@
|
|||
-- SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
local extension = Package("test_p_0")
|
||||
extension.extensionName = "test"
|
||||
|
||||
local cheat = fk.CreateActiveSkill{
|
||||
name = "cheat",
|
||||
|
@ -270,6 +271,18 @@ test2:addSkill(damage_maker)
|
|||
test2:addSkill(change_hero)
|
||||
test2:addSkill(test_zhenggong)
|
||||
|
||||
local shibing = General(extension, "blank_shibing", "qun", 5)
|
||||
shibing.hidden = true
|
||||
Fk:loadTranslationTable{
|
||||
["blank_shibing"] = "男士兵",
|
||||
}
|
||||
|
||||
local nvshibing = General(extension, "blank_nvshibing", "qun", 5, 5, General.Female)
|
||||
Fk:loadTranslationTable{
|
||||
["blank_nvshibing"] = "女士兵",
|
||||
}
|
||||
nvshibing.hidden = true
|
||||
|
||||
Fk:loadTranslationTable{
|
||||
["test_p_0"] = "测试包",
|
||||
["test"] = "测试",
|
||||
|
|
Loading…
Reference in New Issue