mirror of
https://github.com/Qsgs-Fans/FreeKill.git
synced 2024-11-16 11:42:45 +08:00
parent
69137c9eba
commit
64127bffb6
|
@ -15,7 +15,7 @@ QtObject {
|
|||
property string roomBg
|
||||
property string bgmFile
|
||||
property string language
|
||||
property var disabledPack: []
|
||||
property list<string> disabledPack: []
|
||||
property string preferedMode
|
||||
property int preferedPlayerNum
|
||||
property int preferredGeneralNum
|
||||
|
@ -23,8 +23,8 @@ QtObject {
|
|||
property real bgmVolume
|
||||
property bool disableMsgAudio
|
||||
property bool hideUseless
|
||||
property var disabledGenerals: []
|
||||
property var disableGeneralSchemes: []
|
||||
property list<string> disabledGenerals: []
|
||||
property list<var> disableGeneralSchemes: []
|
||||
property int disableSchemeIdx: 0
|
||||
|
||||
property int preferredTimeout
|
||||
|
@ -39,13 +39,13 @@ QtObject {
|
|||
|
||||
// Client data
|
||||
property string serverMotd: ""
|
||||
property var serverHiddenPacks: []
|
||||
property list<string> serverHiddenPacks: []
|
||||
property int roomCapacity: 0
|
||||
property int roomTimeout: 0
|
||||
property bool enableFreeAssign: false
|
||||
property bool observing: false
|
||||
property bool replaying: false
|
||||
property var blockedUsers: []
|
||||
property list<string> blockedUsers: []
|
||||
|
||||
onDisabledGeneralsChanged: {
|
||||
disableGeneralSchemes[disableSchemeIdx] = disabledGenerals;
|
||||
|
|
|
@ -431,6 +431,7 @@ Item {
|
|||
isOwner: model.isOwner
|
||||
ready: model.ready
|
||||
surrendered: model.surrendered
|
||||
sealedSlots: JSON.parse(model.sealedSlots)
|
||||
|
||||
onSelectedChanged: {
|
||||
Logic.updateSelectedTargets(playerid, selected);
|
||||
|
@ -1227,6 +1228,7 @@ Item {
|
|||
isOwner: false,
|
||||
ready: false,
|
||||
surrendered: false,
|
||||
sealedSlots: "[]",
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -663,11 +663,14 @@ callbacks["PropertyUpdate"] = (jsonData) => {
|
|||
const data = JSON.parse(jsonData);
|
||||
const uid = data[0];
|
||||
const property_name = data[1];
|
||||
const value = data[2];
|
||||
let value = data[2];
|
||||
|
||||
let model = getPhotoModel(uid);
|
||||
|
||||
if (typeof(model) !== "undefined") {
|
||||
if (property_name == "sealedSlots")
|
||||
value = JSON.stringify(value); // 辣鸡qml
|
||||
|
||||
model[property_name] = value;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,16 @@ import Fk
|
|||
import Fk.RoomElement
|
||||
|
||||
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 {
|
||||
id: area
|
||||
checkExisting: true
|
||||
|
|
|
@ -13,9 +13,11 @@ import Fk.RoomElement
|
|||
*/
|
||||
|
||||
Column {
|
||||
id: root
|
||||
|
||||
height: 70
|
||||
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 subtypes: ["treasure", "weapon", "armor", "defensive_horse", "offensive_horse"]
|
||||
property int length: area.length
|
||||
|
@ -28,23 +30,29 @@ Column {
|
|||
|
||||
EquipItem {
|
||||
id: treasureItem
|
||||
subtype: "treasure"
|
||||
width: parent.width
|
||||
height: name === "" ? 0 : itemHeight
|
||||
height: (name === "" && !sealed) ? 0 : itemHeight
|
||||
opacity: 0
|
||||
sealed: root.parent.sealedSlots.includes('TreasureSlot')
|
||||
}
|
||||
|
||||
EquipItem {
|
||||
id: weaponItem
|
||||
subtype: "weapon"
|
||||
width: parent.width
|
||||
height: itemHeight
|
||||
opacity: 0
|
||||
sealed: root.parent.sealedSlots.includes('WeaponSlot')
|
||||
}
|
||||
|
||||
EquipItem {
|
||||
id: armorItem
|
||||
subtype: "armor"
|
||||
width: parent.width
|
||||
height: itemHeight
|
||||
opacity: 0
|
||||
sealed: root.parent.sealedSlots.includes('ArmorSlot')
|
||||
}
|
||||
|
||||
Row {
|
||||
|
@ -61,6 +69,7 @@ Column {
|
|||
height: itemHeight
|
||||
icon: "horse"
|
||||
opacity: 0
|
||||
sealed: root.parent.sealedSlots.includes('DefensiveRideSlot')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,6 +83,7 @@ Column {
|
|||
height: itemHeight
|
||||
icon: "horse"
|
||||
opacity: 0
|
||||
sealed: root.parent.sealedSlots.includes('OffensiveRideSlot')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,31 +9,41 @@ Item {
|
|||
property string name: ""
|
||||
property string suit: ""
|
||||
property int number: 0
|
||||
property bool sealed: false
|
||||
property string subtype
|
||||
|
||||
property string icon: ""
|
||||
property alias text: textItem.text
|
||||
|
||||
id: root
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: 2
|
||||
visible: sealed
|
||||
color: "#CCC"
|
||||
opacity: 0.8
|
||||
}
|
||||
|
||||
Image {
|
||||
id: iconItem
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
x: 3
|
||||
|
||||
source: icon ? SkinBank.getEquipIcon(cid, icon) : ""
|
||||
source: sealed ? (SkinBank.EQUIP_ICON_DIR + "sealed") : (icon ? SkinBank.getEquipIcon(cid, icon) : "")
|
||||
}
|
||||
|
||||
Image {
|
||||
id: suitItem
|
||||
anchors.right: parent.right
|
||||
source: suit ? SkinBank.CARD_SUIT_DIR + suit : ""
|
||||
source: (suit && !sealed) ? SkinBank.CARD_SUIT_DIR + suit : ""
|
||||
width: implicitWidth / implicitHeight * height
|
||||
height: 16
|
||||
}
|
||||
|
||||
GlowText {
|
||||
id: numberItem
|
||||
visible: number > 0 && number < 14
|
||||
visible: !sealed && number > 0 && number < 14
|
||||
text: Utility.convertNumber(number)
|
||||
color: "white"
|
||||
font.family: fontLibian.name
|
||||
|
@ -49,7 +59,7 @@ Item {
|
|||
Text {
|
||||
id: textItem
|
||||
font.family: fontLibian.name
|
||||
color: "white"
|
||||
color: sealed ? "black" : "white"
|
||||
font.pixelSize: 18
|
||||
anchors.left: iconItem.right
|
||||
anchors.leftMargin: -8
|
||||
|
@ -131,13 +141,24 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
function show()
|
||||
{
|
||||
showAnime.start();
|
||||
function show() {
|
||||
if (!sealed) {
|
||||
showAnime.start();
|
||||
}
|
||||
}
|
||||
|
||||
function hide()
|
||||
{
|
||||
hideAnime.start();
|
||||
function hide() {
|
||||
if (!sealed) {
|
||||
hideAnime.start();
|
||||
}
|
||||
}
|
||||
|
||||
onSealedChanged: {
|
||||
showAnime.stop();
|
||||
hideAnime.stop();
|
||||
x = 0;
|
||||
|
||||
opacity = 1;
|
||||
text = ' ' + Backend.translate(subtype + "_sealed")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ Item {
|
|||
property int winGame: 0
|
||||
property int runGame: 0
|
||||
property int totalGame: 0
|
||||
property list<string> sealedSlots: []
|
||||
|
||||
property int distance: -1
|
||||
property string status: "normal"
|
||||
|
@ -41,6 +42,7 @@ Item {
|
|||
|
||||
property alias handcardArea: handcardAreaItem
|
||||
property alias equipArea: equipAreaItem
|
||||
property alias areasSealed: equipAreaItem
|
||||
property alias markArea: markAreaItem
|
||||
property alias picMarkArea: picMarkAreaItem
|
||||
property alias delayedTrickArea: delayedTrickAreaItem
|
||||
|
|
|
@ -16,7 +16,7 @@ Window {
|
|||
minimumHeight: 90
|
||||
title: qsTr("FreeKill") + " v" + FkVersion
|
||||
property var callbacks: Logic.callbacks
|
||||
property var tipList: []
|
||||
property list<string> tipList: []
|
||||
|
||||
Item {
|
||||
id: mainWindow
|
||||
|
|
BIN
image/card/delayedTrick/sealed.png
Normal file
BIN
image/card/delayedTrick/sealed.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
BIN
image/card/equipIcon/sealed.png
Normal file
BIN
image/card/equipIcon/sealed.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1016 B |
|
@ -338,6 +338,11 @@ Fk:loadTranslationTable{
|
|||
["Distance"] = "距离",
|
||||
["Judge"] = "判定",
|
||||
["Retrial"] = "改判",
|
||||
|
||||
["_sealed"] = "废除",
|
||||
["weapon_sealed"] = "武器栏废除",
|
||||
["armor_sealed"] = "防具栏废除",
|
||||
["treasure_sealed"] = "宝物栏废除",
|
||||
}
|
||||
|
||||
-- related to sendLog
|
||||
|
|
|
@ -61,6 +61,13 @@ Player.HistoryTurn = 2
|
|||
Player.HistoryRound = 3
|
||||
Player.HistoryGame = 4
|
||||
|
||||
Player.WeaponSlot = 'WeaponSlot'
|
||||
Player.ArmorSlot = 'ArmorSlot'
|
||||
Player.OffensiveRideSlot = 'OffensiveRideSlot'
|
||||
Player.DefensiveRideSlot = 'DefensiveRideSlot'
|
||||
Player.TreasureSlot = 'TreasureSlot'
|
||||
Player.JudgeSlot = 'JudgeSlot'
|
||||
|
||||
--- 构造函数。总之这不是随便调用的函数
|
||||
function Player:initialize()
|
||||
self.id = 0
|
||||
|
@ -93,6 +100,15 @@ function Player:initialize()
|
|||
self.virtual_equips = {}
|
||||
self.special_cards = {}
|
||||
|
||||
self.equipSlots = {
|
||||
Player.WeaponSlot,
|
||||
Player.ArmorSlot,
|
||||
Player.OffensiveRideSlot,
|
||||
Player.DefensiveRideSlot,
|
||||
Player.TreasureSlot,
|
||||
}
|
||||
self.sealedSlots = {}
|
||||
|
||||
self.cardUsedHistory = {}
|
||||
self.skillUsedHistory = {}
|
||||
self.fixedDistance = {}
|
||||
|
@ -392,6 +408,20 @@ function Player:getEquipment(cardSubtype)
|
|||
return nil
|
||||
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()
|
||||
local baseValue = math.max(self.hp, 0)
|
||||
|
@ -799,6 +829,15 @@ end
|
|||
---@param card Card @ 特定牌
|
||||
function Player:isProhibited(to, card)
|
||||
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
|
||||
for _, skill in ipairs(status_skills) do
|
||||
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)
|
||||
|
||||
if card.type == Card.TypeEquip then
|
||||
return not to:getEquipment(card.sub_type)
|
||||
return to:hasEmptyEquipSlot(card.sub_type)
|
||||
else
|
||||
return not table.find(to:getCardIds(Player.Judge), function(cardId)
|
||||
return Fk:getCardById(cardId).name == card.name
|
||||
end)
|
||||
return
|
||||
not (
|
||||
table.find(to:getCardIds(Player.Judge), function(cardId)
|
||||
return Fk:getCardById(cardId).name == card.name
|
||||
end) or
|
||||
table.contains(to.sealedSlots, Player.JudgeSlot)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -910,6 +953,41 @@ function Player:getQuestSkillState(skillName)
|
|||
return type(questSkillState) == "string" and questSkillState or nil
|
||||
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)
|
||||
table.insert(self.buddy_list, other.id)
|
||||
end
|
||||
|
|
|
@ -28,6 +28,30 @@ Util.lockTable = function(t)
|
|||
return setmetatable({}, new_mt)
|
||||
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, ...)
|
||||
print(string.format(fmt, ...))
|
||||
end
|
||||
|
|
|
@ -438,6 +438,18 @@ local defaultCardSkill = fk.CreateActiveSkill{
|
|||
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)
|
||||
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
||||
if not spec.name then spec.name = spec.class_name
|
||||
|
@ -447,7 +459,7 @@ local function preprocessCardSpec(spec)
|
|||
end
|
||||
|
||||
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.special_skills = spec.special_skills
|
||||
card.is_damage_card = spec.is_damage_card
|
||||
|
|
|
@ -17,33 +17,69 @@ GameEvent.functions[GameEvent.MoveCards] = function(self)
|
|||
|
||||
---@type MoveInfo[]
|
||||
local infos = {}
|
||||
local abortMoveInfos = {}
|
||||
for _, id in ipairs(cardsMoveInfo.ids) do
|
||||
table.insert(infos, {
|
||||
cardId = id,
|
||||
fromArea = room:getCardArea(id),
|
||||
fromSpecialName = cardsMoveInfo.from and room:getPlayerById(cardsMoveInfo.from):getPileNameOfId(id),
|
||||
})
|
||||
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, {
|
||||
cardId = id,
|
||||
fromArea = room:getCardArea(id),
|
||||
fromSpecialName = cardsMoveInfo.from and room:getPlayerById(cardsMoveInfo.from):getPileNameOfId(id),
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
---@type CardsMoveStruct
|
||||
local cardsMoveStruct = {
|
||||
moveInfo = infos,
|
||||
from = cardsMoveInfo.from,
|
||||
to = cardsMoveInfo.to,
|
||||
toArea = cardsMoveInfo.toArea,
|
||||
moveReason = cardsMoveInfo.moveReason,
|
||||
proposer = cardsMoveInfo.proposer,
|
||||
skillName = cardsMoveInfo.skillName,
|
||||
moveVisible = cardsMoveInfo.moveVisible,
|
||||
specialName = cardsMoveInfo.specialName,
|
||||
specialVisible = cardsMoveInfo.specialVisible,
|
||||
drawPilePosition = cardsMoveInfo.drawPilePosition,
|
||||
}
|
||||
if #infos > 0 then
|
||||
---@type CardsMoveStruct
|
||||
local cardsMoveStruct = {
|
||||
moveInfo = infos,
|
||||
from = cardsMoveInfo.from,
|
||||
to = cardsMoveInfo.to,
|
||||
toArea = cardsMoveInfo.toArea,
|
||||
moveReason = cardsMoveInfo.moveReason,
|
||||
proposer = cardsMoveInfo.proposer,
|
||||
skillName = cardsMoveInfo.skillName,
|
||||
moveVisible = cardsMoveInfo.moveVisible,
|
||||
specialName = cardsMoveInfo.specialName,
|
||||
specialVisible = cardsMoveInfo.specialVisible,
|
||||
drawPilePosition = cardsMoveInfo.drawPilePosition,
|
||||
}
|
||||
|
||||
table.insert(cardsMoveStructs, cardsMoveStruct)
|
||||
table.insert(cardsMoveStructs, cardsMoveStruct)
|
||||
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
|
||||
|
||||
self.data = cardsMoveStructs
|
||||
|
||||
if #cardsMoveStructs < 1 then
|
||||
return false
|
||||
end
|
||||
|
|
|
@ -185,13 +185,7 @@ GameEvent.functions[GameEvent.UseCard] = function(self)
|
|||
local room = self.room
|
||||
local logic = room.logic
|
||||
|
||||
local from = cardUseEvent.from
|
||||
room:moveCards({
|
||||
ids = room:getSubcardsByRule(cardUseEvent.card),
|
||||
from = from,
|
||||
toArea = Card.Processing,
|
||||
moveReason = fk.ReasonUse,
|
||||
})
|
||||
room:moveCardTo(cardUseEvent.card, Card.Processing, nil, fk.ReasonUse)
|
||||
|
||||
if cardUseEvent.card.skill then
|
||||
cardUseEvent.card.skill:onUse(room, cardUseEvent)
|
||||
|
@ -270,12 +264,7 @@ GameEvent.functions[GameEvent.RespondCard] = function(self)
|
|||
card = cardIds,
|
||||
}
|
||||
end
|
||||
room:moveCards({
|
||||
ids = cardIds,
|
||||
from = from,
|
||||
toArea = Card.Processing,
|
||||
moveReason = fk.ReasonResonpse,
|
||||
})
|
||||
room:moveCardTo(card, Card.Processing, nil, fk.ReasonResonpse)
|
||||
if #cardIds > 0 then
|
||||
room:sendFootnote(cardIds, {
|
||||
type = "##ResponsePlayCard",
|
||||
|
|
|
@ -2210,7 +2210,7 @@ function Room:doCardUseEffect(cardUseEvent)
|
|||
end
|
||||
|
||||
if self:getPlayerById(TargetGroup:getRealTargets(cardUseEvent.tos)[1]).dead then
|
||||
self.moveCards({
|
||||
self:moveCards({
|
||||
ids = realCardIds,
|
||||
toArea = Card.DiscardPile,
|
||||
moveReason = fk.ReasonPutIntoDiscardPile,
|
||||
|
@ -2621,17 +2621,30 @@ function Room:moveCardTo(card, to_place, target, reason, skill_name, special_nam
|
|||
to = target.id
|
||||
end
|
||||
|
||||
self:moveCards{
|
||||
ids = ids,
|
||||
from = self.owner_map[ids[1]],
|
||||
to = to,
|
||||
toArea = to_place,
|
||||
moveReason = reason,
|
||||
skillName = skill_name,
|
||||
specialName = special_name,
|
||||
moveVisible = visible,
|
||||
proposer = proposer,
|
||||
}
|
||||
local movesSplitedByOwner = {}
|
||||
for _, cardId in ipairs(ids) do
|
||||
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,
|
||||
toArea = to_place,
|
||||
moveReason = reason,
|
||||
skillName = skill_name,
|
||||
specialName = special_name,
|
||||
moveVisible = visible,
|
||||
proposer = proposer,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
self:moveCards(table.unpack(movesSplitedByOwner))
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
@ -3210,4 +3223,54 @@ function Room:updateQuestSkillState(player, skillName, failed)
|
|||
})
|
||||
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
|
||||
|
|
|
@ -306,6 +306,10 @@ function ServerPlayer:marshal(player, observe)
|
|||
if self.role_shown then
|
||||
room:notifyProperty(player, self, "role")
|
||||
end
|
||||
|
||||
if #self.sealedSlots > 0 then
|
||||
room:notifyProperty(player, self, "sealedSlots")
|
||||
end
|
||||
end
|
||||
|
||||
function ServerPlayer:reconnect()
|
||||
|
|
|
@ -51,7 +51,6 @@ local discardSkill = fk.CreateActiveSkill{
|
|||
|
||||
local chooseCardsSkill = fk.CreateActiveSkill{
|
||||
name = "choose_cards_skill",
|
||||
-- expand_pile = function(self) return self.expand_pile end,
|
||||
card_filter = function(self, to_select, selected)
|
||||
if #selected >= self.num then
|
||||
return false
|
||||
|
|
|
@ -648,7 +648,7 @@ extension:addCards({
|
|||
local lightningSkill = fk.CreateActiveSkill{
|
||||
name = "lightning_skill",
|
||||
can_use = function(self, player)
|
||||
return not Self:hasDelayedTrick("lightning")
|
||||
return not (Self:hasDelayedTrick("lightning") or table.contains(player.sealedSlots, Player.JudgeSlot))
|
||||
end,
|
||||
on_use = function(self, room, use)
|
||||
if not use.tos or #TargetGroup:getRealTargets(use.tos) == 0 then
|
||||
|
|
|
@ -293,6 +293,26 @@ local test_zhenggong = fk.CreateTriggerSkill{
|
|||
player:gainAnExtraTurn()
|
||||
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)
|
||||
test2.shield = 5
|
||||
test2:addSkill("rende")
|
||||
|
@ -303,6 +323,7 @@ test2:addSkill(control)
|
|||
test2:addSkill(damage_maker)
|
||||
test2:addSkill(change_hero)
|
||||
test2:addSkill(test_zhenggong)
|
||||
test2:addSkill(test_feichu)
|
||||
|
||||
local shibing = General(extension, "blank_shibing", "qun", 5)
|
||||
shibing.hidden = true
|
||||
|
|
Loading…
Reference in New Issue
Block a user