diff --git a/image/anim/damage/0.png b/image/anim/damage/0.png new file mode 100644 index 00000000..29b05d4d Binary files /dev/null and b/image/anim/damage/0.png differ diff --git a/image/anim/damage/1.png b/image/anim/damage/1.png new file mode 100644 index 00000000..b42dfd60 Binary files /dev/null and b/image/anim/damage/1.png differ diff --git a/image/anim/damage/2.png b/image/anim/damage/2.png new file mode 100644 index 00000000..41c31773 Binary files /dev/null and b/image/anim/damage/2.png differ diff --git a/image/anim/damage/3.png b/image/anim/damage/3.png new file mode 100644 index 00000000..0b369ce4 Binary files /dev/null and b/image/anim/damage/3.png differ diff --git a/image/anim/damage/4.png b/image/anim/damage/4.png new file mode 100644 index 00000000..4f7df1c4 Binary files /dev/null and b/image/anim/damage/4.png differ diff --git a/image/anim/damage/5.png b/image/anim/damage/5.png new file mode 100644 index 00000000..bbcef796 Binary files /dev/null and b/image/anim/damage/5.png differ diff --git a/image/card/delayedTrick/YanxiaoCard.png b/image/card/delayedTrick/YanxiaoCard.png deleted file mode 100644 index e8eeac0c..00000000 Binary files a/image/card/delayedTrick/YanxiaoCard.png and /dev/null differ diff --git a/image/card/delayedTrick/deluge.png b/image/card/delayedTrick/deluge.png deleted file mode 100644 index 9adf30cc..00000000 Binary files a/image/card/delayedTrick/deluge.png and /dev/null differ diff --git a/image/card/delayedTrick/earthquake.png b/image/card/delayedTrick/earthquake.png deleted file mode 100644 index 6597331b..00000000 Binary files a/image/card/delayedTrick/earthquake.png and /dev/null differ diff --git a/image/card/delayedTrick/indulgence.png b/image/card/delayedTrick/indulgence.png index 9301c4dd..59a0b135 100644 Binary files a/image/card/delayedTrick/indulgence.png and b/image/card/delayedTrick/indulgence.png differ diff --git a/image/card/delayedTrick/lightning.png b/image/card/delayedTrick/lightning.png index be86598d..0c0f0c37 100644 Binary files a/image/card/delayedTrick/lightning.png and b/image/card/delayedTrick/lightning.png differ diff --git a/image/card/delayedTrick/mudslide.png b/image/card/delayedTrick/mudslide.png deleted file mode 100644 index e76710bd..00000000 Binary files a/image/card/delayedTrick/mudslide.png and /dev/null differ diff --git a/image/card/delayedTrick/supply_shortage.png b/image/card/delayedTrick/supply_shortage.png index cd375a8b..f0ec8578 100644 Binary files a/image/card/delayedTrick/supply_shortage.png and b/image/card/delayedTrick/supply_shortage.png differ diff --git a/image/card/delayedTrick/typhoon.png b/image/card/delayedTrick/typhoon.png deleted file mode 100644 index 8ec700fb..00000000 Binary files a/image/card/delayedTrick/typhoon.png and /dev/null differ diff --git a/image/card/delayedTrick/volcano.png b/image/card/delayedTrick/volcano.png deleted file mode 100644 index e1b6b8f2..00000000 Binary files a/image/card/delayedTrick/volcano.png and /dev/null differ diff --git a/image/card/double_sword.png b/image/card/double_swords.png similarity index 100% rename from image/card/double_sword.png rename to image/card/double_swords.png diff --git a/image/card/equipIcon/ico_28.png b/image/card/equipIcon/axe.png similarity index 100% rename from image/card/equipIcon/ico_28.png rename to image/card/equipIcon/axe.png diff --git a/image/card/equipIcon/ico_26.png b/image/card/equipIcon/blade.png similarity index 100% rename from image/card/equipIcon/ico_26.png rename to image/card/equipIcon/blade.png diff --git a/image/card/equipIcon/ico_23.png b/image/card/equipIcon/crossbow.png similarity index 100% rename from image/card/equipIcon/ico_23.png rename to image/card/equipIcon/crossbow.png diff --git a/image/card/equipIcon/ico_24.png b/image/card/equipIcon/double_sword.png similarity index 100% rename from image/card/equipIcon/ico_24.png rename to image/card/equipIcon/double_sword.png diff --git a/image/card/equipIcon/ico_16.png b/image/card/equipIcon/eight_diagram.png similarity index 100% rename from image/card/equipIcon/ico_16.png rename to image/card/equipIcon/eight_diagram.png diff --git a/image/card/equipIcon/ico_38.png b/image/card/equipIcon/fan.png similarity index 100% rename from image/card/equipIcon/ico_38.png rename to image/card/equipIcon/fan.png diff --git a/image/card/equipIcon/ico_37.png b/image/card/equipIcon/guding_blade.png similarity index 100% rename from image/card/equipIcon/ico_37.png rename to image/card/equipIcon/guding_blade.png diff --git a/image/card/equipIcon/ico_29.png b/image/card/equipIcon/halberd.png similarity index 100% rename from image/card/equipIcon/ico_29.png rename to image/card/equipIcon/halberd.png diff --git a/image/card/equipIcon/horse_flag.png b/image/card/equipIcon/horse.png similarity index 100% rename from image/card/equipIcon/horse_flag.png rename to image/card/equipIcon/horse.png diff --git a/image/card/equipIcon/ico_32.png b/image/card/equipIcon/ice_sword.png similarity index 100% rename from image/card/equipIcon/ico_32.png rename to image/card/equipIcon/ice_sword.png diff --git a/image/card/equipIcon/ico_101.png b/image/card/equipIcon/ico_101.png deleted file mode 100644 index a0a37575..00000000 Binary files a/image/card/equipIcon/ico_101.png and /dev/null differ diff --git a/image/card/equipIcon/ico_102.png b/image/card/equipIcon/ico_102.png deleted file mode 100644 index 2dc9c3bd..00000000 Binary files a/image/card/equipIcon/ico_102.png and /dev/null differ diff --git a/image/card/equipIcon/ico_11048.png b/image/card/equipIcon/ico_11048.png deleted file mode 100644 index 3b3892e3..00000000 Binary files a/image/card/equipIcon/ico_11048.png and /dev/null differ diff --git a/image/card/equipIcon/ico_11049.png b/image/card/equipIcon/ico_11049.png deleted file mode 100644 index 51d0915c..00000000 Binary files a/image/card/equipIcon/ico_11049.png and /dev/null differ diff --git a/image/card/equipIcon/ico_11050.png b/image/card/equipIcon/ico_11050.png deleted file mode 100644 index 0c0a34fe..00000000 Binary files a/image/card/equipIcon/ico_11050.png and /dev/null differ diff --git a/image/card/equipIcon/ico_11051.png b/image/card/equipIcon/ico_11051.png deleted file mode 100644 index a98266b3..00000000 Binary files a/image/card/equipIcon/ico_11051.png and /dev/null differ diff --git a/image/card/equipIcon/ico_11052.png b/image/card/equipIcon/ico_11052.png deleted file mode 100644 index c370c065..00000000 Binary files a/image/card/equipIcon/ico_11052.png and /dev/null differ diff --git a/image/card/equipIcon/ico_11161.png b/image/card/equipIcon/ico_11161.png deleted file mode 100644 index ee500736..00000000 Binary files a/image/card/equipIcon/ico_11161.png and /dev/null differ diff --git a/image/card/equipIcon/ico_11179.png b/image/card/equipIcon/ico_11179.png deleted file mode 100644 index 7fe5a75e..00000000 Binary files a/image/card/equipIcon/ico_11179.png and /dev/null differ diff --git a/image/card/equipIcon/ico_11200.png b/image/card/equipIcon/ico_11200.png deleted file mode 100644 index 23856b44..00000000 Binary files a/image/card/equipIcon/ico_11200.png and /dev/null differ diff --git a/image/card/equipIcon/ico_11228.png b/image/card/equipIcon/ico_11228.png deleted file mode 100644 index b908d6d9..00000000 Binary files a/image/card/equipIcon/ico_11228.png and /dev/null differ diff --git a/image/card/equipIcon/ico_11229.png b/image/card/equipIcon/ico_11229.png deleted file mode 100644 index 9e47948c..00000000 Binary files a/image/card/equipIcon/ico_11229.png and /dev/null differ diff --git a/image/card/equipIcon/ico_11230.png b/image/card/equipIcon/ico_11230.png deleted file mode 100644 index 752a4d56..00000000 Binary files a/image/card/equipIcon/ico_11230.png and /dev/null differ diff --git a/image/card/equipIcon/ico_11231.png b/image/card/equipIcon/ico_11231.png deleted file mode 100644 index 204866e8..00000000 Binary files a/image/card/equipIcon/ico_11231.png and /dev/null differ diff --git a/image/card/equipIcon/ico_11232.png b/image/card/equipIcon/ico_11232.png deleted file mode 100644 index b20cdb06..00000000 Binary files a/image/card/equipIcon/ico_11232.png and /dev/null differ diff --git a/image/card/equipIcon/ico_11233.png b/image/card/equipIcon/ico_11233.png deleted file mode 100644 index 96cda0d0..00000000 Binary files a/image/card/equipIcon/ico_11233.png and /dev/null differ diff --git a/image/card/equipIcon/ico_11234.png b/image/card/equipIcon/ico_11234.png deleted file mode 100644 index 6ad37f39..00000000 Binary files a/image/card/equipIcon/ico_11234.png and /dev/null differ diff --git a/image/card/equipIcon/ico_12052.png b/image/card/equipIcon/ico_12052.png deleted file mode 100644 index 9cd88034..00000000 Binary files a/image/card/equipIcon/ico_12052.png and /dev/null differ diff --git a/image/card/equipIcon/ico_48.png b/image/card/equipIcon/ico_48.png deleted file mode 100644 index d5994f5e..00000000 Binary files a/image/card/equipIcon/ico_48.png and /dev/null differ diff --git a/image/card/equipIcon/ico_49.png b/image/card/equipIcon/ico_49.png deleted file mode 100644 index 997c69d5..00000000 Binary files a/image/card/equipIcon/ico_49.png and /dev/null differ diff --git a/image/card/equipIcon/ico_580.png b/image/card/equipIcon/ico_580.png deleted file mode 100644 index 18ef90b5..00000000 Binary files a/image/card/equipIcon/ico_580.png and /dev/null differ diff --git a/image/card/equipIcon/ico_30.png b/image/card/equipIcon/kylin_bow.png similarity index 100% rename from image/card/equipIcon/ico_30.png rename to image/card/equipIcon/kylin_bow.png diff --git a/image/card/equipIcon/ico_25.png b/image/card/equipIcon/qinggang_sword.png similarity index 100% rename from image/card/equipIcon/ico_25.png rename to image/card/equipIcon/qinggang_sword.png diff --git a/image/card/equipIcon/ico_31.png b/image/card/equipIcon/renwang_shield.png similarity index 100% rename from image/card/equipIcon/ico_31.png rename to image/card/equipIcon/renwang_shield.png diff --git a/image/card/equipIcon/ico_40.png b/image/card/equipIcon/silver_lion.png similarity index 100% rename from image/card/equipIcon/ico_40.png rename to image/card/equipIcon/silver_lion.png diff --git a/image/card/equipIcon/ico_27.png b/image/card/equipIcon/spear.png similarity index 100% rename from image/card/equipIcon/ico_27.png rename to image/card/equipIcon/spear.png diff --git a/image/card/equipIcon/ico_0.png b/image/card/equipIcon/unknown.png similarity index 100% rename from image/card/equipIcon/ico_0.png rename to image/card/equipIcon/unknown.png diff --git a/image/card/equipIcon/ico_39.png b/image/card/equipIcon/vine.png similarity index 100% rename from image/card/equipIcon/ico_39.png rename to image/card/equipIcon/vine.png diff --git a/image/card/renwang_shield.png b/image/card/nioh_shield.png similarity index 100% rename from image/card/renwang_shield.png rename to image/card/nioh_shield.png diff --git a/lua/client/client.lua b/lua/client/client.lua index 4f1f4808..19f6dfe5 100644 --- a/lua/client/client.lua +++ b/lua/client/client.lua @@ -1,3 +1,6 @@ +---@class Client +---@field client fk.Client +---@field players ClientPlayer[] Client = class('Client') -- load client classes @@ -23,6 +26,15 @@ function Client:initialize() self.players = {} -- ClientPlayer[] end +---@param id integer +---@return ClientPlayer +function Client:findPlayer(id) + for _, p in ipairs(self.players) do + if p.player:getId() == id then return p end + end + return nil +end + fk.client_callback["Setup"] = function(jsonData) -- jsonData: [ int id, string screenName, string avatar ] local data = json.decode(jsonData) @@ -31,6 +43,8 @@ fk.client_callback["Setup"] = function(jsonData) self:setId(id) self:setScreenName(name) self:setAvatar(avatar) + Self = ClientPlayer:new(fk.Self) + table.insert(ClientInstance.players, Self) end fk.client_callback["AddPlayer"] = function(jsonData) @@ -47,13 +61,13 @@ fk.client_callback["RemovePlayer"] = function(jsonData) -- jsonData: [ int id ] local data = json.decode(jsonData) local id = data[1] - fk.ClientInstance:removePlayer(id) for _, p in ipairs(ClientInstance.players) do if p.player:getId() == id then table.removeOne(ClientInstance.players, p) break end end + fk.ClientInstance:removePlayer(id) ClientInstance:notifyUI("RemovePlayer", jsonData) end @@ -61,20 +75,70 @@ fk.client_callback["ArrangeSeats"] = function(jsonData) local data = json.decode(jsonData) local n = #ClientInstance.players local players = {} - local function findPlayer(id) - for _, p in ipairs(ClientInstance.players) do - if p.player:getId() == id then return p end - end - return nil - end for i = 1, n do - table.insert(players, findPlayer(data[i])) + table.insert(players, ClientInstance:findPlayer(data[i])) end ClientInstance.players = players ClientInstance:notifyUI("ArrangeSeats", jsonData) end +fk.client_callback["PropertyUpdate"] = function(jsonData) + -- jsonData: [ int id, string property_name, value ] + local data = json.decode(jsonData) + local id, name, value = data[1], data[2], data[3] + ClientInstance:findPlayer(id)[name] = value + ClientInstance:notifyUI("PropertyUpdate", jsonData) +end + +--- separated moves to many moves(one card per move) +---@param moves CardsMoveStruct[] +local function separateMoves(moves) + local ret = {} ---@type CardsMoveInfo[] + for _, move in ipairs(moves) do + for _, info in ipairs(move.moveInfo) do + table.insert(ret, { + ids = {info.cardId}, + from = move.from, + to = move.to, + toArea = move.toArea, + fromArea = info.fromArea, + }) + end + end + return ret +end + +--- merge separated moves (one fromArea per move) +local function mergeMoves(moves) + local ret = {} + local temp = {} + for _, move in ipairs(moves) do + if temp[move.fromArea] == nil then + temp[move.fromArea] = { + ids = {}, + from = move.from, + to = move.to, + fromArea = move.fromArea, + toArea = move.toArea + } + end + table.insert(temp[move.fromArea].ids, move.ids[1]) + end + for _, v in pairs(temp) do + table.insert(ret, v) + end + return ret +end + +fk.client_callback["MoveCards"] = function(jsonData) + -- jsonData: CardsMoveStruct[] + local raw_moves = json.decode(jsonData) + local separated = separateMoves(raw_moves) + local merged = mergeMoves(separated) + ClientInstance:notifyUI("MoveCards", json.encode(merged)) +end + -- Create ClientInstance (used by Lua) ClientInstance = Client:new() diff --git a/lua/client/client_util.lua b/lua/client/client_util.lua index 7f76a612..ffeac518 100644 --- a/lua/client/client_util.lua +++ b/lua/client/client_util.lua @@ -9,3 +9,18 @@ function GetGeneralData(name) general.kingdom } end + +function GetCardData(id) + local card = Fk.cards[id] + if card == nil then return json.encode{ + cid = id, + known = false + } end + return json.encode{ + cid = id, + name = card.name, + number = card.number, + suit = card:getSuitString(), + color = card.color, + } +end diff --git a/lua/client/clientplayer.lua b/lua/client/clientplayer.lua index 6d451770..e2c575d6 100644 --- a/lua/client/clientplayer.lua +++ b/lua/client/clientplayer.lua @@ -1,7 +1,13 @@ +---@class ClientPlayer +---@field player fk.Player +---@field handcardNum integer +---@field known_cards integer[] local ClientPlayer = Player:subclass("ClientPlayer") function ClientPlayer:initialize(cp) self.player = cp + self.handcardNum = 0 + self.known_cards = {} end return ClientPlayer diff --git a/lua/core/card.lua b/lua/core/card.lua index 68a27b0f..c288c61b 100644 --- a/lua/core/card.lua +++ b/lua/core/card.lua @@ -74,4 +74,19 @@ function Card:initialize(name, suit, number, color) self.sub_type = Card.SubTypeNone end +function Card:getSuitString() + local suit = self.suit + if suit == Card.Spade then + return "spade" + elseif suit == Card.Heart then + return "heart" + elseif suit == Card.Club then + return "club" + elseif suit == Card.Diamond then + return "diamond" + else + return "unknown" + end +end + return Card diff --git a/lua/core/debug.lua b/lua/core/debug.lua index 04dd4b7e..638dee0a 100644 --- a/lua/core/debug.lua +++ b/lua/core/debug.lua @@ -17,3 +17,4 @@ end --debug.sethook(PrintWhenMethodCall, "c") function p(v) print(inspect(v)) end +function pt(t) for k,v in pairs(t)do print(k,v) end end diff --git a/lua/core/util.lua b/lua/core/util.lua index 26178b56..13b0cbdc 100644 --- a/lua/core/util.lua +++ b/lua/core/util.lua @@ -49,6 +49,23 @@ function table:removeOne(element) return false end +-- Note: only clone key and value, no metatable +-- so dont use for class or instance +---@generic T +---@param self T +---@return T +function table.clone(self) + local ret = {} + for k, v in pairs(self) do + if type(v) == "table" then + ret[k] = table.clone(v) + else + ret[k] = v + end + end + return ret +end + ---@class Sql Sql = { ---@param filename string diff --git a/lua/server/room.lua b/lua/server/room.lua index 2431c2da..82a5db69 100644 --- a/lua/server/room.lua +++ b/lua/server/room.lua @@ -219,6 +219,42 @@ function Room:getCardArea(cardId) return self.card_place[cardId] or Card.Unknown end +---@param players ServerPlayer[] +---@param card_moves CardsMoveStruct[] +---@param forceVisible boolean +function Room:notifyMoveCards(players, card_moves, forceVisible) + if players == nil or players == {} then players = self.players end + for _, p in ipairs(players) do + local arg = table.clone(card_moves) + for _, move in ipairs(arg) do + -- local to = self:getPlayerById(move.to) + + -- forceVisible make the move visible + -- FIXME: move.moveInfo is an array, fix this + move.moveVisible = (forceVisible) + -- if move is relevant to player, it should be open + or ((move.from == p:getId()) or (move.to == p:getId() and move.toArea ~= Card.PlayerSpecial)) + -- cards move from/to equip/judge/discard/processing should be open + or move.moveInfo.fromArea == Card.PlayerEquip + or move.toArea == Card.PlayerEquip + or move.moveInfo.fromArea == Card.PlayerJudge + or move.toArea == Card.PlayerJudge + or move.moveInfo.fromArea == Card.DiscardPile + or move.toArea == Card.DiscardPile + or move.moveInfo.fromArea == Card.Processing + or move.toArea == Card.Processing + -- TODO: PlayerSpecial + + if not move.moveVisible then + for _, info in ipairs(move.moveInfo) do + info.cardId = -1 + end + end + end + p:doNotify("MoveCards", json.encode(arg)) + end +end + ---@vararg CardsMoveInfo ---@return boolean function Room:moveCards(...) @@ -266,6 +302,8 @@ function Room:moveCards(...) return false end + self:notifyMoveCards(self.players, cardsMoveStructs) + for _, data in ipairs(cardsMoveStructs) do if #data.moveInfo > 0 then infoCheck(data) diff --git a/lua/server/system_enum.lua b/lua/server/system_enum.lua index 39628169..ddb13229 100644 --- a/lua/server/system_enum.lua +++ b/lua/server/system_enum.lua @@ -1,6 +1,6 @@ ---@alias CardsMoveInfo {ids: integer[], from: integer|null, to: integer|null, toArea: CardArea, moveReason: CardMoveReason, proposer: integer, skillName: string|null, moveVisible: boolean|null, specialName: string|null, specialVisible: boolean|null } ---@alias MoveInfo {cardId: integer, fromArea: CardArea} ----@alias CardsMoveStruct {moveInfo: {id: integer, fromArea: CardArea}[], from: integer|null, to: integer|null, toArea: CardArea, moveReason: CardMoveReason, proposer: integer|null, skillName: string|null, moveVisible: boolean|null, specialName: string|null, specialVisible: boolean|null, fromSpecialName: string|null } +---@alias CardsMoveStruct {moveInfo: MoveInfo[], from: integer|null, to: integer|null, toArea: CardArea, moveReason: CardMoveReason, proposer: integer|null, skillName: string|null, moveVisible: boolean|null, specialName: string|null, specialVisible: boolean|null, fromSpecialName: string|null } ---@alias HpChangedData { num: integer, reason: string, skillName: string } ---@alias HpLostData { num: integer, skillName: string } diff --git a/packages/standard/game_rule.lua b/packages/standard/game_rule.lua index efc99486..a82eb846 100644 --- a/packages/standard/game_rule.lua +++ b/packages/standard/game_rule.lua @@ -31,6 +31,15 @@ GameRule = fk.CreateTriggerSkill{ -- TODO: need a new function to call the UI local cardIds = room:getNCards(data.num) player:addCards(Player.Hand, cardIds) + local move_to_notify = {} ---@type CardsMoveStruct + move_to_notify.toArea = Card.PlayerHand + move_to_notify.to = player:getId() + move_to_notify.moveInfo = {} + for _, id in ipairs(cardIds) do + table.insert(move_to_notify.moveInfo, + { cardId = id, fromArea = Card.DrawPile }) + end + room:notifyMoveCards(room.players, {move_to_notify}) for _, id in ipairs(cardIds) do room:setCardArea(id, Card.PlayerHand) @@ -62,34 +71,31 @@ GameRule = fk.CreateTriggerSkill{ error("You should never proceed PhaseNone") end, [Player.RoundStart] = function() - print("Proceeding RoundStart.") + end, [Player.Start] = function() - print("Proceeding Start.") + end, [Player.Judge] = function() - print("Proceeding Judge.") + end, [Player.Draw] = function() - print("Proceeding Draw.") room:drawCards(player, 2, self.name) end, [Player.Play] = function() - print("Proceeding Play.") room:askForSkillInvoke(player, "rule") end, [Player.Discard] = function() - print("Proceeding Discard.") local discardNum = #player:getCardIds(Player.Hand) - player:getMaxCards() if discardNum > 0 then room:askForDiscard(player, discardNum, discardNum, false, self.name) end end, [Player.Finish] = function() - print("Proceeding Finish.") + end, [Player.NotActive] = function() - print("Proceeding NotActive.") + end, }) end, diff --git a/qml/Pages/Room.qml b/qml/Pages/Room.qml index 06f41943..0a5c1d16 100644 --- a/qml/Pages/Room.qml +++ b/qml/Pages/Room.qml @@ -17,6 +17,22 @@ Item { property alias promptText: prompt.text // tmp + Row { + Button{text:"摸1牌" + onClicked:{ + Logic.moveCards([{ + from:Logic.Player.DrawPile, + to:Logic.Player.PlaceHand, + cards:[1], + }]) + }} + Button{text:"弃1牌" + onClicked:{Logic.moveCards([{ + to:Logic.Player.DrawPile, + from:Logic.Player.PlaceHand, + cards:[1], + }])}} + } Button { text: "quit" anchors.top: parent.top @@ -145,7 +161,7 @@ Item { width: parent.width * 0.6 height: 150 x: parent.width * 0.2 - y: parent.height * 0.5 + y: parent.height * 0.6 } } diff --git a/qml/Pages/RoomElement/CardItem.qml b/qml/Pages/RoomElement/CardItem.qml index 0e4a2951..d9d15b1b 100644 --- a/qml/Pages/RoomElement/CardItem.qml +++ b/qml/Pages/RoomElement/CardItem.qml @@ -21,8 +21,9 @@ Item { property string suit: "club" property int number: 7 property string name: "slash" + property string subtype: "" property string color: "" // only use when suit is empty - property string footnote: "曹操对刘备" // footnote, e.g. "A use card to B" + property string footnote: "" // footnote, e.g. "A use card to B" property bool footnoteVisible: true property bool known: true // if false it only show a card back property bool enabled: true // if false the card will be grey @@ -247,7 +248,7 @@ Item { function destroyOnStop() { root.moveFinished.connect(function(){ - destroy(); + root.destroy(); }); } } diff --git a/qml/Pages/RoomElement/Dashboard.qml b/qml/Pages/RoomElement/Dashboard.qml index 829c6266..cac9f336 100644 --- a/qml/Pages/RoomElement/Dashboard.qml +++ b/qml/Pages/RoomElement/Dashboard.qml @@ -6,15 +6,25 @@ RowLayout { id: root property alias self: selfPhoto + property alias handcardArea: handcardAreaItem + property alias equipArea: selfPhoto.equipArea + property alias delayedTrickArea: selfPhoto.delayedTrickArea + property alias specialArea: selfPhoto.specialArea + + Item { + width: 40 + } HandcardArea { id: handcardAreaItem Layout.fillWidth: true - Layout.fillHeight: true + Layout.preferredHeight: 130 + Layout.alignment: Qt.AlignVCenter } Photo { id: selfPhoto + handcards: handcardAreaItem.length } Item { width: 5 } diff --git a/qml/Pages/RoomElement/HandcardArea.qml b/qml/Pages/RoomElement/HandcardArea.qml index c9744f93..839bd81e 100644 --- a/qml/Pages/RoomElement/HandcardArea.qml +++ b/qml/Pages/RoomElement/HandcardArea.qml @@ -1,4 +1,5 @@ import QtQuick 2.15 +import "../../util.js" as Utility Item { property alias cards: cardArea.cards @@ -68,12 +69,12 @@ Item { for (i = 0; i < cards.length; i++) { card = cards[i]; if (card.selected) - card.homeY -= 20; + card.origY -= 20; } if (animated) { for (i = 0; i < cards.length; i++) - roomScene.cardItemGoBack(cards[i], true) + cards[i].goBack(true) } } diff --git a/qml/Pages/RoomElement/IndicatorLine.qml b/qml/Pages/RoomElement/IndicatorLine.qml new file mode 100644 index 00000000..9c4ad5dc --- /dev/null +++ b/qml/Pages/RoomElement/IndicatorLine.qml @@ -0,0 +1,101 @@ +import QtQuick 2.15 + +Item { + property point start: Qt.point(0, 0) + property var end: [] + property alias running: pointToAnimation.running + property color color: "#96943D" + property real ratio: 0 + property int lineWidth: 6 + + signal finished() + + id: root + anchors.fill: parent + + Repeater { + model: end + + Rectangle { + width: 6 + height: Math.sqrt(Math.pow(modelData.x - start.x, 2) + Math.pow(modelData.y - start.y, 2)) * ratio + x: start.x + y: start.y + antialiasing: true + + gradient: Gradient { + GradientStop { + position: 0 + color: Qt.rgba(255, 255, 255, 0) + } + GradientStop { + position: 1 + color: Qt.rgba(200, 200, 200, 0.12) + } + } + + Rectangle { + anchors.horizontalCenter: parent.horizontalCenter + width: 3 + height: parent.height + antialiasing: true + + gradient: Gradient { + GradientStop { + position: 0 + color: Qt.rgba(255, 255, 255, 0) + } + GradientStop { + position: 1 + color: Qt.lighter(root.color) + } + } + } + + transform: Rotation { + angle: 0 + + Component.onCompleted: { + var dx = modelData.x - start.x; + var dy = modelData.y - start.y; + if (dx > 0) { + angle = Math.atan2(dy, dx) / Math.PI * 180 - 90; + } else if (dx < 0) { + angle = Math.atan2(dy, dx) / Math.PI * 180 + 270; + } else if (dy < 0) { + angle = 180; + } + } + } + } + } + + SequentialAnimation { + id: pointToAnimation + + PropertyAnimation { + target: root + property: "ratio" + to: 1 + easing.type: Easing.OutCubic + duration: 200 + } + + PauseAnimation { + duration: 200 + } + + PropertyAnimation { + target: root + property: "opacity" + to: 0 + easing.type: Easing.InQuart + duration: 300 + } + + onStopped: { + root.visible = false; + root.finished(); + } + } +} diff --git a/qml/Pages/RoomElement/InvisibleCardArea.qml b/qml/Pages/RoomElement/InvisibleCardArea.qml index 0b329b49..67561bb2 100644 --- a/qml/Pages/RoomElement/InvisibleCardArea.qml +++ b/qml/Pages/RoomElement/InvisibleCardArea.qml @@ -57,7 +57,7 @@ Item { let items = []; for (let i = 0; i < outputs.length; i++) { if (_contains(outputs[i])) { - let state = JSON.parse(Sanguosha.getCard4Qml(outputs[i])) + let state = JSON.parse(Backend.getCardData(outputs[i])) state.x = parentPos.x; state.y = parentPos.y; state.opacity = 0; diff --git a/qml/Pages/RoomElement/Photo.qml b/qml/Pages/RoomElement/Photo.qml index 52889b22..a060986e 100644 --- a/qml/Pages/RoomElement/Photo.qml +++ b/qml/Pages/RoomElement/Photo.qml @@ -14,7 +14,7 @@ Item { property string role: "unknown" property string kingdom: "qun" property string netstate: "online" - property int handcards: 0 + property alias handcards: handcardAreaItem.length property int maxHp: 0 property int hp: 0 property int seatNumber: 1 @@ -24,10 +24,19 @@ Item { property bool chained: false property bool drank: false property bool isOwner: false + property string status: "normal" + + property alias handcardArea: handcardAreaItem + property alias equipArea: equipAreaItem + property alias delayedTrickArea: delayedTrickAreaItem + property alias specialArea: handcardAreaItem property alias progressBar: progressBar property alias progressTip: progressTip.text + property bool selectable: false + property bool selected: false + Behavior on x { NumberAnimation { duration: 600; easing.type: Easing.InOutQuad } } @@ -36,6 +45,14 @@ Item { NumberAnimation { duration: 600; easing.type: Easing.InOutQuad } } + PixmapAnimation { + id: animFrame + source: "selected" + anchors.centerIn: parent + loop: true + scale: 1.1 + } + Image { id: back source: SkinBank.PHOTO_BACK_DIR + root.kingdom @@ -108,6 +125,18 @@ Item { visible: screenName != "" && !roomScene.isStarted } + Image { + visible: equipAreaItem.length > 0 + source: SkinBank.PHOTO_DIR + "equipbg" + x: 31 + y: 121 + } + + Image { + source: root.status != "normal" ? SkinBank.STATUS_DIR + root.status : "" + x: -6 + } + Image { id: turnedOver visible: !root.faceup @@ -115,6 +144,13 @@ Item { x: 29; y: 5 } + EquipArea { + id: equipAreaItem + + x: 31 + y: 139 + } + Image { id: chain visible: root.chained @@ -244,6 +280,30 @@ Item { } } + PixmapAnimation { + id: animSelectable + source: "selectable" + anchors.centerIn: parent + loop: true + } + + InvisibleCardArea { + id: handcardAreaItem + anchors.centerIn: parent + } + + DelayedTrickArea { + id: delayedTrickAreaItem + rows: 1 + anchors.bottom: parent.bottom + anchors.bottomMargin: 8 + } + + InvisibleCardArea { + id: defaultArea + anchors.centerIn: parent + } + onGeneralChanged: { if (!roomScene.isStarted) return; generalName.text = Backend.translate(general); diff --git a/qml/Pages/RoomElement/PhotoElement/DelayedTrickArea.qml b/qml/Pages/RoomElement/PhotoElement/DelayedTrickArea.qml index 8b137891..87070c93 100644 --- a/qml/Pages/RoomElement/PhotoElement/DelayedTrickArea.qml +++ b/qml/Pages/RoomElement/PhotoElement/DelayedTrickArea.qml @@ -1 +1,65 @@ +import QtQuick 2.15 +import ".." +import "../../skin-bank.js" as SkinBank + +Item { + property alias rows: grid.rows + property alias columns: grid.columns + + InvisibleCardArea { + id: area + checkExisting: true + } + + ListModel { + id: cards + } + + Grid { + id: grid + anchors.fill: parent + rows: 100 + columns: 100 + + Repeater { + model: cards + + Image { + source: SkinBank.DELAYED_TRICK_DIR + name + } + } + } + + function add(inputs) + { + area.add(inputs); + if (inputs instanceof Array) { + cards.append(...inputs); + } else { + cards.append(inputs); + } + } + + function remove(outputs) + { + let result = area.remove(outputs); + for (let i = 0; i < result.length; i++) { + let item = result[i]; + for (let j = 0; j < cards.count; j++) { + let icon = cards.get(j); + if (icon.cid === item.cid) { + cards.remove(j, 1); + break; + } + } + } + + return result; + } + + function updateCardPosition(animated) + { + area.updateCardPosition(animated); + } +} diff --git a/qml/Pages/RoomElement/PhotoElement/EquipArea.qml b/qml/Pages/RoomElement/PhotoElement/EquipArea.qml index 8b137891..c3be0ba6 100644 --- a/qml/Pages/RoomElement/PhotoElement/EquipArea.qml +++ b/qml/Pages/RoomElement/PhotoElement/EquipArea.qml @@ -1 +1,120 @@ +import QtQuick 2.15 +import ".." +import "../../skin-bank.js" as SkinBank + +/* Layout of EquipArea: + * | Treasure | + | Weapon | + | Armor | + | +1 | -1 | + +---------------+ + */ + +Column { + height: 88 + width: 138 + property int itemHeight: Math.floor(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 + + InvisibleCardArea { + id: area + checkExisting: true + } + + EquipItem { + id: treasureItem + width: parent.width + height: itemHeight + opacity: 0 + } + + EquipItem { + id: weaponItem + width: parent.width + height: itemHeight + opacity: 0 + } + + EquipItem { + id: armorItem + width: parent.width + height: itemHeight + opacity: 0 + } + + Row { + width: parent.width + height: itemHeight + + Item { + width: Math.ceil(parent.width / 2) + height: itemHeight + + EquipItem { + id: defensiveHorseItem + width: parent.width + height: itemHeight + icon: "horse" + opacity: 0 + } + } + + Item { + width: Math.floor(parent.width / 2) + height: itemHeight + + EquipItem { + id: offensiveHorseItem + width: parent.width + height: itemHeight + icon: "horse" + opacity: 0 + } + } + } + + function add(inputs) + { + area.add(inputs); + + let card, item; + if (inputs instanceof Array) { + for (let i = 0; i < inputs.length; i++) { + card = inputs[i]; + item = items[subtypes.indexOf(card.subtype)]; + item.setCard(card); + item.show(); + } + } else { + card = inputs; + item = items[subtypes.indexOf(card.subtype)]; + item.setCard(card); + item.show(); + } + } + + function remove(outputs) + { + let result = area.remove(outputs); + for (let i = 0; i < result.length; i++) { + let card = result[i]; + for (let j = 0; j < items.length; j++) { + let item = items[j]; + if (item.cid === card.cid) { + item.reset(); + item.hide(); + } + } + } + + return result; + } + + function updateCardPosition(animated) + { + area.updateCardPosition(animated); + } +} diff --git a/qml/Pages/RoomElement/PhotoElement/EquipItem.qml b/qml/Pages/RoomElement/PhotoElement/EquipItem.qml new file mode 100644 index 00000000..e4bbb0cc --- /dev/null +++ b/qml/Pages/RoomElement/PhotoElement/EquipItem.qml @@ -0,0 +1,142 @@ +import QtQuick 2.15 +import ".." +import "../../../util.js" as Utility +import "../../skin-bank.js" as SkinBank + +Item { + property int cid: 0 + property string name: "" + property string suit: "" + property int number: 0 + + property string icon: "" + property alias text: textItem.text + + id: root + + Image { + id: iconItem + anchors.verticalCenter: parent.verticalCenter + x: 3 + + source: icon ? SkinBank.EQUIP_ICON_DIR + icon : "" + } + + Image { + id: suitItem + anchors.right: parent.right + source: suit ? SkinBank.CARD_SUIT_DIR + suit : "" + width: implicitWidth / implicitHeight * height + height: 16 + } + + GlowText { + id: numberItem + visible: number > 0 && number < 14 + text: Utility.convertNumber(number) + color: "white" + font.family: "FZLiBian-S02" + font.pixelSize: 16 + glow.color: "black" + glow.spread: 0.75 + glow.radius: 2 + glow.samples: 4 + x: parent.width - 24 + y: 1 + } + + GlowText { + id: textItem + font.family: "FZLiBian-S02" + color: "white" + font.pixelSize: 18 + glow.color: "black" + glow.spread: 0.9 + glow.radius: 2 + glow.samples: 6 + anchors.left: iconItem.right + anchors.leftMargin: -8 + verticalAlignment: Text.AlignVCenter + } + + ParallelAnimation { + id: showAnime + + NumberAnimation { + target: root + property: "x" + duration: 200 + easing.type: Easing.InOutQuad + from: 10 + to: 0 + } + + NumberAnimation { + target: root + property: "opacity" + duration: 200 + easing.type: Easing.InOutQuad + from: 0 + to: 1 + } + } + + ParallelAnimation { + id: hideAnime + + NumberAnimation { + target: root + property: "x" + duration: 200 + easing.type: Easing.InOutQuad + from: 0 + to: 10 + } + + NumberAnimation { + target: root + property: "opacity" + duration: 200 + easing.type: Easing.InOutQuad + from: 1 + to: 0 + } + } + + function reset() + { + cid = 0; + name = ""; + suit = ""; + number = 0; + text = ""; + } + + function setCard(card) + { + cid = card.cid; + name = card.name; + suit = card.suit; + number = card.number; + if (card.subtype === "defensive_horse") { + text = "+1"; + icon = "horse"; + } else if (card.subtype === "offensive_horse") { + text = "-1" + icon = "horse"; + } else { + text = name; + icon = name; + } + } + + function show() + { + showAnime.start(); + } + + function hide() + { + hideAnime.start(); + } +} diff --git a/qml/Pages/RoomElement/PixmapAnimation.qml b/qml/Pages/RoomElement/PixmapAnimation.qml new file mode 100644 index 00000000..f2ebc003 --- /dev/null +++ b/qml/Pages/RoomElement/PixmapAnimation.qml @@ -0,0 +1,89 @@ +import QtQuick 2.15 +import Qt.labs.folderlistmodel 2.15 +import "../skin-bank.js" as SkinBank + +Item { + property string source: "" + property int currentFrame: 0 + property alias interval: timer.interval + property int loadedFrameCount: 0 + property bool autoStart: false + property bool loop: false + + signal loaded() + signal started() + signal finished() + + id: root + width: childrenRect.width + height: childrenRect.height + + FolderListModel { + id: fileModel + folder: SkinBank.PIXANIM_DIR + source + nameFilters: ["*.png"] + showDirs: false + } + + Repeater { + id: frames + model: fileModel + + Image { + source: SkinBank.PIXANIM_DIR + root.source + "/" + index + visible: false + onStatusChanged: { + if (status == Image.Ready) { + loadedFrameCount++; + if (loadedFrameCount == fileModel.count) + root.loaded(); + } + } + } + } + + onLoaded: { + if (autoStart) + timer.start(); + } + + Timer { + id: timer + interval: 50 + repeat: true + onTriggered: { + if (currentFrame >= fileModel.count) { + frames.itemAt(fileModel.count - 1).visible = false; + if (loop) { + currentFrame = 0; + } else { + timer.stop(); + root.finished(); + return; + } + } + + if (currentFrame > 0) + frames.itemAt(currentFrame - 1).visible = false; + frames.itemAt(currentFrame).visible = true; + + currentFrame++; + } + } + + function start() + { + if (loadedFrameCount == fileModel.count) { + timer.start(); + } else { + root.loaded.connect(function(){ + timer.start(); + }); + } + } + + function stop() + { + timer.stop(); + } +} diff --git a/qml/Pages/RoomElement/TablePile.qml b/qml/Pages/RoomElement/TablePile.qml index 6c301b15..f49f6f6d 100644 --- a/qml/Pages/RoomElement/TablePile.qml +++ b/qml/Pages/RoomElement/TablePile.qml @@ -26,9 +26,8 @@ Item { if (toVanish) { for (i = 0; i < discardedCards.length; i++) { card = discardedCards[i]; - card.homeOpacity = 0; - // card.goBack(true); - roomScene.cardItemGoBack(card, true) + card.origOpacity = 0; + card.goBack(true); card.destroyOnStop() } @@ -101,12 +100,12 @@ Item { let overflow = false; for (i = 0; i < cards.length; i++) { card = cards[i]; - card.homeX = i * card.width; - if (card.homeX + card.width >= root.width) { + card.origX = i * card.width; + if (card.origX + card.width >= root.width) { overflow = true; break; } - card.homeY = 0; + card.origY = 0; } if (overflow) { @@ -115,8 +114,8 @@ Item { let spacing = xLimit / (cards.length - 1); for (i = 0; i < cards.length; i++) { card = cards[i]; - card.homeX = i * spacing; - card.homeY = 0; + card.origX = i * spacing; + card.origY = 0; } } @@ -124,15 +123,13 @@ Item { let parentPos = roomScene.mapFromItem(root, 0, 0); for (i = 0; i < cards.length; i++) { card = cards[i]; - card.homeX += parentPos.x + offsetX; - card.homeY += parentPos.y; + card.origX += parentPos.x + offsetX; + card.origY += parentPos.y; } if (animated) { for (i = 0; i < cards.length; i++) - // cards[i].goBack() // WTF - // console.log(cards[i].homeOpacity) - roomScene.cardItemGoBack(cards[i], true) + cards[i].goBack(true) } } } diff --git a/qml/Pages/RoomLogic.js b/qml/Pages/RoomLogic.js index ac4066d6..de90f53e 100644 --- a/qml/Pages/RoomLogic.js +++ b/qml/Pages/RoomLogic.js @@ -1,3 +1,15 @@ +var Card = { + Unknown : 0, + PlayerHand : 1, + PlayerEquip : 2, + PlayerJudge : 3, + PlayerSpecial : 4, + Processing : 5, + DrawPile : 6, + DiscardPile : 7, + Void : 8 +} + function arrangePhotos() { /* Layout of photos: * +---------------+ @@ -61,6 +73,134 @@ function replyToServer(jsonData) { ClientInstance.replyToServer("", jsonData); } +function getPhotoModel(id) { + for (let i = 0; i < photoModel.count; i++) { + let item = photoModel.get(i); + if (item.id === id) { + return item; + } + } + return undefined; +} + +function getPhoto(id) { + for (let i = 0; i < photoModel.count; i++) { + let item = photoModel.get(i); + if (item.id === id) { + return photos.itemAt(i); + } + } + return undefined; +} + +function getPhotoOrDashboard(id) { + let photo = getPhoto(id); + if (!photo) { + if (id === Self.id) + return dashboard; + } + return photo; +} + +function getAreaItem(area, id) { + if (area === Card.DrawPile) { + return drawPile; + } else if (area === Card.DiscardPile || area === Card.Processing) { + return tablePile; + } else if (area === Card.AG) { + return popupBox.item; + } + + let photo = getPhotoOrDashboard(id); + if (!photo) { + return null; + } + + if (area === Card.PlayerHand) { + return photo.handcardArea; + } else if (area === Card.PlayerEquip) + return photo.equipArea; + else if (area === Card.PlayerJudge) + return photo.delayedTrickArea; + else if (area === Card.PlayerSpecial) + return photo.specialArea; + + return null; +} + +function moveCards(moves) { + for (let i = 0; i < moves.length; i++) { + let move = moves[i]; + let from = getAreaItem(move.fromArea, move.from); + let to = getAreaItem(move.toArea, move.to); + if (!from || !to || from === to) + continue; + let items = from.remove(move.ids); + if (items.length > 0) + to.add(items); + to.updateCardPosition(true); + } +} + +function setEmotion(id, emotion) { + let component = Qt.createComponent("RoomElement/PixmapAnimation.qml"); + if (component.status !== Component.Ready) + return; + + let photo = getPhoto(id); + if (!photo) { + if (id === dashboardModel.id) { + photo = dashboard.self; + } else { + return null; + } + } + + let animation = component.createObject(photo, {source: emotion, anchors: {centerIn: photo}}); + animation.finished.connect(() => animation.destroy()); + animation.start(); +} + +function changeHp(id, delta, losthp) { + let photo = getPhoto(id); + if (!photo) { + if (id === dashboardModel.id) { + photo = dashboard.self; + } else { + return null; + } + } + if (delta < 0) { + if (!losthp) { + setEmotion(id, "damage") + photo.tremble() + } + } +} + +function doIndicate(from, tos) { + let component = Qt.createComponent("RoomElement/IndicatorLine.qml"); + if (component.status !== Component.Ready) + return; + + let fromItem = getPhotoOrDashboard(from); + let fromPos = mapFromItem(fromItem, fromItem.width / 2, fromItem.height / 2); + + let end = []; + for (let i = 0; i < tos.length; i++) { + if (from === tos[i]) + continue; + let toItem = getPhotoOrDashboard(tos[i]); + let toPos = mapFromItem(toItem, toItem.width / 2, toItem.height / 2); + end.push(toPos); + } + + let color = "#96943D"; + let line = component.createObject(roomScene, {start: fromPos, end: end, color: color}); + line.finished.connect(() => line.destroy()); + line.running = true; +} + callbacks["AddPlayer"] = function(jsonData) { // jsonData: int id, string screenName, string avatar for (let i = 0; i < photoModel.count; i++) { @@ -81,14 +221,11 @@ callbacks["AddPlayer"] = function(jsonData) { callbacks["RemovePlayer"] = function(jsonData) { // jsonData: int uid let uid = JSON.parse(jsonData)[0]; - for (let i = 0; i < photoModel.count; i++) { - let item = photoModel.get(i); - if (item.id === uid) { - item.id = -1; - item.screenName = ""; - item.general = ""; - return; - } + let model = getPhotoModel(uid); + if (typeof(model) !== "undefined") { + model.id = -1; + model.screenName = ""; + model.general = ""; } } @@ -102,12 +239,9 @@ callbacks["RoomOwner"] = function(jsonData) { return; } - for (let i = 0; i < photoModel.count; i++) { - let item = photoModel.get(i); - if (item.id === uid) { - item.isOwner = true; - return; - } + let model = getPhotoModel(uid); + if (typeof(model) !== "undefined") { + model.isOwner = true; } } @@ -124,12 +258,9 @@ callbacks["PropertyUpdate"] = function(jsonData) { return; } - for (let i = 0; i < photoModel.count; i++) { - let item = photoModel.get(i); - if (item.id === uid) { - item[property_name] = value; - return; - } + let model = getPhotoModel(uid); + if (typeof(model) !== "undefined") { + model[property_name] = value; } } @@ -193,12 +324,9 @@ callbacks["PlayerRunned"] = function(jsonData) { let runner = data[0]; let robot = data[1]; - let model; - for (let i = 0; i < playerNum - 1; i++) { - model = photoModel.get(i); - if (model.id === runner) { - model.id = robot; - } + let model = getPhotoModel(runner); + if (typeof(model) !== "undefined") { + model.id = robot; } } @@ -241,3 +369,9 @@ callbacks["AskForChoice"] = function(jsonData) { replyToServer(choices[box.result]); }); } + +callbacks["MoveCards"] = function(jsonData) { + // jsonData: merged moves + let moves = JSON.parse(jsonData); + moveCards(moves); +} diff --git a/qml/Pages/skin-bank.js b/qml/Pages/skin-bank.js index 2afb1e55..64ea0033 100644 --- a/qml/Pages/skin-bank.js +++ b/qml/Pages/skin-bank.js @@ -1,10 +1,14 @@ -//var AppPath = "file://home/notify/develop/FreeKill"; +//var AppPath = "file:///home/notify/develop/FreeKill"; var PHOTO_BACK_DIR = AppPath + "/image/photo/back/"; var PHOTO_DIR = AppPath + "/image/photo/"; var GENERAL_DIR = AppPath + "/image/generals/"; var STATE_DIR = AppPath + "/image/photo/state/"; +var STATUS_DIR = AppPath + "/image/photo/status/"; var ROLE_DIR = AppPath + "/image/photo/role/"; var DEATH_DIR = AppPath + "/image/photo/death/"; var MAGATAMA_DIR = AppPath + "/image/photo/magatama/"; var CARD_DIR = AppPath + "/image/card/"; var CARD_SUIT_DIR = AppPath + "/image/card/suit/"; +var DELAYED_TRICK_DIR = AppPath + "/image/card/delayedTrick/"; +var EQUIP_ICON_DIR = AppPath + "/image/card/equipIcon/"; +var PIXANIM_DIR = AppPath + "/image/anim/" diff --git a/qml/util.js b/qml/util.js new file mode 100644 index 00000000..796be1c0 --- /dev/null +++ b/qml/util.js @@ -0,0 +1,21 @@ +.pragma library + +function convertNumber(number) { + if (number === 1) + return "A"; + if (number >= 2 && number <= 10) + return number; + if (number >= 11 && number <= 13) { + const strs = ["J", "Q", "K"]; + return strs[number - 11]; + } + return ""; +} + +Array.prototype.contains = function(element) { + return this.indexOf(element) != -1; +} + +Array.prototype.prepend = function() { + this.splice(0, 0, ...arguments); +} diff --git a/src/ui/qmlbackend.cpp b/src/ui/qmlbackend.cpp index 22397923..a57a0680 100644 --- a/src/ui/qmlbackend.cpp +++ b/src/ui/qmlbackend.cpp @@ -85,20 +85,22 @@ bool QmlBackend::isDir(const QString &file) { return QFileInfo(file).isDir(); } +#define CALLFUNC int err = lua_pcall(L, 1, 1, 0); \ + const char *result = lua_tostring(L, -1); \ + if (err) { \ + qDebug() << result; \ + lua_pop(L, 1); \ + return ""; \ + } \ + lua_pop(L, 1); \ + return QString(result); \ + QString QmlBackend::translate(const QString &src) { lua_State *L = ClientInstance->getLuaState(); lua_getglobal(L, "Translate"); lua_pushstring(L, src.toUtf8().data()); - int err = lua_pcall(L, 1, 1, 0); - const char *result = lua_tostring(L, -1); - if (err) { - qDebug() << result; - lua_pop(L, 1); - return ""; - } - lua_pop(L, 1); - return QString(result); + CALLFUNC } QString QmlBackend::getGeneralData(const QString &general_name) { @@ -106,13 +108,15 @@ QString QmlBackend::getGeneralData(const QString &general_name) { lua_getglobal(L, "GetGeneralData"); lua_pushstring(L, general_name.toUtf8().data()); - int err = lua_pcall(L, 1, 1, 0); - const char *result = lua_tostring(L, -1); - if (err) { - qDebug() << result; - lua_pop(L, 1); - return ""; - } - lua_pop(L, 1); - return QString(result); + CALLFUNC } + +QString QmlBackend::getCardData(int id) { + lua_State *L = ClientInstance->getLuaState(); + lua_getglobal(L, "GetCardData"); + lua_pushinteger(L, id); + + CALLFUNC +} + +#undef CALLFUNC diff --git a/src/ui/qmlbackend.h b/src/ui/qmlbackend.h index 1cad730b..1ed39441 100644 --- a/src/ui/qmlbackend.h +++ b/src/ui/qmlbackend.h @@ -28,6 +28,7 @@ public: // read data from lua, call lua functions Q_INVOKABLE QString translate(const QString &src); Q_INVOKABLE QString getGeneralData(const QString &general_name); + Q_INVOKABLE QString getCardData(int id); signals: void notifyUI(const QString &command, const QString &jsonData);