From 0d8791e1a7165281428fba64f105976c5bf1f2d5 Mon Sep 17 00:00:00 2001 From: TheSumm Date: Sat, 24 Oct 2015 17:46:53 +0200 Subject: [PATCH] Protocol updates up to 10.82 --- modules/gamelib/const.lua | 24 ++++- modules/gamelib/game.lua | 3 +- modules/gamelib/market.lua | 4 +- modules/gamelib/protocol.lua | 20 +++- src/client/const.h | 24 ++++- src/client/game.cpp | 50 +++++++++- src/client/game.h | 8 ++ src/client/luafunctions.cpp | 6 ++ src/client/protocolcodes.h | 18 +++- src/client/protocolgame.h | 14 +++ src/client/protocolgameparse.cpp | 152 +++++++++++++++++++++++++++++++ src/client/protocolgamesend.cpp | 59 ++++++++++++ 12 files changed, 371 insertions(+), 11 deletions(-) diff --git a/modules/gamelib/const.lua b/modules/gamelib/const.lua index 558c15c4..3ac7b2a1 100644 --- a/modules/gamelib/const.lua +++ b/modules/gamelib/const.lua @@ -133,6 +133,7 @@ GameSessionKey = 69 GameDeathType = 70 GameIdleAnimations = 71 GameKeepUnawareTiles = 72 +GameIngameStore = 73 TextColors = { red = '#f55e5e', --'#c83200' @@ -216,7 +217,7 @@ CIPSOFT_RSA = "1321277432058722840622950990822933849527763264961655079678763618" "88792221429527047321331896351555606801473202394175817" -- set to the latest Tibia.pic signature to make otclient compatible with official tibia -PIC_SIGNATURE = 0x542100C1 +PIC_SIGNATURE = 0x557fe565 OsTypes = { Linux = 1, @@ -280,4 +281,25 @@ DeathType = { Blessed = 1 } +ProductType = { + Other = 0, + NameChange = 1 +} + +StoreErrorType = { + NoError = -1, + PurchaseError = 0, + NetworkError = 1, + HistoryError = 2, + TransferError = 3, + Information = 4 +} + +StoreState = { + None = 0, + New = 1, + Sale = 2, + Timed = 3 +} + -- @} diff --git a/modules/gamelib/game.lua b/modules/gamelib/game.lua index aff644c7..2259995e 100644 --- a/modules/gamelib/game.lua +++ b/modules/gamelib/game.lua @@ -73,7 +73,8 @@ function g_game.getSupportedClients() 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1070, 1071, 1072, - 1073, 1074, 1075, 1076 + 1073, 1074, 1075, 1076, 1080, + 1081, 1082 } end diff --git a/modules/gamelib/market.lua b/modules/gamelib/market.lua index 428f454c..c1764b37 100644 --- a/modules/gamelib/market.lua +++ b/modules/gamelib/market.lua @@ -45,11 +45,12 @@ MarketCategory = { Swords = 20, WandsRods = 21, PremiumScrolls = 22, + TibiaCoins = 23, MetaWeapons = 255 } MarketCategory.First = MarketCategory.Armors -MarketCategory.Last = MarketCategory.PremiumScrolls +MarketCategory.Last = MarketCategory.TibiaCoins MarketCategoryWeapons = { [MarketCategory.Ammunition] = { slots = {255} }, @@ -84,6 +85,7 @@ MarketCategoryStrings = { [20] = 'Swords', [21] = 'Wands and Rods', [22] = 'Premium Scrolls', + [23] = 'Tibia Coins', [255] = 'Weapons' } diff --git a/modules/gamelib/protocol.lua b/modules/gamelib/protocol.lua index 0f2c5cbd..205a938c 100644 --- a/modules/gamelib/protocol.lua +++ b/modules/gamelib/protocol.lua @@ -64,7 +64,7 @@ GameServerOpcodes = { GameServerPlayerSkills = 161, GameServerPlayerState = 162, GameServerClearTarget = 163, - GameServerSpellDelay = 164, --870 + GameServerSpellDelay = 164, -- 870 GameServerSpellGroupDelay = 165, -- 870 GameServerMultiUseDelay = 166, -- 870 GameServerTalk = 170, @@ -88,8 +88,12 @@ GameServerOpcodes = { GameServerVipLogout = 212, GameServerTutorialHint = 220, GameServerAutomapFlag = 221, + GameServerCoinBalance = 223, -- 1080 + GameServerStoreError = 224, -- 1080 + GameServerRequestPurchaseData = 225, -- 1080 GameServerQuestLog = 240, GameServerQuestLine = 241, + GameServerCoinBalanceUpdating = 242, -- 1080 GameServerChannelEvent = 243, -- 910 GameServerItemInfo = 244, -- 910 GameServerPlayerInventory = 245, -- 910 @@ -97,7 +101,11 @@ GameServerOpcodes = { GameServerMarketLeave = 247, -- 944 GameServerMarketDetail = 248, -- 944 GameServerMarketBrowse = 249, -- 944 - GameServerShowModalDialog = 250 -- 960 + GameServerShowModalDialog = 250, -- 960 + GameServerStore = 251, -- 1080 + GameServerStoreOffers = 252, -- 1080 + GameServerStoreTransactionHistory = 253, -- 1080 + GameServerStoreCompletePurchase = 254 -- 1080 } ClientOpcodes = { @@ -179,6 +187,7 @@ ClientOpcodes = { ClientBugReport = 230, ClientRuleViolation = 231, ClientDebugReport = 232, + ClientTransferCoins = 239, -- 1080 ClientRequestQuestLog = 240, ClientRequestQuestLine = 241, ClientNewRuleViolation = 242, -- 910 @@ -188,5 +197,10 @@ ClientOpcodes = { ClientMarketCreate = 246, -- 944 ClientMarketCancel = 247, -- 944 ClientMarketAccept = 248, -- 944 - ClientAnswerModalDialog = 249 -- 960 + ClientAnswerModalDialog = 249, -- 960 + ClientOpenStore = 250, -- 1080 + ClientRequestStoreOffers = 251, -- 1080 + ClientBuyStoreOffer = 252, -- 1080 + ClientOpenTransactionHistory = 253, -- 1080 + ClientRequestTransactionHistory = 254 -- 1080 } diff --git a/src/client/const.h b/src/client/const.h index 39947392..775a8e4b 100644 --- a/src/client/const.h +++ b/src/client/const.h @@ -404,7 +404,8 @@ namespace Otc GameSessionKey = 69, GameDeathType = 70, GameIdleAnimations = 71, - GameKeepUnawareTiles=72, + GameKeepUnawareTiles = 72, + GameIngameStore = 73, LastGameFeature = 101 }; @@ -474,6 +475,27 @@ namespace Otc DeathRegular = 0, DeathBlessed = 1 }; + + enum StoreProductTypes { + ProductTypeOther = 0, + ProductTypeNameChange = 1 + }; + + enum StoreErrorTypes { + StoreNoError = -1, + StorePurchaseError = 0, + StoreNetworkError = 1, + StoreHistoryError = 2, + StoreTransferError = 3, + StoreInformation = 4 + }; + + enum StoreStates { + StateNone = 0, + StateNew = 1, + StateSale = 2, + StateTimed = 3 + }; } #endif diff --git a/src/client/game.cpp b/src/client/game.cpp index ff7d149b..3655dbc2 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1395,6 +1395,48 @@ void Game::seekInContainer(int cid, int index) m_protocolGame->sendSeekInContainer(cid, index); } +void Game::buyStoreOffer(int offerId, int productType, const std::string& name) +{ + if(!canPerformGameAction()) + return; + m_protocolGame->sendBuyStoreOffer(offerId, productType, name); +} + +void Game::requestTransactionHistory(int page, int entriesPerPage) +{ + if(!canPerformGameAction()) + return; + m_protocolGame->sendRequestTransactionHistory(page, entriesPerPage); +} + +void Game::requestStoreOffers(const std::string& categoryName) +{ + if(!canPerformGameAction()) + return; + m_protocolGame->sendRequestStoreOffers(categoryName); +} + +void Game::openStore() +{ + if(!canPerformGameAction()) + return; + m_protocolGame->sendOpenStore(); +} + +void Game::transferCoins(const std::string& recipient, int amount) +{ + if(!canPerformGameAction()) + return; + m_protocolGame->sendTransferCoins(recipient, amount); +} + +void Game::openTransactionHistory(int entriesPerPage) +{ + if(!canPerformGameAction()) + return; + m_protocolGame->sendOpenTransactionHistory(entriesPerPage); +} + void Game::ping() { if(!m_protocolGame || !m_protocolGame->isConnected()) @@ -1450,7 +1492,7 @@ void Game::setProtocolVersion(int version) if(isOnline()) stdext::throw_exception("Unable to change protocol version while online"); - if(version != 0 && (version < 740 || version > 1076)) + if(version != 0 && (version < 740 || version > 1082)) stdext::throw_exception(stdext::format("Protocol version %d not supported", version)); m_protocolVersion = version; @@ -1468,7 +1510,7 @@ void Game::setClientVersion(int version) if(isOnline()) stdext::throw_exception("Unable to change client version while online"); - if(version != 0 && (version < 740 || version > 1076)) + if(version != 0 && (version < 740 || version > 1082)) stdext::throw_exception(stdext::format("Client version %d not supported", version)); m_features.reset(); @@ -1620,6 +1662,10 @@ void Game::setClientVersion(int version) enableFeature(Otc::GameSessionKey); } + if(version >= 1080) { + enableFeature(Otc::GameIngameStore); + } + m_clientVersion = version; g_lua.callGlobalField("g_game", "onClientVersionChange", version); diff --git a/src/client/game.h b/src/client/game.h index cf51fe6c..ec10317f 100644 --- a/src/client/game.h +++ b/src/client/game.h @@ -288,6 +288,14 @@ public: void browseField(const Position& position); void seekInContainer(int cid, int index); + // >= 1080 ingame store + void buyStoreOffer(int offerId, int productType, const std::string& name = ""); + void requestTransactionHistory(int page, int entriesPerPage); + void requestStoreOffers(const std::string& categoryName); + void openStore(); + void transferCoins(const std::string& recipient, int amount); + void openTransactionHistory(int entriesPerPage); + //void reportRuleViolation2(); void ping(); void setPingDelay(int delay) { m_pingDelay = delay; } diff --git a/src/client/luafunctions.cpp b/src/client/luafunctions.cpp index ee60f178..9ab60e18 100644 --- a/src/client/luafunctions.cpp +++ b/src/client/luafunctions.cpp @@ -301,6 +301,12 @@ void Client::registerLuaFunctions() g_lua.bindSingletonFunction("g_game", "browseField", &Game::browseField, &g_game); g_lua.bindSingletonFunction("g_game", "seekInContainer", &Game::seekInContainer, &g_game); g_lua.bindSingletonFunction("g_game", "getLastWalkDir", &Game::getLastWalkDir, &g_game); + g_lua.bindSingletonFunction("g_game", "buyStoreOffer", &Game::buyStoreOffer, &g_game); + g_lua.bindSingletonFunction("g_game", "requestTransactionHistory", &Game::requestTransactionHistory, &g_game); + g_lua.bindSingletonFunction("g_game", "requestStoreOffers", &Game::requestStoreOffers, &g_game); + g_lua.bindSingletonFunction("g_game", "openStore", &Game::openStore, &g_game); + g_lua.bindSingletonFunction("g_game", "transferCoins", &Game::transferCoins, &g_game); + g_lua.bindSingletonFunction("g_game", "openTransactionHistory", &Game::openTransactionHistory, &g_game); g_lua.registerSingletonClass("g_shaders"); g_lua.bindSingletonFunction("g_shaders", "createShader", &ShaderManager::createShader, &g_shaders); diff --git a/src/client/protocolcodes.h b/src/client/protocolcodes.h index b0bb6d66..186a4cc7 100644 --- a/src/client/protocolcodes.h +++ b/src/client/protocolcodes.h @@ -143,8 +143,12 @@ namespace Proto { GameServerVipLogout = 212, GameServerTutorialHint = 220, GameServerAutomapFlag = 221, + GameServerCoinBalance = 223, // 1080 + GameServerStoreError = 224, // 1080 + GameServerRequestPurchaseData = 225, // 1080 GameServerQuestLog = 240, GameServerQuestLine = 241, + GameServerCoinBalanceUpdating = 242, // 1080 GameServerChannelEvent = 243, // 910 GameServerItemInfo = 244, // 910 GameServerPlayerInventory = 245, // 910 @@ -152,7 +156,11 @@ namespace Proto { GameServerMarketLeave = 247, // 944 GameServerMarketDetail = 248, // 944 GameServerMarketBrowse = 249, // 944 - GameServerModalDialog = 250 // 960 + GameServerModalDialog = 250, // 960 + GameServerStore = 251, // 1080 + GameServerStoreOffers = 252, // 1080 + GameServerStoreTransactionHistory = 253, // 1080 + GameServerStoreCompletePurchase = 254 // 1080 }; enum ClientOpcodes : uint8 @@ -245,6 +253,7 @@ namespace Proto { ClientBugReport = 230, ClientRuleViolation = 231, ClientDebugReport = 232, + ClientTransferCoins = 239, // 1080 ClientRequestQuestLog = 240, ClientRequestQuestLine = 241, ClientNewRuleViolation = 242, // 910 @@ -254,7 +263,12 @@ namespace Proto { ClientMarketCreate = 246, // 944 ClientMarketCancel = 247, // 944 ClientMarketAccept = 248, // 944 - ClientAnswerModalDialog = 249 // 960 + ClientAnswerModalDialog = 249, // 960 + ClientOpenStore = 250, // 1080 + ClientRequestStoreOffers = 251, // 1080 + ClientBuyStoreOffer = 252, // 1080 + ClientOpenTransactionHistory = 253, // 1080 + ClientRequestTransactionHistory = 254 // 1080 }; enum CreatureType { diff --git a/src/client/protocolgame.h b/src/client/protocolgame.h index 100c07ea..da34caee 100644 --- a/src/client/protocolgame.h +++ b/src/client/protocolgame.h @@ -113,6 +113,12 @@ public: void sendAnswerModalDialog(int dialog, int button, int choice); void sendBrowseField(const Position& position); void sendSeekInContainer(int cid, int index); + void sendBuyStoreOffer(int offerId, int productType, const std::string& name); + void sendRequestTransactionHistory(int page, int entriesPerPage); + void sendRequestStoreOffers(const std::string& categoryName); + void sendOpenStore(); + void sendTransferCoins(const std::string& recipient, int amount); + void sendOpenTransactionHistory(int entiresPerPage); // otclient only void sendChangeMapAwareRange(int xrange, int yrange); @@ -128,6 +134,14 @@ public: void addPosition(const OutputMessagePtr& msg, const Position& position); private: + void parseStore(const InputMessagePtr& msg); + void parseStoreError(const InputMessagePtr& msg); + void parseStoreTransactionHistory(const InputMessagePtr& msg); + void parseStoreOffers(const InputMessagePtr& msg); + void parseCompleteStorePurchase(const InputMessagePtr& msg); + void parseRequestPurchaseData(const InputMessagePtr& msg); + void parseCoinBalance(const InputMessagePtr& msg); + void parseCoinBalanceUpdating(const InputMessagePtr& msg); void parseBlessings(const InputMessagePtr& msg); void parseUnjustifiedStats(const InputMessagePtr& msg); void parsePvpSituations(const InputMessagePtr& msg); diff --git a/src/client/protocolgameparse.cpp b/src/client/protocolgameparse.cpp index 31764b88..a00fa143 100644 --- a/src/client/protocolgameparse.cpp +++ b/src/client/protocolgameparse.cpp @@ -356,6 +356,31 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg) case Proto::GameServerPreset: parsePreset(msg); break; + // PROTOCOL>=1080 + case Proto::GameServerCoinBalanceUpdating: + parseCoinBalanceUpdating(msg); + break; + case Proto::GameServerCoinBalance: + parseCoinBalance(msg); + break; + case Proto::GameServerRequestPurchaseData: + parseRequestPurchaseData(msg); + break; + case Proto::GameServerStoreCompletePurchase: + parseCompleteStorePurchase(msg); + break; + case Proto::GameServerStoreOffers: + parseStoreOffers(msg); + break; + case Proto::GameServerStoreTransactionHistory: + parseStoreTransactionHistory(msg); + break; + case Proto::GameServerStoreError: + parseStoreError(msg); + break; + case Proto::GameServerStore: + parseStore(msg); + break; // otclient ONLY case Proto::GameServerExtendedOpcode: parseExtendedOpcode(msg); @@ -396,6 +421,15 @@ void ProtocolGame::parseLogin(const InputMessagePtr& msg) g_game.setExpertPvpMode(expertModeEnabled); } + if(g_game.getFeature(Otc::GameIngameStore)) { + // URL to ingame store images + msg->getString(); + + // premium coin package size + // e.g you can only buy packs of 25, 50, 75, .. coins in the market + msg->getU16(); + } + m_localPlayer->setId(playerId); g_game.setServerBeat(serverBeat); g_game.setCanReportBugs(canReportBugs); @@ -431,6 +465,124 @@ void ProtocolGame::parsePreset(const InputMessagePtr& msg) uint16 preset = msg->getU32(); } +void ProtocolGame::parseRequestPurchaseData(const InputMessagePtr& msg) +{ + int transactionId = msg->getU32(); + int productType = msg->getU8(); +} + +void ProtocolGame::parseStore(const InputMessagePtr& msg) +{ + parseCoinBalance(msg); + + // Parse all categories + int count = msg->getU16(); + for(int i = 0; i < count; i++) { + std::string category = msg->getString(); + std::string description = msg->getString(); + + std::vector icons; + int iconCount = msg->getU8(); + for(int i = 0; i < iconCount; i++) { + std::string icon = msg->getString(); + icons.push_back(icon); + } + + // If this is a valid category name then + // the category we just parsed is a child of that + std::string parentCategory = msg->getString(); + } +} + +void ProtocolGame::parseCoinBalance(const InputMessagePtr& msg) +{ + bool update = msg->getU8() == 1; + int coins = -1; + int transferableCoins = -1; + if(update) { + // amount of coins that can be used to buy prodcuts + // in the ingame store + coins = msg->getU32(); + + // amount of coins that can be sold in market + // or be transfered to another player + transferableCoins = msg->getU32(); + } +} + +void ProtocolGame::parseCoinBalanceUpdating(const InputMessagePtr& msg) +{ + // coin balance can be updating and might not be accurate + bool isUpdating = msg->getU8() == 1; +} + +void ProtocolGame::parseCompleteStorePurchase(const InputMessagePtr& msg) +{ + // not used + msg->getU8(); + + std::string message = msg->getString(); + int coins = msg->getU32(); + int transferableCoins = msg->getU32(); + + g_logger.info(stdext::format("Purchase Complete: %s", message)); +} + +void ProtocolGame::parseStoreTransactionHistory(const InputMessagePtr &msg) +{ + int currentPage = msg->getU16(); + bool hasNextPage = msg->getU8() == 1; + + int entries = msg->getU8(); + for(int i = 0; i < entries; i++) { + int time = msg->getU16(); + int productType = msg->getU8(); + int coinChange = msg->getU32(); + std::string productName = msg->getString(); + g_logger.error(stdext::format("Time %i, type %i, change %i, product name %s", time, productType, coinChange, productName)); + } +} + +void ProtocolGame::parseStoreOffers(const InputMessagePtr& msg) +{ + std::string categoryName = msg->getString(); + + int offers = msg->getU16(); + for(int i = 0; i < offers; i++) { + int offerId = msg->getU32(); + std::string offerName = msg->getString(); + std::string offerDescription = msg->getString(); + + int price = msg->getU32(); + int state = msg->getU8(); + int disabled = msg->getU8() == 1; + + int icons = msg->getU8(); + for(int j = 0; j < icons; j++) { + std::string icon = msg->getString(); + } + + int subOffers = msg->getU16(); + for(int j = 0; j < subOffers; j++) { + std::string name = msg->getString(); + std::string description = msg->getString(); + + int subIcons = msg->getU8(); + for(int k = 0; k < subIcons; k++) { + std::string icon = msg->getString(); + } + std::string serviceType = msg->getString(); + } + } +} + +void ProtocolGame::parseStoreError(const InputMessagePtr& msg) +{ + int errorType = msg->getU8(); + std::string message = msg->getString(); + g_logger.error(stdext::format("Store Error: %s [%i]", message, errorType)); +} + void ProtocolGame::parseUnjustifiedStats(const InputMessagePtr& msg) { UnjustifiedPoints unjustifiedPoints; diff --git a/src/client/protocolgamesend.cpp b/src/client/protocolgamesend.cpp index 5eb6a97d..8ec1e4e3 100644 --- a/src/client/protocolgamesend.cpp +++ b/src/client/protocolgamesend.cpp @@ -863,6 +863,65 @@ void ProtocolGame::sendSeekInContainer(int cid, int index) send(msg); } +void ProtocolGame::sendBuyStoreOffer(int offerId, int productType, const std::string& name) +{ + OutputMessagePtr msg(new OutputMessage); + msg->addU8(Proto::ClientBuyStoreOffer); + msg->addU32(offerId); + msg->addU8(productType); + + if(productType == Otc::ProductTypeNameChange) + msg->addString(name); + + send(msg); +} + +void ProtocolGame::sendRequestTransactionHistory(int page, int entriesPerPage) +{ + OutputMessagePtr msg(new OutputMessage); + msg->addU8(Proto::ClientRequestTransactionHistory); + msg->addU16(page); + msg->addU32(entriesPerPage); + + send(msg); +} + +void ProtocolGame::sendRequestStoreOffers(const std::string& categoryName) +{ + OutputMessagePtr msg(new OutputMessage); + msg->addU8(Proto::ClientRequestStoreOffers); + msg->addString(categoryName); + + send(msg); +} + +void ProtocolGame::sendOpenStore() +{ + OutputMessagePtr msg(new OutputMessage); + msg->addU8(Proto::ClientOpenStore); + + send(msg); +} + +void ProtocolGame::sendTransferCoins(const std::string& recipient, int amount) +{ + OutputMessagePtr msg(new OutputMessage); + msg->addU8(Proto::ClientTransferCoins); + msg->addString(recipient); + msg->addU16(amount); + send(msg); +} + +void ProtocolGame::sendOpenTransactionHistory(int entriesPerPage) +{ + OutputMessagePtr msg(new OutputMessage); + msg->addU8(Proto::ClientOpenTransactionHistory); + msg->addU8(entriesPerPage); + + send(msg); +} + + void ProtocolGame::sendChangeMapAwareRange(int xrange, int yrange) { if(!g_game.getFeature(Otc::GameChangeMapAwareRange))