diff --git a/Fk/Pages/Room.qml b/Fk/Pages/Room.qml index f55360d1cebdfcb5eb964ed78ecd4583596cf810..7e9d01ae6f67612c450f9ec6e0ee6664f39ad425 100644 --- a/Fk/Pages/Room.qml +++ b/Fk/Pages/Room.qml @@ -501,10 +501,12 @@ Item { // text: luatr("Trust") // } MetroButton { + id: sortBtn text: luatr("Sort Cards") textFont.pixelSize: 28 + enabled: dashboard.sortable// lcall("CanSortHandcards", Self.id) onClicked: { - if (lcall("CanSortHandcards", Self.id)) { + if (dashboard.sortable) { let sortMethods = []; for (let index = 0; index < sortMenuRepeater.count; index++) { var tCheckBox = sortMenuRepeater.itemAt(index) diff --git a/Fk/Pages/RoomLogic.js b/Fk/Pages/RoomLogic.js index 559abb64d08b3ef029d91f0503ff4fd027ea1da0..16eed59fea1d8e10a0bd2ac741525ff25b375907 100644 --- a/Fk/Pages/RoomLogic.js +++ b/Fk/Pages/RoomLogic.js @@ -259,14 +259,27 @@ function sortHandcards(sortMethods) { ["treasure"]: Card.SubtypeTreasure, } - const hand = dashboard.handcardArea.cards.map(c => { + const others = []; + const hands = []; + const orignal_hands = lcall("GetPlayerHandcards", Self.id); // 不计入expand_pile + + dashboard.handcardArea.cards.forEach(c => { + if (orignal_hands.includes(c.cid)) { + hands.push(c); + } else { + others.push(c); + } + }) + + const orignal = hands.map(c => { return c.cid; }) + let sortedByType = true; let handcards if (cardType) { - handcards = dashboard.handcardArea.cards.slice(0); + handcards = hands.slice(0); handcards.sort((prev, next) => { if (prev.footnote === next.footnote) { if (prev.type === next.type) { @@ -297,7 +310,7 @@ function sortHandcards(sortMethods) { // Check if the cards are sorted by type let i = 0; handcards.every(c => { - if (hand[i] !== c.cid) { + if (orignal[i] !== c.cid) { sortedByType = false; return false; } @@ -310,7 +323,7 @@ function sortHandcards(sortMethods) { let sortedByNum = true; if (cardNum) { - handcards = dashboard.handcardArea.cards.slice(0); + handcards = hands.slice(0); handcards.sort((prev, next) => { if (prev.footnote === next.footnote) { if (prev.number === next.number) { @@ -329,7 +342,7 @@ function sortHandcards(sortMethods) { let i = 0; handcards.every(c => { - if (hand[i] !== c.cid) { + if (orignal[i] !== c.cid) { sortedByNum = false; return false; } @@ -342,7 +355,7 @@ function sortHandcards(sortMethods) { let sortedBySuit = true; if (cardSuit) { - handcards = dashboard.handcardArea.cards.slice(0); + handcards = hands.slice(0); handcards.sort((prev, next) => { if (prev.footnote === next.footnote) { if (suitInteger[prev.suit] === suitInteger[next.suit]) { @@ -361,7 +374,7 @@ function sortHandcards(sortMethods) { let i = 0; handcards.every(c => { - if (hand[i] !== c.cid) { + if (orignal[i] !== c.cid) { sortedBySuit = false; return false; } @@ -380,6 +393,7 @@ function sortHandcards(sortMethods) { } } if (!output) output = sortOutputs[0]; + output.concat(others); dashboard.handcardArea.cards = output; dashboard.handcardArea.updateCardPosition(true); } @@ -689,6 +703,34 @@ callbacks["PropertyUpdate"] = (data) => { } } +callbacks["UpdateHandcard"] = (j) => { + const id = parseInt(j); + const sortable = lcall("CanSortHandcards", Self.id); + let card; + roomScene.tableCards.forEach((v) => { + if (v.cid === id) { + card = v; + return; + } + }); + + if (!card) { + roomScene.dashboard.handcardArea.cards.forEach((v) => { + if (v.cid === id) { + card = v; + return; + } + }); + } + + if (!card) { + return; + } + + card.setData(lcall("GetCardData", id)); + card.draggable = sortable; +} + callbacks["UpdateCard"] = (j) => { const id = parseInt(j); let card; @@ -1527,6 +1569,14 @@ callbacks["UpdateRequestUI"] = (uiUpdate) => { } } +// 蒋琬 +callbacks["GetPlayerHandcards"] = (data) => { + const hand = dashboard.handcardArea.cards.map(c => { + return c.cid; + }) + replyToServer(JSON.stringify(hand)); +} + callbacks["ReplyToServer"] = (data) => { replyToServer(data); } diff --git a/Fk/RoomElement/Dashboard.qml b/Fk/RoomElement/Dashboard.qml index 0e164dfb6dae1134fadb468bc89a220177abb413..c9a2169e1718439f539285548f159f1f2cbfc3f4 100644 --- a/Fk/RoomElement/Dashboard.qml +++ b/Fk/RoomElement/Dashboard.qml @@ -12,6 +12,7 @@ RowLayout { property alias handcardArea: handcardAreaItem property string pending_skill: "" + property bool sortable: true property var pending_card property var pendings: [] // int[], store cid property int selected_card: -1 @@ -137,6 +138,7 @@ RowLayout { function update() { unSelectAll(); disableSkills(); + sortable = handcardAreaItem.sortable; let cards = handcardAreaItem.cards; const toRemove = []; @@ -187,6 +189,7 @@ RowLayout { } }); handcardAreaItem.applyChange(uiUpdate); + sortable = handcardAreaItem.sortable; // skillBtn - SkillArea const skDatas = uiUpdate["SkillButton"] skDatas?.forEach(skdata => { diff --git a/Fk/RoomElement/HandcardArea.qml b/Fk/RoomElement/HandcardArea.qml index b45022dd1ce15253027bfed2b6c05383265aacea..21409cada669fd1b9d84c33b4a73d8928ae1ad1e 100644 --- a/Fk/RoomElement/HandcardArea.qml +++ b/Fk/RoomElement/HandcardArea.qml @@ -6,6 +6,7 @@ import Fk Item { property alias cards: cardArea.cards property alias length: cardArea.length + property bool sortable: true property var selectedCards: [] property var movepos @@ -33,7 +34,8 @@ Item { function filterInputCard(card) { card.autoBack = true; - card.draggable = lcall("CanSortHandcards", Self.id); + // 只有会被频繁刷新的手牌才能拖动 + // card.draggable = lcall("CanSortHandcards", Self.id); card.selectable = false; card.clicked.connect(selectCard); card.clicked.connect(adjustCards); @@ -112,7 +114,9 @@ Item { function updateCardReleased(_card) { let i; - if (movepos != null) { + if (movepos != null && sortable) { + const handcardnum = lcall("GetPlayerHandcards", Self.id).length; // 不计入expand_pile + if (movepos >= handcardnum) movepos = handcardnum - 1; i = cards.indexOf(_card); cards.splice(i, 1); cards.splice(movepos, 0, _card); @@ -152,6 +156,7 @@ Item { } function applyChange(uiUpdate) { + area.sortable = lcall("CanSortHandcards", Self.id); uiUpdate["CardItem"]?.forEach(cdata => { for (let i = 0; i < cards.length; i++) { const card = cards[i]; diff --git a/lua/client/client_util.lua b/lua/client/client_util.lua index 55b4d293b9e751c38140db75d23b59447ae1aec1..c389c952c92c73472a9709cea3a50be0ab175e39 100644 --- a/lua/client/client_util.lua +++ b/lua/client/client_util.lua @@ -843,7 +843,14 @@ function GetTargetTip(pid) end function CanSortHandcards(pid) - return ClientInstance:getPlayerById(pid):getMark(MarkEnum.SortProhibited) == 0 + local cplayer = ClientInstance:getPlayerById(pid) + if cplayer then + -- for m, _ in pairs(cplayer.mark) do + -- if m == MarkEnum.SortProhibited or m:startsWith(MarkEnum.SortProhibited .. "-") then return false end + -- end + return cplayer:canSortHandcards() + end + return true end function ChooseGeneralPrompt(rule_name, data, extra_data) @@ -1045,7 +1052,7 @@ function RefreshStatusSkills() end -- 刷自己的手牌 for _, cid in ipairs(Self:getCardIds("h")) do - self:notifyUI("UpdateCard", cid) + self:notifyUI("UpdateHandcard", cid) end Self:filterHandcards() -- 刷技能状态 diff --git a/lua/core/player.lua b/lua/core/player.lua index e3fa74210df16b2377e32ffca5ed512643b1033f..0abf72be58d6a670200989eb9c1535a79eab2324 100644 --- a/lua/core/player.lua +++ b/lua/core/player.lua @@ -1544,6 +1544,15 @@ function Player:getEnemies(include_dead) return enemies end +--- 判断角色是否可以排序手牌 +---@return boolean +function Player:canSortHandcards() + for m, _ in pairs(self.mark) do + if m == MarkEnum.SortProhibited or m:startsWith(MarkEnum.SortProhibited .. "-") then return false end + end + return true +end + function Player:toJsonObject() local ptable = {} for _, k in ipairs(self.property_keys) do diff --git a/lua/server/room.lua b/lua/server/room.lua index 4b2a6a62464b85a9a01689a44e29e50657e7e3f0..592c7142d58c6f8ed1bb80b14fa3fff6e97a29ad 100644 --- a/lua/server/room.lua +++ b/lua/server/room.lua @@ -3666,6 +3666,59 @@ function Room:ActExtraTurn() end end +local function isSame(table1, table2) + if #table1 ~= #table2 then return false end + local tabledup = table.simpleClone(table2) + for _, j in ipairs(table1) do + if not table.removeOne(tabledup, j) then return false end + end + return #tabledup == 0 +end + +--- 获得一名角色的客户端手牌顺序 +--- 本bug由玄蝶提供 +---@param player ServerPlayer @ 角色 +---@return integer[] @ 卡牌ID,有元素检测就是了…… +function Room:getPlayerClientCards(player) + local req = Request:new({player}, "GetPlayerHandcards") + local cards = player.player_cards[Player.Hand] + req:setDefaultReply(player, cards) + local result = req:getResult(player) + -- printf("客户端返回组合:%s", table.map(result, function(e) return tostring(Fk:getCardById(e)) end)) + -- assert(isSame(cards, result), "客户端和服务端信息不符!") + return result +end +--- 同步一名角色的客户端手牌顺序 +--- 本bug由玄蝶提供 +---@param player ServerPlayer @ 角色 +---@return integer[] @ 卡牌ID,有元素检测就是了…… +function Room:syncPlayerClientCards(player) + local cards = player.player_cards[Player.Hand] + local result = self:getPlayerClientCards(player) + -- printf("服务端此时组合:%s", table.concat(table.map(cards, function(e) return tostring(Fk:getCardById(e)) end), ",")) + -- printf("客户端返回组合:%s", table.concat(table.map(result, function(e) return tostring(Fk:getCardById(e)) end), ",")) + assert(isSame(cards, result), "客户端和服务端信息不符!") + player.player_cards[Player.Hand] = result + return result +end + +--- 禁止排序手牌,在此时点,客户端手牌顺序将应用于服务端手牌顺序 +---@param player ServerPlayer @ 角色 +---@param suffix string? @ 后缀,如“-turn” +function Room:banSortingHandcards(player, suffix) + suffix = suffix or "" + self:setPlayerMark(player, MarkEnum.SortProhibited .. suffix, 1) + self:syncPlayerClientCards(player) + --FIXME: 需要一个假request +end + +--- 解禁排序手牌,配合banSortingHandcards使用。 +---@param player ServerPlayer @ 角色 +---@param suffix string? @ 后缀,如“-turn”,一般是你用banSortingHandcards时填入的后缀 +function Room:unbanSortingHandcards(player, suffix) + suffix = suffix or "" + self:setPlayerMark(player, MarkEnum.SortProhibited .. suffix, 0) +end return Room