diff --git a/modules/game_blessing/blessing.html b/modules/game_blessing/blessing.html new file mode 100644 index 0000000000..688a6b3e18 --- /dev/null +++ b/modules/game_blessing/blessing.html @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/game_blessing/blessing.lua b/modules/game_blessing/blessing.lua new file mode 100644 index 0000000000..788d18250a --- /dev/null +++ b/modules/game_blessing/blessing.lua @@ -0,0 +1,136 @@ +BlessingController = Controller:new() + +function BlessingController:onInit() +end + +function BlessingController:onTerminate() + -- BlessingController:findWidget("#main"):destroy() +end + +function BlessingController:onGameStart() + g_ui.importStyle("style.otui") + BlessingController:loadHtml('blessing.html', g_ui.getRootWidget()) + + BlessingController:registerEvents(g_game, { + onUpdateBlessDialog = onUpdateBlessDialog + }) + BlessingController.ui:hide() +end + +function BlessingController:onGameEnd() + if BlessingController.ui:isVisible() then + BlessingController.ui:hide() + end +end + +function BlessingController:close() + hide() +end + +function BlessingController:showHistory() + if BlessingController.ui.blessingHistory:isVisible() then + setBlessing() + else + setHistory() + end +end + +function setHistory() + local ui = BlessingController.ui + ui.test:hide() + ui.promotionStatus2:hide() + ui.promotionStatus:hide() + ui.blessingHistory:show() + ui.historyButton:setText("Back") +end + +function setBlessing() + local ui = BlessingController.ui + ui.test:show() + ui.promotionStatus2:show() + ui.promotionStatus:show() + ui.blessingHistory:hide() + ui.historyButton:setText("History") +end + +function toggle() + if not BlessingController.ui then + return + end + + if BlessingController.ui:isVisible() then + return hide() + end + show() +end + +function hide() + if not BlessingController.ui then + return + end + BlessingController.ui:hide() +end + +function show() + if not BlessingController.ui then + return + end + g_game.requestBless() + BlessingController.ui:show() + BlessingController.ui:raise() + BlessingController.ui:focus() + setBlessing() +end + +function onUpdateBlessDialog(data) + BlessingController.ui.test:destroyChildren() + + for i, entry in ipairs(data.blesses) do + local label = g_ui.createWidget("blessingTEST", BlessingController.ui.test) + local totalCount = entry.playerBlessCount + entry.store + label.text:setText(entry.playerBlessCount .. " (" .. entry.store .. ")") + if totalCount >= 1 then + label.enabled:setImageSource("images/" .. i .. "_on") + end + end + + if (data.promotion ~= 0) then + BlessingController.ui.promotionStatus2.premium_only:setOn(false) + BlessingController.ui.promotionStatus2.rank:setColoredText( + "Your character is promoted and your account has Premium\nstatus. As a result, your XP loss is reduced by {30%, #f75f5f}.") + else + BlessingController.ui.promotionStatus2.rank:setColoredText( + "Your character is promoted and your account has Premium\nstatus. As a result, your XP loss is reduced by {0%, #f75f5f}.") + BlessingController.ui.promotionStatus2.premium_only:setOn(true) + end + + BlessingController.ui.promotionStatus.fightRules:setColoredText( + "- Depending on the fair fight rules, you will lose between {" .. data.pvpMinXpLoss .. ", #f75f5f} and {" .. + data.pvpMaxXpLoss .. "%, #f75f5f} less XP and skill points \nupon your next PvP death.") + + BlessingController.ui.promotionStatus.expLoss:setColoredText( + "- You will lose {" .. data.pveExpLoss .. "%, #f75f5f}% less XP and skill points upon your next PvE death.") + + BlessingController.ui.promotionStatus.containerLoss:setColoredText( + "- There is a {" .. data.equipPvpLoss .. + "%, #f75f5f} chance that you will lose your equipped container on your next death.") + + BlessingController.ui.promotionStatus.equipmentLoss:setColoredText( + "- There is a {" .. data.equipPveLoss .. "%, #f75f5f} chance that you will lose items upon your next death.") + + BlessingController.ui.blessingHistory:getChildByIndex(1):destroyChildren() + local row2 = g_ui.createWidget("historyData", BlessingController.ui.blessingHistory:getChildByIndex(1)) + row2:setBackgroundColor("#363636") + row2.rank:setText("date") + row2.name:setText("Event") + row2.rank:setColor("#c0c0c0") + row2.name:setColor("#c0c0c0") + + for index, entry in ipairs(data.logs) do + local row = g_ui.createWidget("historyData", BlessingController.ui.blessingHistory:getChildByIndex(1)) + local date = os.date("%Y-%m-%d, %H:%M:%S", entry.timestamp) + row:setBackgroundColor(index % 2 == 0 and "#ffffff12" or "#00000012") + row.rank:setText(date) + row.name:setText(entry.historyMessage) + end +end diff --git a/modules/game_blessing/blessing.otmod b/modules/game_blessing/blessing.otmod new file mode 100644 index 0000000000..a5b55cbeef --- /dev/null +++ b/modules/game_blessing/blessing.otmod @@ -0,0 +1,9 @@ +Module + name: game_blessing + description: game_blessing + author: game_blessing + website: game_blessing + scripts: [ blessing.lua ] + sandboxed: true + @onLoad: BlessingController:init() + @onUnload: BlessingController:terminate() \ No newline at end of file diff --git a/modules/game_blessing/images/1.png b/modules/game_blessing/images/1.png new file mode 100644 index 0000000000..5e65bf2648 Binary files /dev/null and b/modules/game_blessing/images/1.png differ diff --git a/modules/game_blessing/images/1_on.png b/modules/game_blessing/images/1_on.png new file mode 100644 index 0000000000..6bba7a551e Binary files /dev/null and b/modules/game_blessing/images/1_on.png differ diff --git a/modules/game_blessing/images/2.png b/modules/game_blessing/images/2.png new file mode 100644 index 0000000000..2fe31822cf Binary files /dev/null and b/modules/game_blessing/images/2.png differ diff --git a/modules/game_blessing/images/2_on.png b/modules/game_blessing/images/2_on.png new file mode 100644 index 0000000000..6b46a4623e Binary files /dev/null and b/modules/game_blessing/images/2_on.png differ diff --git a/modules/game_blessing/images/3.png b/modules/game_blessing/images/3.png new file mode 100644 index 0000000000..5163bf7f60 Binary files /dev/null and b/modules/game_blessing/images/3.png differ diff --git a/modules/game_blessing/images/3_on.png b/modules/game_blessing/images/3_on.png new file mode 100644 index 0000000000..c5fc6e5e53 Binary files /dev/null and b/modules/game_blessing/images/3_on.png differ diff --git a/modules/game_blessing/images/4.png b/modules/game_blessing/images/4.png new file mode 100644 index 0000000000..ac0c7d30cc Binary files /dev/null and b/modules/game_blessing/images/4.png differ diff --git a/modules/game_blessing/images/4_on.png b/modules/game_blessing/images/4_on.png new file mode 100644 index 0000000000..f5de21c2c1 Binary files /dev/null and b/modules/game_blessing/images/4_on.png differ diff --git a/modules/game_blessing/images/5.png b/modules/game_blessing/images/5.png new file mode 100644 index 0000000000..a08dc9eb91 Binary files /dev/null and b/modules/game_blessing/images/5.png differ diff --git a/modules/game_blessing/images/5_on.png b/modules/game_blessing/images/5_on.png new file mode 100644 index 0000000000..88b9018144 Binary files /dev/null and b/modules/game_blessing/images/5_on.png differ diff --git a/modules/game_blessing/images/6.png b/modules/game_blessing/images/6.png new file mode 100644 index 0000000000..fad669126b Binary files /dev/null and b/modules/game_blessing/images/6.png differ diff --git a/modules/game_blessing/images/6_on.png b/modules/game_blessing/images/6_on.png new file mode 100644 index 0000000000..34c4f07651 Binary files /dev/null and b/modules/game_blessing/images/6_on.png differ diff --git a/modules/game_blessing/images/7.png b/modules/game_blessing/images/7.png new file mode 100644 index 0000000000..37ebb68538 Binary files /dev/null and b/modules/game_blessing/images/7.png differ diff --git a/modules/game_blessing/images/7_on.png b/modules/game_blessing/images/7_on.png new file mode 100644 index 0000000000..2b3e7ab681 Binary files /dev/null and b/modules/game_blessing/images/7_on.png differ diff --git a/modules/game_blessing/images/8.png b/modules/game_blessing/images/8.png new file mode 100644 index 0000000000..a3de881dc9 Binary files /dev/null and b/modules/game_blessing/images/8.png differ diff --git a/modules/game_blessing/images/8_on.png b/modules/game_blessing/images/8_on.png new file mode 100644 index 0000000000..069505c3dc Binary files /dev/null and b/modules/game_blessing/images/8_on.png differ diff --git a/modules/game_blessing/images/blessingContainer.png b/modules/game_blessing/images/blessingContainer.png new file mode 100644 index 0000000000..2199237070 Binary files /dev/null and b/modules/game_blessing/images/blessingContainer.png differ diff --git a/modules/game_blessing/images/getpremium.png b/modules/game_blessing/images/getpremium.png new file mode 100644 index 0000000000..14566df045 Binary files /dev/null and b/modules/game_blessing/images/getpremium.png differ diff --git a/modules/game_blessing/style.otui b/modules/game_blessing/style.otui new file mode 100644 index 0000000000..b4cc028234 --- /dev/null +++ b/modules/game_blessing/style.otui @@ -0,0 +1,74 @@ +historyData < UIWidget + height: 16 + Label + anchors.top: parent.top + anchors.left: parent.left + anchors.bottom : parent.bottom + id: rank + width: 150 + !text: tr('1') + text-align: center + color: #dfdfdfcf + phantom: false + margin-left: 4 + + VerticalSeparator + id: separator + anchors.top: parent.top + anchors.left: parent.left + anchors.bottom: parent.bottom + margin-top: -1 + margin-bottom: -1 + margin-left: 155 + + Label + anchors.top: parent.top + anchors.left: prev.right + anchors.bottom : parent.bottom + id: name + width: 216 + !text: tr('-') + text-align: left + color: #ff0000cf + phantom: true + margin-left: 5 + +blessingTEST < UIWidget + background-color: alpha + height: 62 + width: 70 + focusable: true + text-align: left + UIWidget + id: enabled + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + margin-top: -10 + margin-left: 3 + Label + id: text + !text: tr('loooooong text') + text-align: center + margin-top: 5 + width: 65 + anchors.left: prev.left + anchors.top: prev.bottom + + image-source: /game_blessing/images/blessingContainer + focusable: false + +BlessingButton < UIButton + size: 128 37 + image-source: /game_blessing/images/getpremium + image-clip: 0 0 128 37 + image-border: 3 + @onClick: modules.game_shop.toggle() + + $pressed: + image-clip: 0 37 128 37 + $!on: + image-clip: 0 74 128 37 + $disabled: + color: #dfdfdf88 + opacity: 0.8 + diff --git a/modules/game_interface/interface.otmod b/modules/game_interface/interface.otmod index 4a5ef51aae..2f3cdb1698 100644 --- a/modules/game_interface/interface.otmod +++ b/modules/game_interface/interface.otmod @@ -42,8 +42,8 @@ Module - game_shop - game_screenshot - game_highscore + - game_blessing - game_store - game_quickloot - @onLoad: init() @onUnload: terminate() diff --git a/modules/game_inventory/inventory.otui b/modules/game_inventory/inventory.otui index 3d87c9c130..9718a44264 100644 --- a/modules/game_inventory/inventory.otui +++ b/modules/game_inventory/inventory.otui @@ -68,7 +68,7 @@ PhantomMiniWindow anchors.left: changeSize.right margin-left: 3 size: 12 12 - + @onClick: modules.game_blessing.toggle() $pressed !disabled: image-clip: 12 0 12 12 @@ -556,7 +556,7 @@ PhantomMiniWindow anchors.left: changeSize.left margin-top: 3 size: 12 12 - + @onClick: modules.game_blessing.toggle() $pressed !disabled: image-clip: 12 0 12 12 diff --git a/src/client/game.cpp b/src/client/game.cpp index c26a3e3766..ccf0e20c1f 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1726,6 +1726,13 @@ void Game::imbuementDurations(bool isOpen) m_protocolGame->sendImbuementDurations(isOpen); } +void Game::requestBless() +{ + if (!canPerformGameAction()) + return; + + m_protocolGame->sendRequestBless(); + void Game::requestQuickLootBlackWhiteList(uint8_t filter, uint16_t size, const std::vector& listedItems) { m_denyBotCall = false; @@ -1733,9 +1740,10 @@ void Game::requestQuickLootBlackWhiteList(uint8_t filter, uint16_t size, const s m_denyBotCall = true; } -void Game::openContainerQuickLoot(uint8_t action, uint8_t category, const Position& pos, uint16_t itemId, uint8_t stackpos, bool useMainAsFallback) +void Game::openContainerQuickLoot(uint8_t action, uint8_t category, const Position& pos, uint16_t itemId, uint8_t stackpos, bool use]AsFallback) { m_denyBotCall = false; m_protocolGame->openContainerQuickLoot(action, category, pos, itemId, stackpos, useMainAsFallback); m_denyBotCall = true; + } diff --git a/src/client/game.h b/src/client/game.h index 73929c2511..cc00d11732 100644 --- a/src/client/game.h +++ b/src/client/game.h @@ -53,6 +53,36 @@ struct UnjustifiedPoints uint8_t skullTime; }; +struct BlessData +{ + uint16_t blessBitwise; + uint8_t playerBlessCount; + uint8_t store; +}; + +struct LogData +{ + uint32_t timestamp; + uint8_t colorMessage; + std::string_view historyMessage; +}; + +struct BlessDialogData +{ + uint8_t totalBless; + std::vector blesses; + uint8_t premium; + uint8_t promotion; + uint8_t pvpMinXpLoss; + uint8_t pvpMaxXpLoss; + uint8_t pveExpLoss; + uint8_t equipPvpLoss; + uint8_t equipPveLoss; + uint8_t skull; + uint8_t aol; + std::vector logs; +}; + using Vip = std::tuple; struct StoreCategory @@ -483,6 +513,7 @@ class Game const std::vector>& highscores, uint32_t entriesTs); void imbuementDurations(bool isOpen = false); + void requestBless(); void requestQuickLootBlackWhiteList(uint8_t filter, uint16_t size, const std::vector& listedItems); void openContainerQuickLoot(uint8_t action, uint8_t category, const Position& pos, uint16_t itemId, uint8_t stackpos, bool useMainAsFallback); diff --git a/src/client/luafunctions.cpp b/src/client/luafunctions.cpp index 196f08f44d..aa51091128 100644 --- a/src/client/luafunctions.cpp +++ b/src/client/luafunctions.cpp @@ -362,6 +362,7 @@ void Client::registerLuaFunctions() g_lua.bindSingletonFunction("g_game", "stashWithdraw", &Game::stashWithdraw, &g_game); g_lua.bindSingletonFunction("g_game", "requestHighscore", &Game::requestHighscore, &g_game); g_lua.bindSingletonFunction("g_game", "imbuementDurations", &Game::imbuementDurations, &g_game); + g_lua.bindSingletonFunction("g_game", "requestBless", &Game::requestBless, &g_game); g_lua.bindSingletonFunction("g_game", "requestQuickLootBlackWhiteList", &Game::requestQuickLootBlackWhiteList, &g_game); g_lua.bindSingletonFunction("g_game", "openContainerQuickLoot", &Game::openContainerQuickLoot, &g_game); diff --git a/src/client/luavaluecasts_client.cpp b/src/client/luavaluecasts_client.cpp index 72a0d81b2a..8493811e0b 100644 --- a/src/client/luavaluecasts_client.cpp +++ b/src/client/luavaluecasts_client.cpp @@ -289,6 +289,66 @@ bool luavalue_cast(int index, UnjustifiedPoints& unjustifiedPoints) return true; } +int push_luavalue(const BlessData& bless) { + g_lua.createTable(0, 3); + g_lua.pushInteger(bless.blessBitwise); + g_lua.setField("blessBitwise"); + g_lua.pushInteger(bless.playerBlessCount); + g_lua.setField("playerBlessCount"); + g_lua.pushInteger(bless.store); + g_lua.setField("store"); + return 1; +} + +int push_luavalue(const LogData& log) { + g_lua.createTable(0, 3); + g_lua.pushInteger(log.timestamp); + g_lua.setField("timestamp"); + g_lua.pushInteger(log.colorMessage); + g_lua.setField("colorMessage"); + g_lua.pushString(log.historyMessage); + g_lua.setField("historyMessage"); + return 1; +} + +int push_luavalue(const BlessDialogData& data) { + g_lua.createTable(0, 11); + g_lua.pushInteger(data.totalBless); + g_lua.setField("totalBless"); + + g_lua.createTable(data.blesses.size(), 0); + for (size_t i = 0; i < data.blesses.size(); ++i) { + push_luavalue(data.blesses[i]); + g_lua.rawSeti(i + 1); + } + g_lua.setField("blesses"); + + g_lua.pushInteger(data.premium); + g_lua.setField("premium"); + g_lua.pushInteger(data.promotion); + g_lua.setField("promotion"); + g_lua.pushInteger(data.pvpMinXpLoss); + g_lua.setField("pvpMinXpLoss"); + g_lua.pushInteger(data.pvpMaxXpLoss); + g_lua.setField("pvpMaxXpLoss"); + g_lua.pushInteger(data.pveExpLoss); + g_lua.setField("pveExpLoss"); + g_lua.pushInteger(data.equipPvpLoss); + g_lua.setField("equipPvpLoss"); + g_lua.pushInteger(data.equipPveLoss); + g_lua.setField("equipPveLoss"); + g_lua.pushInteger(data.skull); + g_lua.setField("skull"); + g_lua.pushInteger(data.aol); + g_lua.setField("aol"); + + g_lua.createTable(data.logs.size(), 0); + for (size_t i = 0; i < data.logs.size(); ++i) { + push_luavalue(data.logs[i]); + g_lua.rawSeti(i + 1); + } + g_lua.setField("logs"); + int push_luavalue(const StoreCategory& category) { g_lua.createTable(0, 5); g_lua.pushString(category.name); diff --git a/src/client/luavaluecasts_client.h b/src/client/luavaluecasts_client.h index c5f99b3300..368988d81c 100644 --- a/src/client/luavaluecasts_client.h +++ b/src/client/luavaluecasts_client.h @@ -49,6 +49,10 @@ bool luavalue_cast(int index, UnjustifiedPoints& unjustifiedPoints); int push_luavalue(const Imbuement& i); int push_luavalue(const ImbuementTrackerItem& i); +// Bless +int push_luavalue(const BlessData& bless); +int push_luavalue(const LogData& log); +int push_luavalue(const BlessDialogData& data); int push_luavalue(const StoreCategory& category); int push_luavalue(const SubOffer& subOffer); int push_luavalue(const StoreOffer& offer); diff --git a/src/client/protocolcodes.h b/src/client/protocolcodes.h index 6fceffe808..0f90cd8a58 100644 --- a/src/client/protocolcodes.h +++ b/src/client/protocolcodes.h @@ -298,6 +298,7 @@ namespace Proto ClientRefreshContainer = 202, ClientBrowseField = 203, ClientSeekInContainer = 204, + ClientRequestBless = 207, ClientRequestOutfit = 210, ClientChangeOutfit = 211, ClientMount = 212, // 870 diff --git a/src/client/protocolgame.h b/src/client/protocolgame.h index 4cc427834b..b81996bca8 100644 --- a/src/client/protocolgame.h +++ b/src/client/protocolgame.h @@ -97,6 +97,7 @@ class ProtocolGame : public Protocol void sendExcludeFromOwnChannel(const std::string_view name); void sendCancelAttackAndFollow(); void sendRefreshContainer(int containerId); + void sendRequestBless(); void sendRequestOutfit(); void sendChangeOutfit(const Outfit& outfit); void sendTyping(bool typing); diff --git a/src/client/protocolgameparse.cpp b/src/client/protocolgameparse.cpp index 0274eb49a5..11a7fb90b3 100644 --- a/src/client/protocolgameparse.cpp +++ b/src/client/protocolgameparse.cpp @@ -3703,36 +3703,37 @@ void ProtocolGame::parseGameNews(const InputMessagePtr& msg) void ProtocolGame::parseBlessDialog(const InputMessagePtr& msg) { - // parse bless amount - const uint8_t totalBless = msg->getU8(); // total bless - - // parse each bless - for (auto i = 0; i < totalBless; ++i) { - msg->getU16(); // bless bit wise - msg->getU8(); // player bless count - msg->getU8(); // store? - } - - // parse general info - msg->getU8(); // premium - msg->getU8(); // promotion - msg->getU8(); // pvp min xp loss - msg->getU8(); // pvp max xp loss - msg->getU8(); // pve exp loss - msg->getU8(); // equip pvp loss - msg->getU8(); // equip pve loss - msg->getU8(); // skull - msg->getU8(); // aol - - // parse log - const uint8_t logCount = msg->getU8(); // log count + BlessDialogData data; + data.totalBless = msg->getU8(); + + for (auto i = 0; i < data.totalBless; ++i) { + BlessData bless; + bless.blessBitwise = msg->getU16(); + bless.playerBlessCount = msg->getU8(); + bless.store = msg->getU8(); + data.blesses.emplace_back(bless); + } + + data.premium = msg->getU8(); + data.promotion = msg->getU8(); + data.pvpMinXpLoss = msg->getU8(); + data.pvpMaxXpLoss = msg->getU8(); + data.pveExpLoss = msg->getU8(); + data.equipPvpLoss = msg->getU8(); + data.equipPveLoss = msg->getU8(); + data.skull = msg->getU8(); + data.aol = msg->getU8(); + + const uint8_t logCount = msg->getU8(); for (auto i = 0; i < logCount; ++i) { - msg->getU32(); // timestamp - msg->getU8(); // color message (0 = white loss, 1 = red) - msg->getString(); // history message + LogData log; + log.timestamp = msg->getU32(); + log.colorMessage = msg->getU8(); + log.historyMessage = msg->getString(); + data.logs.emplace_back(log); } - // TODO: implement bless dialog usage + g_lua.callGlobalField("g_game", "onUpdateBlessDialog", data); } void ProtocolGame::parseRestingAreaState(const InputMessagePtr& msg) diff --git a/src/client/protocolgamesend.cpp b/src/client/protocolgamesend.cpp index f165cd71ad..eb3219f542 100644 --- a/src/client/protocolgamesend.cpp +++ b/src/client/protocolgamesend.cpp @@ -725,6 +725,13 @@ void ProtocolGame::sendRefreshContainer(int containerId) send(msg); } +void ProtocolGame::sendRequestBless() +{ + const auto& msg = std::make_shared(); + msg->addU8(Proto::ClientRequestBless); + send(msg); +} + void ProtocolGame::sendRequestOutfit() { const auto& msg = std::make_shared();