From b7ac6ce6d5f786d443c428376d8357ab92c84a9e Mon Sep 17 00:00:00 2001 From: BeniS Date: Wed, 18 Jul 2012 02:36:27 +1200 Subject: [PATCH] Added Market/MarketProtocol module to begin the construction of the Market! Fixed some Minor Issues, and Some Cosmetics * Added new protocol lib. * Added missing Game Features to game/const.lua * Added new Market module that will handle the market/market protocols too. * Finished Market protocol and begun on the market structure (MarketOffer etc). * Removed any traces of market protocol in the core (I think). * Moved minimap images to /images. * Removed old zoom images for minimap. * Fixed a bug with randomize outfit. --- modules/corelib/corelib.otmod | 1 + modules/corelib/protocol.lua | 188 ++++++++++++++++ modules/game/const.lua | 5 +- modules/game/game.otmod | 2 + modules/game/market.lua | 38 ++++ modules/game/protocollogin.lua | 2 +- modules/game_market/market.lua | 61 ++++++ modules/game_market/market.otmod | 19 ++ modules/game_market/market.otui | 29 +++ modules/game_market/marketoffer.lua | 137 ++++++++++++ modules/game_market/marketprotocol.lua | 204 ++++++++++++++++++ .../game_minimap/{ => images}/floor_down.png | Bin .../game_minimap/{ => images}/floor_up.png | Bin .../{zoomin.png => images/zoom_in.png} | Bin .../{zoomout.png => images/zoom_out.png} | Bin modules/game_minimap/minimap.otui | 8 +- modules/game_minimap/zoom_in.png | Bin 4454 -> 0 bytes modules/game_minimap/zoom_out.png | Bin 4230 -> 0 bytes modules/game_outfit/outfit.lua | 1 + modules/game_playermount/playermount.otmod | 2 +- src/framework/net/inputmessage.h | 2 +- src/otclient/const.h | 5 +- src/otclient/game.cpp | 8 +- src/otclient/protocolgameparse.cpp | 9 +- 24 files changed, 699 insertions(+), 22 deletions(-) create mode 100644 modules/corelib/protocol.lua create mode 100644 modules/game/market.lua create mode 100644 modules/game_market/market.lua create mode 100644 modules/game_market/market.otmod create mode 100644 modules/game_market/market.otui create mode 100644 modules/game_market/marketoffer.lua create mode 100644 modules/game_market/marketprotocol.lua rename modules/game_minimap/{ => images}/floor_down.png (100%) rename modules/game_minimap/{ => images}/floor_up.png (100%) rename modules/game_minimap/{zoomin.png => images/zoom_in.png} (100%) rename modules/game_minimap/{zoomout.png => images/zoom_out.png} (100%) delete mode 100644 modules/game_minimap/zoom_in.png delete mode 100644 modules/game_minimap/zoom_out.png diff --git a/modules/corelib/corelib.otmod b/modules/corelib/corelib.otmod index 6aa98eba..b3a181cc 100644 --- a/modules/corelib/corelib.otmod +++ b/modules/corelib/corelib.otmod @@ -16,5 +16,6 @@ Module dofile 'settings' dofile 'keyboard' dofile 'mouse' + dofile 'protocol' dofiles 'ui' diff --git a/modules/corelib/protocol.lua b/modules/corelib/protocol.lua new file mode 100644 index 00000000..22e99edd --- /dev/null +++ b/modules/corelib/protocol.lua @@ -0,0 +1,188 @@ +GameServerOpcodes = { + GameServerInitGame = 10, + GameServerGMActions = 11, + GameServerLoginError = 20, + GameServerLoginAdvice = 21, + GameServerLoginWait = 22, + GameServerPingBack = 29, + GameServerPing = 30, + GameServerChallange = 31, + GameServerDeath = 40, + + -- all in game opcodes must be greater than 50 + GameServerFirstGameOpcode = 50, + + -- otclient ONLY + GameServerExtendedOpcode = 50, + + -- NOTE: add any custom opcodes in this range + -- 51 - 99 + + -- original tibia ONLY + GameServerFullMap = 100, + GameServerMapTopRow = 101, + GameServerMapRightRow = 102, + GameServerMapBottomRow = 103, + GameServerMapLeftRow = 104, + GameServerUpdateTile = 105, + GameServerCreateOnMap = 106, + GameServerChangeOnMap = 107, + GameServerDeleteOnMap = 108, + GameServerMoveCreature = 109, + GameServerOpenContainer = 110, + GameServerCloseContainer = 111, + GameServerCreateContainer = 112, + GameServerChangeInContainer = 113, + GameServerDeleteInContainer = 114, + GameServerSetInventory = 120, + GameServerDeleteInventory = 121, + GameServerOpenNpcTrade = 122, + GameServerPlayerGoods = 123, + GameServerCloseNpcTrade = 124, + GameServerOwnTrade = 125, + GameServerCounterTrade = 126, + GameServerCloseTrade = 127, + GameServerAmbient = 130, + GameServerGraphicalEffect = 131, + GameServerTextEffect = 132, + GameServerMissleEffect = 133, + GameServerMarkCreature = 134, + GameServerTrappers = 135, + GameServerCreatureHealth = 140, + GameServerCreatureLight = 141, + GameServerCreatureOutfit = 142, + GameServerCreatureSpeed = 143, + GameServerCreatureSkull = 144, + GameServerCreatureParty = 145, + GameServerCreatureUnpass = 146, + GameServerEditText = 150, + GameServerEditList = 151, + GameServerPlayerDataBasic = 159, -- 910 + GameServerPlayerData = 160, + GameServerPlayerSkills = 161, + GameServerPlayerState = 162, + GameServerClearTarget = 163, + GameServerSpellDelay = 164, --870 + GameServerSpellGroupDelay = 165, -- 870 + GameServerMultiUseDelay = 166, -- 870 + GameServerTalk = 170, + GameServerChannels = 171, + GameServerOpenChannel = 172, + GameServerOpenPrivateChannel = 173, + GameServerRuleViolationChannel = 174, + GameServerRuleViolationRemove = 175, + GameServerRuleViolationCancel = 176, + GameServerRuleViolationLock = 177, + GameServerOpenOwnChannel = 178, + GameServerCloseChannel = 179, + GameServerTextMessage = 180, + GameServerCancelWalk = 181, + GameServerWalkWait = 182, + GameServerFloorChangeUp = 190, + GameServerFloorChangeDown = 191, + GameServerChooseOutfit = 200, + GameServerVipAdd = 210, + GameServerVipLogin = 211, + GameServerVipLogout = 212, + GameServerTutorialHint = 220, + GameServerAutomapFlag = 221, + GameServerQuestLog = 240, + GameServerQuestLine = 241, + GameServerChannelEvent = 243, -- 910 + GameServerItemInfo = 244, -- 910 + GameServerPlayerInventory = 245, -- 910 + GameServerMarketEnter = 246, -- 944 + GameServerMarketLeave = 247, -- 944 + GameServerMarketDetail = 248, -- 944 + GameServerMarketBrowse = 249 -- 944 +} + +ClientOpcodes = { + ClientEnterAccount = 1, + ClientEnterGame = 10, + ClientLeaveGame = 20, + ClientPing = 29, + ClientPingBack = 30, + + -- all in game opcodes must be equal or greater than 50 + ClientFirstGameOpcode = 50, + + -- otclient ONLY + ClientExtendedOpcode = 50, + + -- NOTE: add any custom opcodes in this range + -- 51 - 99 + + -- original tibia ONLY + ClientAutoWalk = 100, + ClientWalkNorth = 101, + ClientWalkEast = 102, + ClientWalkSouth = 103, + ClientWalkWest = 104, + ClientStop = 105, + ClientWalkNorthEast = 106, + ClientWalkSouthEast = 107, + ClientWalkSouthWest = 108, + ClientWalkNorthWest = 109, + ClientTurnNorth = 111, + ClientTurnEast = 112, + ClientTurnSouth = 113, + ClientTurnWest = 114, + ClientEquipItem = 119, -- 910 + ClientMove = 120, + ClientInspectNpcTrade = 121, + ClientBuyItem = 122, + ClientSellItem = 123, + ClientCloseNpcTrade = 124, + ClientRequestTrade = 125, + ClientInspectTrade = 126, + ClientAcceptTrade = 127, + ClientRejectTrade = 128, + ClientUseItem = 130, + ClientUseItemWith = 131, + ClientUseOnCreature = 132, + ClientRotateItem = 133, + ClientCloseContainer = 135, + ClientUpContainer = 136, + ClientEditText = 137, + ClientEditList = 138, + ClientLook = 140, + ClientTalk = 150, + ClientRequestChannels = 151, + ClientJoinChannel = 152, + ClientLeaveChannel = 153, + ClientOpenPrivateChannel = 154, + ClientCloseNpcChannel = 158, + ClientChangeFightModes = 160, + ClientAttack = 161, + ClientFollow = 162, + ClientInviteToParty = 163, + ClientJoinParty = 164, + ClientRevokeInvitation = 165, + ClientPassLeadership = 166, + ClientLeaveParty = 167, + ClientShareExperience = 168, + ClientDisbandParty = 169, + ClientOpenOwnChannel = 170, + ClientInviteToOwnChannel = 171, + ClientExcludeFromOwnChannel = 172, + ClientCancelAttackAndFollow = 190, + ClientRefreshContainer = 202, + ClientRequestOutfit = 210, + ClientChangeOutfit = 211, + ClientMount = 212, -- 870 + ClientAddVip = 220, + ClientRemoveVip = 221, + ClientBugReport = 230, + ClientRuleViolation = 231, + ClientDebugReport = 232, + ClientRequestQuestLog = 240, + ClientRequestQuestLine = 241, + ClientNewRuleViolation = 242, -- 910 + ClientRequestItemInfo = 243, -- 910 + ClientMarketLeave = 244, -- 944 + ClientMarketBrowse = 245, -- 944 + ClientMarketCreate = 246, -- 944 + ClientMarketCancel = 247, -- 944 + ClientMarketAccept = 248 -- 944 +} \ No newline at end of file diff --git a/modules/game/const.lua b/modules/game/const.lua index 1a619f7e..2f9fbc45 100644 --- a/modules/game/const.lua +++ b/modules/game/const.lua @@ -34,9 +34,6 @@ SouthEast = 5 SouthWest = 6 NorthWest = 7 -ClientEnterAccount = 1 -ClientEnterGame = 10 - LoginServerError = 10 LoginServerMotd = 20 LoginServerUpdateNeeded = 30 @@ -64,6 +61,8 @@ GameCreaturePassableInfo = 18 GameItemAnimationPhase = 19 GameTrucatedPingOpcode = 20 GameReverseCreatureStack = 21 +GameMagicEffectU16 = 22 +GamePlayerMarket = 23 OTSERV_RSA = "109120132967399429278860960508995541528237502902798129123468757937266291492576446330739696001110603907230888610072655818825358503429057592827629436413108566029093628212635953836686562675849720620786279431090218017681061521755056710823876476444260558147179707119674283982419152118103759076030616683978566631413" diff --git a/modules/game/game.otmod b/modules/game/game.otmod index 365aad19..3139e17d 100644 --- a/modules/game/game.otmod +++ b/modules/game/game.otmod @@ -32,6 +32,7 @@ Module - game_shaders - game_playerdeath - game_playermount + - game_market @onLoad: | dofile 'const' @@ -40,3 +41,4 @@ Module dofile 'creature' dofile 'player' + dofile 'market' diff --git a/modules/game/market.lua b/modules/game/market.lua new file mode 100644 index 00000000..7c8ebc2f --- /dev/null +++ b/modules/game/market.lua @@ -0,0 +1,38 @@ +MarketAction = { + Buy = 0, + Sell = 1 +} + +MarketRequest = { + MyOffers = 0xFFFE, + MyHistory = 0xFFFF +} + +MarketOfferState = { + Active = 0, + Cancelled = 1, + Expired = 2, + Accepted = 3, + AcceptedEx = 255 +} + +MarketItemDescription = { + Armor = 1, + Attack = 2, + Container = 3, + Defense = 4, + General = 5, + DecayTime = 6, + Combat = 7, + MinLevel = 8, + MinMagicLevel = 9, + Vocation = 10, + Rune = 11, + Ability = 12, + Charges = 13, + WeaponName = 14, + Weight = 15, + + First = Armor, + Last = Weight +} diff --git a/modules/game/protocollogin.lua b/modules/game/protocollogin.lua index 9c992973..d71b171e 100644 --- a/modules/game/protocollogin.lua +++ b/modules/game/protocollogin.lua @@ -4,7 +4,7 @@ ProtocolLogin = extends(Protocol) -- private functions local function sendLoginPacket(protocol) local msg = OutputMessage.create() - msg:addU8(ClientEnterAccount) + msg:addU8(ClientOpcodes.ClientEnterAccount) msg:addU16(1) -- todo: ClientOs msg:addU16(g_game.getClientVersion()) diff --git a/modules/game_market/market.lua b/modules/game_market/market.lua new file mode 100644 index 00000000..891ac39b --- /dev/null +++ b/modules/game_market/market.lua @@ -0,0 +1,61 @@ +Market = {} + +local marketWindow + +function Market.init() + g_ui.importStyle('market.otui') + +end + +function Market.terminate() + marketWindow = nil + Market = nil +end + +function Market.onMarketEnter(depotItems, offers, balance) + -- open market window + -- populate market? + print('onMarketEnter') + print(offers) + print(balance) + print('depotItems:') + for k, item in pairs(depotItems) do + print('id- '..item[1]) + print('count- '..item[2]) + end +end + +function Market.onMarketLeave() + -- close market window? + print('onMarketLeave') +end + +function Market.onMarketDetail(itemId, descriptions, purchaseStats, saleStats) + -- populate market widget + print('onMarketDetail') + print(itemId) + print('descriptions:') + for k, desc in pairs(descriptions) do + print('type- '..desc[1]) + print('description- '..desc[2]) + end + print('purchaseStats:') + for k, stat in pairs(purchaseStats) do + print('transactions- '..stat[1]) + print('total price- '..stat[2]) + print('highest price- '..stat[3]) + print('lowest price- '..stat[4]) + end + print('saleStats:') + for k, stat in pairs(saleStats) do + print('transactions- '..stat[1]) + print('total price- '..stat[2]) + print('highest price- '..stat[3]) + print('lowest price- '..stat[4]) + end +end + +function Market.onMarketBrowse(offers) + -- populate market widget + print('onMarketBrowse') +end diff --git a/modules/game_market/market.otmod b/modules/game_market/market.otmod new file mode 100644 index 00000000..2a345723 --- /dev/null +++ b/modules/game_market/market.otmod @@ -0,0 +1,19 @@ +Module + name: game_market + description: Manage the Players Market system + author: BeniS + website: www.otclient.info + + dependencies: + - game + + @onLoad: | + dofile 'marketoffer' + dofile 'marketprotocol' + dofile 'market' + MarketProtocol.init() + Market.init() + + @onUnload: | + MarketProtocol.terminate() + Market.terminate() diff --git a/modules/game_market/market.otui b/modules/game_market/market.otui new file mode 100644 index 00000000..6ed320b7 --- /dev/null +++ b/modules/game_market/market.otui @@ -0,0 +1,29 @@ +MarketWindow < MainWindow + id: marketWindow + !text: tr('Market') + size: 350 155 + + Label + !text: tr('Alas! Brave adventurer, you have met a sad fate.\nBut do not despair, for the gods will bring you back\ninto this world in exchange for a small sacrifice\n\nSimply click on Ok to resume your journeys!') + width: 550 + height: 140 + anchors.left: parent.left + anchors.top: parent.top + margin-left: 10 + margin-top: 2 + + Button + id: buttonOk + !text: tr('Ok') + width: 64 + anchors.left: parent.left + anchors.bottom: parent.bottom + margin-left: 160 + + Button + id: buttonCancel + !text: tr('Cancel') + width: 64 + anchors.left: prev.right + anchors.bottom: parent.bottom + margin-left: 5 diff --git a/modules/game_market/marketoffer.lua b/modules/game_market/marketoffer.lua new file mode 100644 index 00000000..dbeb2181 --- /dev/null +++ b/modules/game_market/marketoffer.lua @@ -0,0 +1,137 @@ +MarketOffer = {} +MarketOffer.__index = MarketOffer + +local OFFER_TIMESTAMP = 1 +local OFFER_COUNTER = 2 + +MarketOffer.new = function(offerId, action, itemId, amount, price, playerName, state) + local offer = { + id = {}, + action = nil, + item = 0, + amount = 0, + price = 0, + player = '', + state = 0 + } + + if not offerId or type(offerId) ~= 'table' then + g_logger.error('MarketOffer.new - invalid offer id provided.') + end + offer.id = offerId + + action = tonumber(action) + if action ~= MarketAction.Buy and action ~= MarketAction.Sell then + g_logger.error('MarketOffer.new - invalid action provided.') + end + offer.action = action + + offer.item = itemId + offer.amount = amount + offer.price = price + offer.player = playerName + + state = tonumber(state) + if state ~= MarketOfferState.Active and state ~= MarketOfferState.Cancelled + and state ~= MarketOfferState.Expired and state ~= MarketOfferState.Accepted then + g_logger.error('MarketOffer.new - invalid state provided.') + end + offer.state = state + + setmetatable(offer, MarketOffer) + return offer +end + +function MarketOffer:isEqual(offer) + return self.offer[OFFER_TIMESTAMP] == offer[OFFER_TIMESTAMP] and self.offer[OFFER_COUNTER] == offer[OFFER_COUNTER] +end + +function MarketOffer:isLessThan(offer) + return self.offer[OFFER_TIMESTAMP] <= offer[OFFER_TIMESTAMP] and self.offer[OFFER_COUNTER] < offer[OFFER_COUNTER] +end + +function MarketOffer:isNull(offer) + return table.empty(self.id) +end + +-- Sets/Gets + +function MarketOffer:setId(id) + if not id or type(id) ~= 'table' then + g_logger.error('MarketOffer.setId - invalid id provided.') + end + self.id = id +end + +function MarketOffer:getId() + return self.id +end + +function MarketOffer:setItem(item) + if not item or type(item) ~= 'number' then + g_logger.error('MarketOffer.setItem - invalid item id provided.') + end + self.item = item +end + +function MarketOffer:getItem() + return self.item +end + +function MarketOffer:setAmount(amount) + if not amount or type(amount) ~= 'number' then + g_logger.error('MarketOffer.setAmount - invalid amount provided.') + end + self.amount = amount +end + +function MarketOffer:getAmount() + return self.amount +end + +function MarketOffer:setPrice(price) + if not price or type(price) ~= 'number' then + g_logger.error('MarketOffer.setPrice - invalid price provided.') + end + self.price = price +end + +function MarketOffer:getPrice() + return self.price +end + +function MarketOffer:setPlayer(player) + if not player or type(player) ~= 'number' then + g_logger.error('MarketOffer.setPlayer - invalid player provided.') + end + self.player = player +end + +function MarketOffer:getPlayer() + return self.player +end + +function MarketOffer:setState(state) + if not state or type(state) ~= 'number' then + g_logger.error('MarketOffer.setState - invalid state provided.') + end + self.state = state +end + +function MarketOffer:getState() + return self.state +end + +function MarketOffer:getTimeStamp() + if table.empty(self.id) or #self.id < OFFER_TIMESTAMP then + return + end + return self.id[OFFER_TIMESTAMP] +end + +function MarketOffer:getCounter() + if table.empty(self.id) or #self.id < OFFER_COUNTER then + return + end + return self.id[OFFER_COUNTER] +end \ No newline at end of file diff --git a/modules/game_market/marketprotocol.lua b/modules/game_market/marketprotocol.lua new file mode 100644 index 00000000..2e8eb1aa --- /dev/null +++ b/modules/game_market/marketprotocol.lua @@ -0,0 +1,204 @@ +MarketProtocol = {} + +local market + +-- private functions + +function parseOpcode(protocol, opcode, msg) + if not g_game.getFeature(GamePlayerMarket) then + return false + end + + -- process msg + if opcode == GameServerOpcodes.GameServerMarketEnter then + parseMarketEnter(msg) + elseif opcode == GameServerOpcodes.GameServerMarketLeave then + parseMarketLeave(msg) + elseif opcode == GameServerOpcodes.GameServerMarketDetail then + parseMarketDetail(msg) + elseif opcode == GameServerOpcodes.GameServerMarketBrowse then + parseMarketBrowse(msg) + else + return false + end + return true +end + +function send(msg) + print(msg:getMessageSize()) + g_game.getProtocolGame():safeSend(msg) +end + +function readMarketOffer(msg, action, var) + local timestamp = msg:getU32() + local counter = msg:getU16() + + local itemId = 0 + if var == MarketRequest.MyOffers or var == MarketRequest.MyHistory then + itemId = msg:getU16() + else + itemId = var + end + + local amount = msg:getU16() + local price = msg:getU32() + local playerName + local state = MarketOfferState.Active + if var == MarketRequest.MyHistory then + state = msg:getU8() + else + playerName = msg:getString() + end + + return MarketOffer.new({timestamp, counter}, action, itemId, amount, price, playerName, state) +end + +-- parsing protocols + +function parseMarketEnter(msg) + local balance = msg:getU32() + local offers = msg:getU8() + local depotItems = {} + + local depotCount = (msg:getU16() - 1) + for i = 0, depotCount do + local itemId = msg:getU16() -- item id + local itemCount = msg:getU16() -- item count + + table.insert(depotItems, {itemId, itemCount}) + end + + Market.onMarketEnter(depotItems, offers, balance) +end + +function parseMarketLeave(msg) + Market.onMarketLeave() +end + +function parseMarketDetail(msg) + local itemId = msg:getU16() + + local descriptions = {} + for i = MarketItemDescription.First, MarketItemDescription.Last do + if msg:peekU16() ~= 0x00 then + table.insert(descriptions, {i, msg:getString()}) + else + msg:getU16() + end + end + + local purchaseStats = {} + if msg:getU8() == 0x01 then + local transactions = msg:getU32() -- transaction count + local totalPrice = msg:getU32() -- total price + local highestPrice = msg:getU32() -- highest price + local lowestPrice = msg: getU32() -- lowest price + + table.insert(purchaseStats, {transaction, totalPrice, highestPrice, lowestPrice}) + end + + local saleStats = {} + if msg:getU8() == 0x01 then + local transactions = msg:getU32() -- transaction count + local totalPrice = msg:getU32() -- total price + local highestPrice = msg:getU32() -- highest price + local lowestPrice = msg: getU32() -- lowest price + + table.insert(saleStats, {transaction, totalPrice, highestPrice, lowestPrice}) + end + + Market.onMarketDetail(itemId, descriptions, purchaseStats, saleStats) +end + +function parseMarketBrowse(msg) + local var = msg:getU16() + local offers = {} + + local buyOfferCount = (msg:getU32() - 1) + for i = 0, buyOfferCount do + table.insert(offers, readMarketOffer(msg, MarketAction.Buy, var)) + end + + local sellOfferCount = (msg:getU32() - 1) + for i = 0, sellOfferCount do + table.insert(offers, readMarketOffer(msg, MarketAction.Sell, var)) + end + + Market.onMarketBrowse(offers) +end + +-- public functions + +function MarketProtocol.init() + connect(ProtocolGame, { onOpcode = parseOpcode } ) + +end + +function MarketProtocol.terminate() + disconnect(ProtocolGame, { onOpcode = parseOpcode } ) + + market = nil + MarketProtocol = nil +end + +-- sending protocols + +function MarketProtocol.sendMarketLeave() + if g_game.getFeature(GamePlayerMarket) then + local msg = OutputMessage.create() + msg:addU8(ClientOpcodes.ClientMarketLeave) + send(msg) + else + g_logger.error('MarketProtocol.sendMarketLeave does not support the current protocol.') + end +end + +function MarketProtocol.sendMarketBrowse(browseId) + if g_game.getFeature(GamePlayerMarket) then + local msg = OutputMessage.create() + msg:addU8(ClientOpcodes.ClientMarketBrowse) + msg:addU16(browseId) + send(msg) + else + g_logger.error('MarketProtocol.sendMarketBrowse does not support the current protocol.') + end +end + +function MarketProtocol.sendMarketCreateOffer(type, spriteId, amount, price, anonymous) + if g_game.getFeature(GamePlayerMarket) then + local msg = OutputMessage.create() + msg:addU8(ClientOpcodes.ClientMarketCreate) + msg:addU8(type) + msg:addU16(spriteId) + msg:addU16(amount) + msg:addU32(price) + msg:addU8(anonymous) + send(msg) + else + g_logger.error('MarketProtocol.sendMarketCreateOffer does not support the current protocol.') + end +end + +function MarketProtocol.sendMarketCancelOffer(counter) + if g_game.getFeature(GamePlayerMarket) then + local msg = OutputMessage.create() + msg:addU8(ClientOpcodes.ClientMarketCancel) + msg:addU32(os.time()) + msg:addU16(counter) + send(msg) + else + g_logger.error('MarketProtocol.sendMarketCancelOffer does not support the current protocol.') + end +end + +function MarketProtocol.sendMarketAcceptOffer(counter) + if g_game.getFeature(GamePlayerMarket) then + local msg = OutputMessage.create() + msg:addU8(ClientOpcodes.ClientMarketAccept) + msg:addU32(os.time()) + msg:addU16(counter) + send(msg) + else + g_logger.error('MarketProtocol.sendMarketAcceptOffer does not support the current protocol.') + end +end diff --git a/modules/game_minimap/floor_down.png b/modules/game_minimap/images/floor_down.png similarity index 100% rename from modules/game_minimap/floor_down.png rename to modules/game_minimap/images/floor_down.png diff --git a/modules/game_minimap/floor_up.png b/modules/game_minimap/images/floor_up.png similarity index 100% rename from modules/game_minimap/floor_up.png rename to modules/game_minimap/images/floor_up.png diff --git a/modules/game_minimap/zoomin.png b/modules/game_minimap/images/zoom_in.png similarity index 100% rename from modules/game_minimap/zoomin.png rename to modules/game_minimap/images/zoom_in.png diff --git a/modules/game_minimap/zoomout.png b/modules/game_minimap/images/zoom_out.png similarity index 100% rename from modules/game_minimap/zoomout.png rename to modules/game_minimap/images/zoom_out.png diff --git a/modules/game_minimap/minimap.otui b/modules/game_minimap/minimap.otui index 60fe4554..51cc815e 100644 --- a/modules/game_minimap/minimap.otui +++ b/modules/game_minimap/minimap.otui @@ -9,16 +9,16 @@ MapControl < Button icon-clip: 0 16 16 16 FloorUpControl < MapControl - icon-source: /game_minimap/floor_up.png + icon-source: /game_minimap/images/floor_up.png FloorDownControl < MapControl - icon-source: /game_minimap/floor_down.png + icon-source: /game_minimap/images/floor_down.png ZoomOutControl < MapControl - //image-source: /game_minimap/zoom_out.png + //image-source: /game_minimap/images/zoom_out.png ZoomInControl < MapControl - //image-source: /game_minimap/zoom_in.png + //image-source: /game_minimap/images/zoom_in.png MiniWindow id: minimapWindow diff --git a/modules/game_minimap/zoom_in.png b/modules/game_minimap/zoom_in.png deleted file mode 100644 index 5bec5146cee9c724b8a6fae827dc5b2e9f8ae622..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4454 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 diff --git a/modules/game_minimap/zoom_out.png b/modules/game_minimap/zoom_out.png deleted file mode 100644 index 9da7a4f17e6e97b0705d7e954a6762d6c8319234..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4230 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 diff --git a/modules/game_outfit/outfit.lua b/modules/game_outfit/outfit.lua index 08cedaf2..b29ffadf 100644 --- a/modules/game_outfit/outfit.lua +++ b/modules/game_outfit/outfit.lua @@ -233,6 +233,7 @@ function Outfit.destroy() mountCreature = nil currentColorBox = nil currentClotheButtonBox = nil + colorBoxes = {} end end diff --git a/modules/game_playermount/playermount.otmod b/modules/game_playermount/playermount.otmod index 0fdf3b6d..a8bea712 100644 --- a/modules/game_playermount/playermount.otmod +++ b/modules/game_playermount/playermount.otmod @@ -2,7 +2,7 @@ Module name: game_playermount description: Manage player mounts author: BeniS - website: www.otclient.infox + website: www.otclient.info @onLoad: | dofile 'playermount' diff --git a/src/framework/net/inputmessage.h b/src/framework/net/inputmessage.h index c55a951b..2ed46b0c 100644 --- a/src/framework/net/inputmessage.h +++ b/src/framework/net/inputmessage.h @@ -32,7 +32,7 @@ class InputMessage : public LuaObject public: enum { BUFFER_MAXSIZE = 16384, - MAX_HEADER_SIZE = 8, + MAX_HEADER_SIZE = 8 }; InputMessage(); diff --git a/src/otclient/const.h b/src/otclient/const.h index c5053324..bd404567 100644 --- a/src/otclient/const.h +++ b/src/otclient/const.h @@ -48,7 +48,7 @@ namespace Otc ANIMATED_TEXT_DURATION = 1000, STATIC_DURATION_PER_CHARACTER = 60, MIN_STATIC_TEXT_DURATION = 3000, - MAX_STATIC_TEXT_WIDTH = 200, + MAX_STATIC_TEXT_WIDTH = 200 }; enum DrawFlags { @@ -309,6 +309,7 @@ namespace Otc GameTrucatedPingOpcode, GameReverseCreatureStack, GameMagicEffectU16, + GamePlayerMarket, LastGameFeature }; @@ -317,7 +318,7 @@ namespace Otc PATHFIND_SAME_POSITION, PATHFIND_IMPOSSIBLE, PATHFIND_TOO_FAR, - PATHFIND_NO_WAY, + PATHFIND_NO_WAY }; } diff --git a/src/otclient/game.cpp b/src/otclient/game.cpp index 5893f225..645e0ff6 100644 --- a/src/otclient/game.cpp +++ b/src/otclient/game.cpp @@ -38,14 +38,14 @@ Game g_game; Game::Game() { resetGameStates(); - setClientVersion(860); + setClientVersion(954); } void Game::resetGameStates() { m_denyBotCall = false; m_dead = false; - m_mounted = false; + m_mounted = false; m_serverBeat = 50; m_canReportBugs = false; m_fightMode = Otc::FightBalanced; @@ -1135,6 +1135,10 @@ void Game::setClientVersion(int clientVersion) enableFeature(Otc::GameItemAnimationPhase); } + if(clientVersion >= 940) { + enableFeature(Otc::GamePlayerMarket); + } + if(clientVersion >= 953) { enableFeature(Otc::GameCreaturePassableInfo); enableFeature(Otc::GameTrucatedPingOpcode); diff --git a/src/otclient/protocolgameparse.cpp b/src/otclient/protocolgameparse.cpp index d4dfbc73..2d1c2002 100644 --- a/src/otclient/protocolgameparse.cpp +++ b/src/otclient/protocolgameparse.cpp @@ -301,13 +301,6 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg) case Proto::GameServerPlayerInventory: parsePlayerInventory(msg); break; - // PROTOCOL>=944 - /* - case Proto::GameServerMarketEnter: - case Proto::GameServerMarketLeave: - case Proto::GameServerMarketDetail: - case Proto::GameServerMarketBrowse: - */ // otclient ONLY case Proto::GameServerExtendedOpcode: parseExtendedOpcode(msg); @@ -1135,7 +1128,6 @@ void ProtocolGame::parseOpenOutfitWindow(const InputMessagePtr& msg) Outfit currentOutfit = getOutfit(msg); std::vector > outfitList; - std::vector > mountList; int outfitCount = msg->getU8(); for(int i = 0; i < outfitCount; i++) { int outfitId = msg->getU16(); @@ -1145,6 +1137,7 @@ void ProtocolGame::parseOpenOutfitWindow(const InputMessagePtr& msg) outfitList.push_back(std::make_tuple(outfitId, outfitName, outfitAddons)); } + std::vector > mountList; if(g_game.getFeature(Otc::GamePlayerMounts)) { int mountCount = msg->getU8(); for(int i = 0; i < mountCount; ++i) {