Abort area (#249)

Co-authored-by: notify <notify-ctrl@qq.com>
This commit is contained in:
Ho-spair 2023-08-13 02:25:04 +08:00 committed by GitHub
parent 69137c9eba
commit 64127bffb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 350 additions and 71 deletions

View File

@ -15,7 +15,7 @@ QtObject {
property string roomBg property string roomBg
property string bgmFile property string bgmFile
property string language property string language
property var disabledPack: [] property list<string> disabledPack: []
property string preferedMode property string preferedMode
property int preferedPlayerNum property int preferedPlayerNum
property int preferredGeneralNum property int preferredGeneralNum
@ -23,8 +23,8 @@ QtObject {
property real bgmVolume property real bgmVolume
property bool disableMsgAudio property bool disableMsgAudio
property bool hideUseless property bool hideUseless
property var disabledGenerals: [] property list<string> disabledGenerals: []
property var disableGeneralSchemes: [] property list<var> disableGeneralSchemes: []
property int disableSchemeIdx: 0 property int disableSchemeIdx: 0
property int preferredTimeout property int preferredTimeout
@ -39,13 +39,13 @@ QtObject {
// Client data // Client data
property string serverMotd: "" property string serverMotd: ""
property var serverHiddenPacks: [] property list<string> serverHiddenPacks: []
property int roomCapacity: 0 property int roomCapacity: 0
property int roomTimeout: 0 property int roomTimeout: 0
property bool enableFreeAssign: false property bool enableFreeAssign: false
property bool observing: false property bool observing: false
property bool replaying: false property bool replaying: false
property var blockedUsers: [] property list<string> blockedUsers: []
onDisabledGeneralsChanged: { onDisabledGeneralsChanged: {
disableGeneralSchemes[disableSchemeIdx] = disabledGenerals; disableGeneralSchemes[disableSchemeIdx] = disabledGenerals;

View File

@ -431,6 +431,7 @@ Item {
isOwner: model.isOwner isOwner: model.isOwner
ready: model.ready ready: model.ready
surrendered: model.surrendered surrendered: model.surrendered
sealedSlots: JSON.parse(model.sealedSlots)
onSelectedChanged: { onSelectedChanged: {
Logic.updateSelectedTargets(playerid, selected); Logic.updateSelectedTargets(playerid, selected);
@ -1227,6 +1228,7 @@ Item {
isOwner: false, isOwner: false,
ready: false, ready: false,
surrendered: false, surrendered: false,
sealedSlots: "[]",
}); });
} }

View File

@ -663,11 +663,14 @@ callbacks["PropertyUpdate"] = (jsonData) => {
const data = JSON.parse(jsonData); const data = JSON.parse(jsonData);
const uid = data[0]; const uid = data[0];
const property_name = data[1]; const property_name = data[1];
const value = data[2]; let value = data[2];
let model = getPhotoModel(uid); let model = getPhotoModel(uid);
if (typeof(model) !== "undefined") { if (typeof(model) !== "undefined") {
if (property_name == "sealedSlots")
value = JSON.stringify(value); // 辣鸡qml
model[property_name] = value; model[property_name] = value;
} }

View File

@ -5,6 +5,16 @@ import Fk
import Fk.RoomElement import Fk.RoomElement
Item { Item {
property bool sealed: parent.sealedSlots.includes("JudgeSlot")
Image {
visible: sealed
x: -6; y: 8; z: 9
source: SkinBank.DELAYED_TRICK_DIR + "sealed"
height: 28
fillMode: Image.PreserveAspectFit
}
InvisibleCardArea { InvisibleCardArea {
id: area id: area
checkExisting: true checkExisting: true

View File

@ -13,9 +13,11 @@ import Fk.RoomElement
*/ */
Column { Column {
id: root
height: 70 height: 70
width: 138 width: 138
property int itemHeight: treasureItem.name === "" ? height / 3 : height / 4 property int itemHeight: (treasureItem.name === "" && !treasureItem.sealed) ? height / 3 : height / 4
property var items: [treasureItem, weaponItem, armorItem, defensiveHorseItem, offensiveHorseItem] property var items: [treasureItem, weaponItem, armorItem, defensiveHorseItem, offensiveHorseItem]
property var subtypes: ["treasure", "weapon", "armor", "defensive_horse", "offensive_horse"] property var subtypes: ["treasure", "weapon", "armor", "defensive_horse", "offensive_horse"]
property int length: area.length property int length: area.length
@ -28,23 +30,29 @@ Column {
EquipItem { EquipItem {
id: treasureItem id: treasureItem
subtype: "treasure"
width: parent.width width: parent.width
height: name === "" ? 0 : itemHeight height: (name === "" && !sealed) ? 0 : itemHeight
opacity: 0 opacity: 0
sealed: root.parent.sealedSlots.includes('TreasureSlot')
} }
EquipItem { EquipItem {
id: weaponItem id: weaponItem
subtype: "weapon"
width: parent.width width: parent.width
height: itemHeight height: itemHeight
opacity: 0 opacity: 0
sealed: root.parent.sealedSlots.includes('WeaponSlot')
} }
EquipItem { EquipItem {
id: armorItem id: armorItem
subtype: "armor"
width: parent.width width: parent.width
height: itemHeight height: itemHeight
opacity: 0 opacity: 0
sealed: root.parent.sealedSlots.includes('ArmorSlot')
} }
Row { Row {
@ -61,6 +69,7 @@ Column {
height: itemHeight height: itemHeight
icon: "horse" icon: "horse"
opacity: 0 opacity: 0
sealed: root.parent.sealedSlots.includes('DefensiveRideSlot')
} }
} }
@ -74,6 +83,7 @@ Column {
height: itemHeight height: itemHeight
icon: "horse" icon: "horse"
opacity: 0 opacity: 0
sealed: root.parent.sealedSlots.includes('OffensiveRideSlot')
} }
} }
} }

View File

@ -9,31 +9,41 @@ Item {
property string name: "" property string name: ""
property string suit: "" property string suit: ""
property int number: 0 property int number: 0
property bool sealed: false
property string subtype
property string icon: "" property string icon: ""
property alias text: textItem.text property alias text: textItem.text
id: root id: root
Rectangle {
anchors.fill: parent
radius: 2
visible: sealed
color: "#CCC"
opacity: 0.8
}
Image { Image {
id: iconItem id: iconItem
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
x: 3 x: 3
source: icon ? SkinBank.getEquipIcon(cid, icon) : "" source: sealed ? (SkinBank.EQUIP_ICON_DIR + "sealed") : (icon ? SkinBank.getEquipIcon(cid, icon) : "")
} }
Image { Image {
id: suitItem id: suitItem
anchors.right: parent.right anchors.right: parent.right
source: suit ? SkinBank.CARD_SUIT_DIR + suit : "" source: (suit && !sealed) ? SkinBank.CARD_SUIT_DIR + suit : ""
width: implicitWidth / implicitHeight * height width: implicitWidth / implicitHeight * height
height: 16 height: 16
} }
GlowText { GlowText {
id: numberItem id: numberItem
visible: number > 0 && number < 14 visible: !sealed && number > 0 && number < 14
text: Utility.convertNumber(number) text: Utility.convertNumber(number)
color: "white" color: "white"
font.family: fontLibian.name font.family: fontLibian.name
@ -49,7 +59,7 @@ Item {
Text { Text {
id: textItem id: textItem
font.family: fontLibian.name font.family: fontLibian.name
color: "white" color: sealed ? "black" : "white"
font.pixelSize: 18 font.pixelSize: 18
anchors.left: iconItem.right anchors.left: iconItem.right
anchors.leftMargin: -8 anchors.leftMargin: -8
@ -131,13 +141,24 @@ Item {
} }
} }
function show() function show() {
{ if (!sealed) {
showAnime.start(); showAnime.start();
} }
}
function hide() function hide() {
{ if (!sealed) {
hideAnime.start(); hideAnime.start();
} }
} }
onSealedChanged: {
showAnime.stop();
hideAnime.stop();
x = 0;
opacity = 1;
text = ' ' + Backend.translate(subtype + "_sealed")
}
}

View File

@ -34,6 +34,7 @@ Item {
property int winGame: 0 property int winGame: 0
property int runGame: 0 property int runGame: 0
property int totalGame: 0 property int totalGame: 0
property list<string> sealedSlots: []
property int distance: -1 property int distance: -1
property string status: "normal" property string status: "normal"
@ -41,6 +42,7 @@ Item {
property alias handcardArea: handcardAreaItem property alias handcardArea: handcardAreaItem
property alias equipArea: equipAreaItem property alias equipArea: equipAreaItem
property alias areasSealed: equipAreaItem
property alias markArea: markAreaItem property alias markArea: markAreaItem
property alias picMarkArea: picMarkAreaItem property alias picMarkArea: picMarkAreaItem
property alias delayedTrickArea: delayedTrickAreaItem property alias delayedTrickArea: delayedTrickAreaItem

View File

@ -16,7 +16,7 @@ Window {
minimumHeight: 90 minimumHeight: 90
title: qsTr("FreeKill") + " v" + FkVersion title: qsTr("FreeKill") + " v" + FkVersion
property var callbacks: Logic.callbacks property var callbacks: Logic.callbacks
property var tipList: [] property list<string> tipList: []
Item { Item {
id: mainWindow id: mainWindow

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1016 B

View File

@ -338,6 +338,11 @@ Fk:loadTranslationTable{
["Distance"] = "距离", ["Distance"] = "距离",
["Judge"] = "判定", ["Judge"] = "判定",
["Retrial"] = "改判", ["Retrial"] = "改判",
["_sealed"] = "废除",
["weapon_sealed"] = "武器栏废除",
["armor_sealed"] = "防具栏废除",
["treasure_sealed"] = "宝物栏废除",
} }
-- related to sendLog -- related to sendLog

View File

@ -61,6 +61,13 @@ Player.HistoryTurn = 2
Player.HistoryRound = 3 Player.HistoryRound = 3
Player.HistoryGame = 4 Player.HistoryGame = 4
Player.WeaponSlot = 'WeaponSlot'
Player.ArmorSlot = 'ArmorSlot'
Player.OffensiveRideSlot = 'OffensiveRideSlot'
Player.DefensiveRideSlot = 'DefensiveRideSlot'
Player.TreasureSlot = 'TreasureSlot'
Player.JudgeSlot = 'JudgeSlot'
--- 构造函数。总之这不是随便调用的函数 --- 构造函数。总之这不是随便调用的函数
function Player:initialize() function Player:initialize()
self.id = 0 self.id = 0
@ -93,6 +100,15 @@ function Player:initialize()
self.virtual_equips = {} self.virtual_equips = {}
self.special_cards = {} self.special_cards = {}
self.equipSlots = {
Player.WeaponSlot,
Player.ArmorSlot,
Player.OffensiveRideSlot,
Player.DefensiveRideSlot,
Player.TreasureSlot,
}
self.sealedSlots = {}
self.cardUsedHistory = {} self.cardUsedHistory = {}
self.skillUsedHistory = {} self.skillUsedHistory = {}
self.fixedDistance = {} self.fixedDistance = {}
@ -392,6 +408,20 @@ function Player:getEquipment(cardSubtype)
return nil return nil
end end
--- 检索玩家装备区是否存在对应类型的装备列表。
---@param cardSubtype CardSubtype @ 卡牌子类
---@return integer[] @ 返回卡牌ID或空表
function Player:getEquipments(cardSubtype)
local cardIds = {}
for _, cardId in ipairs(self.player_cards[Player.Equip]) do
if Fk:getCardById(cardId).sub_type == cardSubtype then
table.insert(cardIds, cardId)
end
end
return cardIds
end
--- 获取玩家手牌上限。 --- 获取玩家手牌上限。
function Player:getMaxCards() function Player:getMaxCards()
local baseValue = math.max(self.hp, 0) local baseValue = math.max(self.hp, 0)
@ -799,6 +829,15 @@ end
---@param card Card @ 特定牌 ---@param card Card @ 特定牌
function Player:isProhibited(to, card) function Player:isProhibited(to, card)
local r = Fk:currentRoom() local r = Fk:currentRoom()
if card.type == Card.TypeEquip and #to:getAvailableEquipSlots(card.sub_type) == 0 then
return true
end
if card.sub_type == Card.SubtypeDelayedTrick and table.contains(to.sealedSlots, Player.JudgeSlot) then
return true
end
local status_skills = r.status_skills[ProhibitSkill] or Util.DummyTable local status_skills = r.status_skills[ProhibitSkill] or Util.DummyTable
for _, skill in ipairs(status_skills) do for _, skill in ipairs(status_skills) do
if skill:isProhibited(self, to, card) then if skill:isProhibited(self, to, card) then
@ -871,11 +910,15 @@ function Player:canMoveCardInBoardTo(to, id)
assert(card.type == Card.TypeEquip or card.sub_type == Card.SubtypeDelayedTrick) assert(card.type == Card.TypeEquip or card.sub_type == Card.SubtypeDelayedTrick)
if card.type == Card.TypeEquip then if card.type == Card.TypeEquip then
return not to:getEquipment(card.sub_type) return to:hasEmptyEquipSlot(card.sub_type)
else else
return not table.find(to:getCardIds(Player.Judge), function(cardId) return
not (
table.find(to:getCardIds(Player.Judge), function(cardId)
return Fk:getCardById(cardId).name == card.name return Fk:getCardById(cardId).name == card.name
end) end) or
table.contains(to.sealedSlots, Player.JudgeSlot)
)
end end
end end
@ -910,6 +953,41 @@ function Player:getQuestSkillState(skillName)
return type(questSkillState) == "string" and questSkillState or nil return type(questSkillState) == "string" and questSkillState or nil
end end
function Player:getAvailableEquipSlots(subtype)
local tempSlots = table.simpleClone(self.equipSlots)
local tempSealedSlots = table.simpleClone(self.sealedSlots)
if subtype then
local subtype2slot = {
[Card.SubtypeWeapon] = Player.WeaponSlot,
[Card.SubtypeArmor] = Player.ArmorSlot,
[Card.SubtypeOffensiveRide] = Player.OffensiveRideSlot,
[Card.SubtypeDefensiveRide] = Player.DefensiveRideSlot,
[Card.SubtypeTreasure] = Player.TreasureSlot,
}
local singleSlot = table.filter(tempSlots, function(slot)
return slot == subtype2slot[subtype]
end)
for _, sealedSlot in ipairs(tempSealedSlots) do
table.removeOne(singleSlot, sealedSlot)
end
return singleSlot
end
for _, sealedSlot in ipairs(tempSealedSlots) do
table.removeOne(tempSlots, sealedSlot)
end
return tempSlots
end
function Player:hasEmptyEquipSlot(subtype)
return #self:getAvailableEquipSlots(subtype) - #self:getEquipments(subtype) > 0
end
function Player:addBuddy(other) function Player:addBuddy(other)
table.insert(self.buddy_list, other.id) table.insert(self.buddy_list, other.id)
end end

View File

@ -28,6 +28,30 @@ Util.lockTable = function(t)
return setmetatable({}, new_mt) return setmetatable({}, new_mt)
end end
Util.convertSubtypeAndEquipSlot = function(value)
if type(value) == "number" then
local mapper = {
[Card.SubtypeWeapon] = Player.WeaponSlot,
[Card.SubtypeArmor] = Player.ArmorSlot,
[Card.SubtypeOffensiveRide] = Player.OffensiveRideSlot,
[Card.SubtypeDefensiveRide] = Player.DefensiveRideSlot,
[Card.SubtypeTreasure] = Player.TreasureSlot,
}
return mapper[value]
else
local mapper = {
[Player.WeaponSlot] = Card.SubtypeWeapon,
[Player.ArmorSlot] = Card.SubtypeArmor,
[Player.OffensiveRideSlot] = Card.SubtypeOffensiveRide,
[Player.DefensiveRideSlot] = Card.SubtypeDefensiveRide,
[Player.TreasureSlot] = Card.SubtypeTreasure,
}
return mapper[value]
end
end
function printf(fmt, ...) function printf(fmt, ...)
print(string.format(fmt, ...)) print(string.format(fmt, ...))
end end

View File

@ -438,6 +438,18 @@ local defaultCardSkill = fk.CreateActiveSkill{
end end
} }
local defaultEquipSkill = fk.CreateActiveSkill{
name = "default_equip_skill",
can_use = function(self, player, card)
return #player:getAvailableEquipSlots(card.sub_type) > 0
end,
on_use = function(self, room, use)
if not use.tos or #TargetGroup:getRealTargets(use.tos) == 0 then
use.tos = { { use.from } }
end
end
}
local function preprocessCardSpec(spec) local function preprocessCardSpec(spec)
assert(type(spec.name) == "string" or type(spec.class_name) == "string") assert(type(spec.name) == "string" or type(spec.class_name) == "string")
if not spec.name then spec.name = spec.class_name if not spec.name then spec.name = spec.class_name
@ -447,7 +459,7 @@ local function preprocessCardSpec(spec)
end end
local function readCardSpecToCard(card, spec) local function readCardSpecToCard(card, spec)
card.skill = spec.skill or defaultCardSkill card.skill = spec.skill or (card.type == Card.TypeEquip and defaultEquipSkill or defaultCardSkill)
card.skill.cardSkill = true card.skill.cardSkill = true
card.special_skills = spec.special_skills card.special_skills = spec.special_skills
card.is_damage_card = spec.is_damage_card card.is_damage_card = spec.is_damage_card

View File

@ -17,14 +17,32 @@ GameEvent.functions[GameEvent.MoveCards] = function(self)
---@type MoveInfo[] ---@type MoveInfo[]
local infos = {} local infos = {}
local abortMoveInfos = {}
for _, id in ipairs(cardsMoveInfo.ids) do for _, id in ipairs(cardsMoveInfo.ids) do
local toAbortDrop = false
if cardsMoveInfo.toArea == Card.PlayerEquip and cardsMoveInfo.to then
local moveToPlayer = room:getPlayerById(cardsMoveInfo.to)
local card = moveToPlayer:getVirualEquip(id) or Fk:getCardById(id)
if card.type == Card.TypeEquip and #moveToPlayer:getAvailableEquipSlots(card.sub_type) == 0 then
table.insert(abortMoveInfos, {
cardId = id,
fromArea = room:getCardArea(id),
fromSpecialName = cardsMoveInfo.from and room:getPlayerById(cardsMoveInfo.from):getPileNameOfId(id),
})
toAbortDrop = true
end
end
if not toAbortDrop then
table.insert(infos, { table.insert(infos, {
cardId = id, cardId = id,
fromArea = room:getCardArea(id), fromArea = room:getCardArea(id),
fromSpecialName = cardsMoveInfo.from and room:getPlayerById(cardsMoveInfo.from):getPileNameOfId(id), fromSpecialName = cardsMoveInfo.from and room:getPlayerById(cardsMoveInfo.from):getPileNameOfId(id),
}) })
end end
end
if #infos > 0 then
---@type CardsMoveStruct ---@type CardsMoveStruct
local cardsMoveStruct = { local cardsMoveStruct = {
moveInfo = infos, moveInfo = infos,
@ -42,7 +60,25 @@ GameEvent.functions[GameEvent.MoveCards] = function(self)
table.insert(cardsMoveStructs, cardsMoveStruct) table.insert(cardsMoveStructs, cardsMoveStruct)
end end
if #abortMoveInfos > 0 then
---@type CardsMoveStruct
local cardsMoveStruct = {
moveInfo = abortMoveInfos,
from = cardsMoveInfo.from,
toArea = Card.DiscardPile,
moveReason = fk.ReasonPutIntoDiscardPile,
specialName = cardsMoveInfo.specialName,
specialVisible = cardsMoveInfo.specialVisible,
drawPilePosition = cardsMoveInfo.drawPilePosition,
}
table.insert(cardsMoveStructs, cardsMoveStruct)
end end
end
end
self.data = cardsMoveStructs
if #cardsMoveStructs < 1 then if #cardsMoveStructs < 1 then
return false return false

View File

@ -185,13 +185,7 @@ GameEvent.functions[GameEvent.UseCard] = function(self)
local room = self.room local room = self.room
local logic = room.logic local logic = room.logic
local from = cardUseEvent.from room:moveCardTo(cardUseEvent.card, Card.Processing, nil, fk.ReasonUse)
room:moveCards({
ids = room:getSubcardsByRule(cardUseEvent.card),
from = from,
toArea = Card.Processing,
moveReason = fk.ReasonUse,
})
if cardUseEvent.card.skill then if cardUseEvent.card.skill then
cardUseEvent.card.skill:onUse(room, cardUseEvent) cardUseEvent.card.skill:onUse(room, cardUseEvent)
@ -270,12 +264,7 @@ GameEvent.functions[GameEvent.RespondCard] = function(self)
card = cardIds, card = cardIds,
} }
end end
room:moveCards({ room:moveCardTo(card, Card.Processing, nil, fk.ReasonResonpse)
ids = cardIds,
from = from,
toArea = Card.Processing,
moveReason = fk.ReasonResonpse,
})
if #cardIds > 0 then if #cardIds > 0 then
room:sendFootnote(cardIds, { room:sendFootnote(cardIds, {
type = "##ResponsePlayCard", type = "##ResponsePlayCard",

View File

@ -2210,7 +2210,7 @@ function Room:doCardUseEffect(cardUseEvent)
end end
if self:getPlayerById(TargetGroup:getRealTargets(cardUseEvent.tos)[1]).dead then if self:getPlayerById(TargetGroup:getRealTargets(cardUseEvent.tos)[1]).dead then
self.moveCards({ self:moveCards({
ids = realCardIds, ids = realCardIds,
toArea = Card.DiscardPile, toArea = Card.DiscardPile,
moveReason = fk.ReasonPutIntoDiscardPile, moveReason = fk.ReasonPutIntoDiscardPile,
@ -2621,9 +2621,18 @@ function Room:moveCardTo(card, to_place, target, reason, skill_name, special_nam
to = target.id to = target.id
end end
self:moveCards{ local movesSplitedByOwner = {}
ids = ids, for _, cardId in ipairs(ids) do
from = self.owner_map[ids[1]], local moveFound = table.find(movesSplitedByOwner, function(move)
return move.from == self.owner_map[cardId]
end)
if moveFound then
table.insert(moveFound.ids, cardId)
else
table.insert(movesSplitedByOwner, {
ids = { cardId },
from = self.owner_map[cardId],
to = to, to = to,
toArea = to_place, toArea = to_place,
moveReason = reason, moveReason = reason,
@ -2631,7 +2640,11 @@ function Room:moveCardTo(card, to_place, target, reason, skill_name, special_nam
specialName = special_name, specialName = special_name,
moveVisible = visible, moveVisible = visible,
proposer = proposer, proposer = proposer,
} })
end
end
self:moveCards(table.unpack(movesSplitedByOwner))
end end
------------------------------------------------------------------------ ------------------------------------------------------------------------
@ -3210,4 +3223,54 @@ function Room:updateQuestSkillState(player, skillName, failed)
}) })
end end
function Room:abortPlayerArea(player, playerSlots)
assert(type(playerSlots) == "string" or type(playerSlots) == "table")
if type(playerSlots) == "string" then
playerSlots = { playerSlots }
end
local cardsToDrop = {}
local slotsSealed = {}
local slotsToSeal = {}
for _, slot in ipairs(playerSlots) do
if slot == Player.JudgeSlot then
if not table.contains(player.sealedSlots, Player.JudgeSlot) then
table.insertIfNeed(slotsToSeal, slot)
local delayedTricks = player:getCardIds(Player.Judge)
if #delayedTricks > 0 then
table.insertTable(cardsToDrop, delayedTricks)
end
end
else
local subtype = Util.convertSubtypeAndEquipSlot(slot)
if #player:getAvailableEquipSlots(subtype) > 0 then
table.insert(slotsToSeal, slot)
local equipmentIndex = (slotsSealed[tostring(subtype)] or 0) + 1
slotsSealed[tostring(subtype)] = equipmentIndex
if equipmentIndex <= #player:getEquipments(subtype) then
table.insert(cardsToDrop, player:getEquipments(subtype)[equipmentIndex])
end
end
end
end
if next(slotsSealed) == nil then
return
end
self:moveCards({
ids = cardsToDrop,
from = player.id,
toArea = Card.DiscardPile,
moveReason = fk.ReasonPutIntoDiscardPile,
})
table.insertTable(player.sealedSlots, slotsToSeal)
self:broadcastProperty(player, "sealedSlots")
end
return Room return Room

View File

@ -306,6 +306,10 @@ function ServerPlayer:marshal(player, observe)
if self.role_shown then if self.role_shown then
room:notifyProperty(player, self, "role") room:notifyProperty(player, self, "role")
end end
if #self.sealedSlots > 0 then
room:notifyProperty(player, self, "sealedSlots")
end
end end
function ServerPlayer:reconnect() function ServerPlayer:reconnect()

View File

@ -51,7 +51,6 @@ local discardSkill = fk.CreateActiveSkill{
local chooseCardsSkill = fk.CreateActiveSkill{ local chooseCardsSkill = fk.CreateActiveSkill{
name = "choose_cards_skill", name = "choose_cards_skill",
-- expand_pile = function(self) return self.expand_pile end,
card_filter = function(self, to_select, selected) card_filter = function(self, to_select, selected)
if #selected >= self.num then if #selected >= self.num then
return false return false

View File

@ -648,7 +648,7 @@ extension:addCards({
local lightningSkill = fk.CreateActiveSkill{ local lightningSkill = fk.CreateActiveSkill{
name = "lightning_skill", name = "lightning_skill",
can_use = function(self, player) can_use = function(self, player)
return not Self:hasDelayedTrick("lightning") return not (Self:hasDelayedTrick("lightning") or table.contains(player.sealedSlots, Player.JudgeSlot))
end, end,
on_use = function(self, room, use) on_use = function(self, room, use)
if not use.tos or #TargetGroup:getRealTargets(use.tos) == 0 then if not use.tos or #TargetGroup:getRealTargets(use.tos) == 0 then

View File

@ -293,6 +293,26 @@ local test_zhenggong = fk.CreateTriggerSkill{
player:gainAnExtraTurn() player:gainAnExtraTurn()
end, end,
} }
local test_feichu = fk.CreateActiveSkill{
name = "test_feichu",
can_use = function(self, player)
return true
end,
card_filter = function(self, card)
return false
end,
card_num = 0,
target_filter = function(self, to_select, selected)
return #selected < 1
end,
target_num = 1,
on_use = function(self, room, effect)
local from = room:getPlayerById(effect.from)
local eqipSlots = from:getAvailableEquipSlots()
table.insert(eqipSlots, Player.JudgeSlot)
room:abortPlayerArea(from, eqipSlots)
end,
}
local test2 = General(extension, "mouxusheng", "wu", 99, 99, General.Female) local test2 = General(extension, "mouxusheng", "wu", 99, 99, General.Female)
test2.shield = 5 test2.shield = 5
test2:addSkill("rende") test2:addSkill("rende")
@ -303,6 +323,7 @@ test2:addSkill(control)
test2:addSkill(damage_maker) test2:addSkill(damage_maker)
test2:addSkill(change_hero) test2:addSkill(change_hero)
test2:addSkill(test_zhenggong) test2:addSkill(test_zhenggong)
test2:addSkill(test_feichu)
local shibing = General(extension, "blank_shibing", "qun", 5) local shibing = General(extension, "blank_shibing", "qun", 5)
shibing.hidden = true shibing.hidden = true