diff --git a/lua/client/client.lua b/lua/client/client.lua index d121f28f..e2db30c7 100644 --- a/lua/client/client.lua +++ b/lua/client/client.lua @@ -568,7 +568,6 @@ fk.client_callback["Chat"] = function(jsonData) end local p = ClientInstance:getPlayerById(data.sender) - -- TODO: observer chatting if not p then for _, pl in ipairs(ClientInstance.observers) do if pl.id == data.sender then diff --git a/lua/client/client_util.lua b/lua/client/client_util.lua index a0ab51f3..5abf1268 100644 --- a/lua/client/client_util.lua +++ b/lua/client/client_util.lua @@ -84,7 +84,7 @@ function GetCardData(id) extension = card.package.extensionName, number = card.number, suit = card:getSuitString(), - color = card.color, + color = card:getColorString(), subtype = cardSubtypeStrings[card.sub_type] } if card.skillName ~= "" then @@ -437,11 +437,7 @@ end function GetInteractionOfSkill(skill_name) local skill = Fk.skills[skill_name] if skill and skill.interaction then - if type(skill.interaction) == "function" then - return json.encode(skill:interaction()) - else - return json.encode(skill.interaction) - end + return json.encode(skill:interaction()) end return "null" end diff --git a/lua/client/i18n/zh_CN.lua b/lua/client/i18n/zh_CN.lua index 7fdbc475..e731b08a 100644 --- a/lua/client/i18n/zh_CN.lua +++ b/lua/client/i18n/zh_CN.lua @@ -111,6 +111,7 @@ FreeKill使用的是libgit2的C API,与此同时使用Git完成拓展包的下 -- Room ["$EnterRoom"] = "成功加入房间。", + ["#currentRoundNum"] = "第 %1 轮", ["$Choice"] = "%1:请选择", ["$ChooseGeneral"] = "请选择 %1 名武将", ["Same General Convert"] = "替换武将", diff --git a/lua/core/card.lua b/lua/core/card.lua index ff8b2422..45ab7f3b 100644 --- a/lua/core/card.lua +++ b/lua/core/card.lua @@ -158,9 +158,15 @@ local function updateColorAndNumber(card) local color = Card.NoColor local number = 0 local different_color = false - for _, id in ipairs(card.subcards) do + for i, id in ipairs(card.subcards) do local c = Fk:getCardById(id) number = math.min(number + c.number, 13) + if i == 1 then + card.suit = c.suit + else + card.suit = Card.NoSuit + end + if color ~= c.color then if not different_color then if c.color ~= Card.NoColor then @@ -278,7 +284,7 @@ end --- 获取卡牌的文字信息并准备作为log发送。 function Card:toLogString() local ret = string.format('%s', Fk:translate(self.name) .. "[") - if self:isVirtual() then + if self:isVirtual() and #self.subcards ~= 1 then ret = ret .. Fk:translate(self:getColorString()) else ret = ret .. Fk:translate("log_" .. self:getSuitString()) diff --git a/lua/fk_ex.lua b/lua/fk_ex.lua index a4dc46ff..32bc2afb 100644 --- a/lua/fk_ex.lua +++ b/lua/fk_ex.lua @@ -172,7 +172,18 @@ function fk.CreateActiveSkill(spec) if spec.about_to_effect then skill.aboutToEffect = spec.about_to_effect end if spec.on_effect then skill.onEffect = spec.on_effect end if spec.on_nullified then skill.onNullified = spec.on_nullified end - skill.interaction = spec.interaction + + if spec.interaction then + skill.interaction = setmetatable({}, { + __call = function(self) + if type(spec.interaction) == "function" then + return spec.interaction(self) + else + return spec.interaction + end + end, + }) + end return skill end @@ -206,7 +217,18 @@ function fk.CreateViewAsSkill(spec) skill.enabledAtResponse = spec.enabled_at_response end - skill.interaction = spec.interaction + if spec.interaction then + skill.interaction = setmetatable({}, { + __call = function() + if type(spec.interaction) == "function" then + return spec.interaction(skill) + else + return spec.interaction + end + end, + }) + end + return skill end diff --git a/lua/server/events/movecard.lua b/lua/server/events/movecard.lua index 75474ff3..5bb90eb0 100644 --- a/lua/server/events/movecard.lua +++ b/lua/server/events/movecard.lua @@ -96,6 +96,10 @@ GameEvent.functions[GameEvent.MoveCards] = function(self) table.insert(toAreaIds, toAreaIds == Card.DrawPile and 1 or #toAreaIds + 1, info.cardId) end self:setCardArea(info.cardId, data.toArea, data.to) + if data.toArea == Card.DrawPile or realFromArea == Card.DrawPile then + self:doBroadcastNotify("UpdateDrawPile", #self.draw_pile) + end + Fk:filterCard(info.cardId, self:getPlayerById(data.to)) local currentCard = Fk:getCardById(info.cardId) diff --git a/lua/server/room.lua b/lua/server/room.lua index 911e7934..e1fb17a3 100644 --- a/lua/server/room.lua +++ b/lua/server/room.lua @@ -316,6 +316,8 @@ function Room:getNCards(num, from) num = num - 1 end + self:doBroadcastNotify("UpdateDrawPile", #self.draw_pile) + return cardIds end @@ -553,10 +555,13 @@ function Room:requestLoop(rest_time) for _, p in ipairs(self.players) do self:notifyProperty(player, p, "general") + self:notifyProperty(player, p, "deputyGeneral") p:marshal(player) end - -- TODO: tell drawPile + player:doNotify("UpdateDrawPile", #self.draw_pile) + player:doNotify("UpdateRoundNum", self:getTag("RoundCount")) + table.insert(self.observers, {observee.id, player}) end diff --git a/lua/server/serverplayer.lua b/lua/server/serverplayer.lua index 06e985d6..323d25a0 100644 --- a/lua/server/serverplayer.lua +++ b/lua/server/serverplayer.lua @@ -235,9 +235,7 @@ function ServerPlayer:reconnect() }) self:doNotify("EnterLobby", "") self:doNotify("EnterRoom", json.encode{ - #room.players, room.timeout, - -- FIXME: use real room settings here - { enableFreeAssign = false } + #room.players, room.timeout, room.settings, }) room:notifyProperty(self, self, "role") @@ -258,10 +256,12 @@ function ServerPlayer:reconnect() for _, p in ipairs(room.players) do room:notifyProperty(self, p, "general") + room:notifyProperty(self, p, "deputyGeneral") p:marshal(self) end - -- TODO: tell drawPile + self:doNotify("UpdateDrawPile", #room.draw_pile) + self:doNotify("UpdateRoundNum", room:getTag("RoundCount")) room:broadcastProperty(self, "state") end diff --git a/packages/standard/game_rule.lua b/packages/standard/game_rule.lua index a1607e79..0d25d4dd 100644 --- a/packages/standard/game_rule.lua +++ b/packages/standard/game_rule.lua @@ -99,6 +99,7 @@ GameRule = fk.CreateTriggerSkill{ end room:setTag("RoundCount", room:getTag("RoundCount") + 1) + room:doBroadcastNotify("UpdateRoundNum", room:getTag("RoundCount")) for _, p in ipairs(room.players) do p:setCardUseHistory("", 0, Player.HistoryRound) diff --git a/packages/test/init.lua b/packages/test/init.lua index 7dce5589..4760e313 100644 --- a/packages/test/init.lua +++ b/packages/test/init.lua @@ -71,13 +71,14 @@ local test_active = fk.CreateActiveSkill{ end, card_num = 2, target_filter = function() return true end, - interaction = UI.ComboBox { + interaction = function()return UI.ComboBox { choices = Fk.package_names, -- default = "guanyu", - }, + }end, on_use = function(self, room, effect) --room:doSuperLightBox("packages/test/qml/Test.qml") local from = room:getPlayerById(effect.from) + print(self.interaction.data) -- local result = room:askForCustomDialog(from, "simayi", "packages/test/qml/TestDialog.qml", "Hello, world. FROM LUA") -- print(result) diff --git a/qml/Pages/Room.qml b/qml/Pages/Room.qml index 51d9fa70..61e3bca0 100644 --- a/qml/Pages/Room.qml +++ b/qml/Pages/Room.qml @@ -30,10 +30,12 @@ Item { property alias tableCards: tablePile.cards property alias dashboard: dashboard property alias skillInteraction: skillInteraction + property alias miscStatus: miscStatus property var selected_targets: [] property string responding_card property bool respond_play: false + property bool autoPending: false property var extra_data: ({}) Image { @@ -64,6 +66,7 @@ Item { // tmp Button { + id: quitButton text: "quit" anchors.top: parent.top anchors.right: parent.right @@ -137,6 +140,7 @@ Item { skillInteraction.source = ""; dashboard.enableCards(responding_card); dashboard.enableSkills(responding_card); + autoPending = false; progress.visible = true; okCancel.visible = true; } @@ -627,6 +631,14 @@ Item { } } + MiscStatus { + id: miscStatus + anchors.right: quitButton.left + anchors.top: parent.top + anchors.rightMargin: 16 + anchors.topMargin: 8 + } + Danmaku { id: danmaku width: parent.width diff --git a/qml/Pages/RoomElement/CardItem.qml b/qml/Pages/RoomElement/CardItem.qml index 1e79f0f0..de7a821e 100644 --- a/qml/Pages/RoomElement/CardItem.qml +++ b/qml/Pages/RoomElement/CardItem.qml @@ -88,7 +88,7 @@ Item { Image { id: suitItem visible: known - source: suit != "" ? SkinBank.CARD_SUIT_DIR + suit : "" + source: (suit !== "" && suit !== "nosuit") ? SkinBank.CARD_SUIT_DIR + suit : "" x: 3 y: 19 width: 21 @@ -108,8 +108,8 @@ Item { Image { id: colorItem - visible: known && suit == "" - source: (visible && color != "") ? SkinBank.CARD_SUIT_DIR + "/" + color : "" + visible: known && (suit === "" || suit === "nosuit") + source: (visible && color !== "") ? SkinBank.CARD_SUIT_DIR + "/" + color : "" x: 1 } diff --git a/qml/Pages/RoomElement/MiscStatus.qml b/qml/Pages/RoomElement/MiscStatus.qml new file mode 100644 index 00000000..fe423505 --- /dev/null +++ b/qml/Pages/RoomElement/MiscStatus.qml @@ -0,0 +1,69 @@ +import QtQuick +import "../skin-bank.js" as SkinBank + +Item { + id: root + property int pileNum: 0 + property int roundNum: 0 + property int playedTime: 0 + visible: roundNum || pileNum + + function getTimeString(time) { + let s = time % 60; + let m = (time - s) / 60; + let h = (time - s - m * 60) / 3600; + return h ? `${h}:${m}:${s}` : `${m}:${s}`; + } + + Text { + id: roundTxt + anchors.right: parent.right + text: Backend.translate("#currentRoundNum").arg(roundNum) + color: "#F0E5DA" + font.pixelSize: 18 + font.family: fontLibian.name + style: Text.Outline + styleColor: "#3D2D1C" + } + + Text { + id: timeTxt + anchors.right: roundTxt.left + anchors.rightMargin: 12 + color: "#F0E5DA" + font.pixelSize: 18 + font.family: fontLibian.name + style: Text.Outline + styleColor: "#3D2D1C" + } + + Timer { + interval: 1000 + running: roomScene.isStarted + repeat: true + onTriggered: { + playedTime++; + timeTxt.text = getTimeString(playedTime); + } + } + + Image { + id: deckImg + anchors.top: timeTxt.bottom + anchors.topMargin: 8 + anchors.right: parent.right + anchors.rightMargin: 12 + source: SkinBank.CARD_DIR + "card-back" + width: 32 + height: 42 + } + + Text { + anchors.centerIn: deckImg + font.family: fontLibian.name + font.pixelSize: 32 + color: "white" + style: Text.Outline + text: pileNum.toString() + } +} diff --git a/qml/Pages/RoomElement/PhotoElement/MarkArea.qml b/qml/Pages/RoomElement/PhotoElement/MarkArea.qml index f0ee9135..41ad5b4a 100644 --- a/qml/Pages/RoomElement/PhotoElement/MarkArea.qml +++ b/qml/Pages/RoomElement/PhotoElement/MarkArea.qml @@ -6,7 +6,6 @@ import QtQuick.Layouts Item { id: root width: 138 - height: markTxtList.height ListModel { id: markList @@ -23,41 +22,44 @@ Item { border.width: 1 } + Repeater { + id: markRepeater + model: markList + Item { + width: childrenRect.width + height: 22 + Text { + text: Backend.translate(mark_name) + ' ' + Backend.translate(mark_extra) + font.family: fontLibian.name + font.pixelSize: 22 + font.letterSpacing: -0.6 + color: "white" + style: Text.Outline + textFormat: Text.RichText + } + + TapHandler { + enabled: root.parent.state != "candidate" || !root.parent.selectable + onTapped: { + let data = JSON.parse(Backend.callLuaFunction("GetPile", [root.parent.playerid, mark_name])); + data = data.filter((e) => e !== -1); + if (data.length === 0) + return; + + // Just for using room's right drawer + roomScene.startCheat("RoomElement/ViewPile.qml", { + name: mark_name, + ids: data + }); + } + } + } + } + ColumnLayout { id: markTxtList x: 2 spacing: 0 - Repeater { - model: markList - Item { - width: childrenRect.width - height: 22 - Text { - text: Backend.translate(mark_name) + ' ' + Backend.translate(mark_extra) - font.family: fontLibian.name - font.pixelSize: 22 - color: "white" - style: Text.Outline - textFormat: Text.RichText - } - - TapHandler { - enabled: root.parent.state != "candidate" || !root.parent.selectable - onTapped: { - let data = JSON.parse(Backend.callLuaFunction("GetPile", [root.parent.playerid, mark_name])); - data = data.filter((e) => e !== -1); - if (data.length === 0) - return; - - // Just for using room's right drawer - roomScene.startCheat("RoomElement/ViewPile.qml", { - name: mark_name, - ids: data - }); - } - } - } - } } function setMark(mark, data) { @@ -72,6 +74,8 @@ Item { modelItem.mark_extra = data; else markList.append({ mark_name: mark, mark_extra: data }); + + arrangeMarks(); } function removeMark(mark) { @@ -79,8 +83,48 @@ Item { for (i = 0; i < markList.count; i++) { if (markList.get(i).mark_name === mark) { markList.remove(i, 1); + arrangeMarks(); return; } } } + + function arrangeMarks() { + let x = 0; + let y = 0; + let i; + let marks = []; + let long_marks = []; + for (i = 0; i < markRepeater.count; i++) { + let item = markRepeater.itemAt(i); + let w = item.width; + if (w < width / 2) marks.push(item); + else long_marks.push(item); + } + + marks.concat(long_marks).forEach(item => { + let w = item.width; + if (x === 0) { + item.x = x; item.y = y; + + if (w < width / 2) { + x += width / 2; + } else { + x = 0; y += 22; + } + } else { + if (w < width / 2) { + item.x = x; item.y = y; + x = 0; y += 22; + } else { + item.x = 0; item.y = y + 22; + x = 0; y += 44; + } + } + + height = x ? y + 22 : y; + }); + + if (i === 0) height = 0; + } } diff --git a/qml/Pages/RoomLogic.js b/qml/Pages/RoomLogic.js index 2dc1d67c..2bbe9774 100644 --- a/qml/Pages/RoomLogic.js +++ b/qml/Pages/RoomLogic.js @@ -89,10 +89,16 @@ function doCancelButton() { dashboard.enableSkills(); return; } else if (roomScene.state == "responding") { + let p = dashboard.pending_skill; dashboard.stopPending(); dashboard.deactivateSkillButton(); dashboard.unSelectAll(); - replyToServer("__cancel"); + if (roomScene.autoPending || !p) { + replyToServer("__cancel"); + } else { + dashboard.enableCards(roomScene.responding_card); + dashboard.enableSkills(roomScene.responding_card); + } return; } @@ -788,6 +794,7 @@ callbacks["AskForUseActiveSkill"] = function(jsonData) { roomScene.respond_play = false; roomScene.state = "responding"; + roomScene.autoPending = true; dashboard.startPending(skill_name); cancelButton.enabled = cancelable; } @@ -1013,3 +1020,13 @@ callbacks["UpdateLimitSkill"] = (j) => { photo.updateLimitSkill(skill, time); } } + +callbacks["UpdateDrawPile"] = (j) => { + let data = parseInt(j); + roomScene.miscStatus.pileNum = data; +} + +callbacks["UpdateRoundNum"] = (j) => { + let data = parseInt(j); + roomScene.miscStatus.roundNum = data; +} diff --git a/src/main.cpp b/src/main.cpp index baaee9e5..5d818ece 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -106,20 +106,20 @@ void fkMsgHandler(QtMsgType type, const QMessageLogContext &context, switch (type) { case QtDebugMsg: - fprintf(stderr, "[%s/D] %s\n", threadName.constData(), + fprintf(stderr, "%s[D] %s\n", threadName.constData(), localMsg.constData()); break; case QtInfoMsg: - fprintf(stderr, "[%s/%s] %s\n", threadName.constData(), + fprintf(stderr, "%s[%s] %s\n", threadName.constData(), Color("I", Green).toUtf8().constData(), localMsg.constData()); break; case QtWarningMsg: - fprintf(stderr, "[%s/%s] %s\n", threadName.constData(), + fprintf(stderr, "%s[%s] %s\n", threadName.constData(), Color("W", Yellow, Bold).toUtf8().constData(), localMsg.constData()); break; case QtCriticalMsg: - fprintf(stderr, "[%s/%s] %s\n", threadName.constData(), + fprintf(stderr, "%s[%s] %s\n", threadName.constData(), Color("C", Red, Bold).toUtf8().constData(), localMsg.constData()); #ifndef FK_SERVER_ONLY if (Backend != nullptr) { @@ -130,7 +130,7 @@ void fkMsgHandler(QtMsgType type, const QMessageLogContext &context, #endif break; case QtFatalMsg: - fprintf(stderr, "[%s/%s] %s\n", threadName.constData(), + fprintf(stderr, "%s[%s] %s\n", threadName.constData(), Color("E", Red, Bold).toUtf8().constData(), localMsg.constData()); break; }