Advertisement
joadson

New Protocolgame.cpp

Jan 14th, 2021
2,107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 106.57 KB | None | 0 0
  1. ////////////////////////////////////////////////////////////////////////
  2. // OpenTibia - an opensource roleplaying game
  3. ////////////////////////////////////////////////////////////////////////
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16. ////////////////////////////////////////////////////////////////////////
  17. #include "otpch.h"
  18. #include "resources.h"
  19.  
  20. #include <boost/function.hpp>
  21. #include <iostream>
  22. #include "iomarket.h"
  23. #include "protocolgame.h"
  24. #include "textlogger.h"
  25.  
  26. #include "waitlist.h"
  27. #include "player.h"
  28.  
  29. #include "connection.h"
  30. #include "networkmessage.h"
  31. #include "outputmessage.h"
  32.  
  33. #include "iologindata.h"
  34. #include "ioban.h"
  35.  
  36. #include "items.h"
  37. #include "tile.h"
  38. #include "house.h"
  39.  
  40. #include "actions.h"
  41. #include "creatureevent.h"
  42. #include "quests.h"
  43.  
  44. #include "chat.h"
  45. #include "configmanager.h"
  46. #include "game.h"
  47.  
  48. #if defined(WINDOWS) && !defined(__CONSOLE__)
  49. #include "gui.h"
  50. #endif
  51.  
  52. extern Game g_game;
  53. extern ConfigManager g_config;
  54. extern Actions actions;
  55. extern CreatureEvents* g_creatureEvents;
  56. extern Chat g_chat;
  57.  
  58. template<class FunctionType>
  59. void ProtocolGame::addGameTaskInternal(uint32_t delay, const FunctionType& func)
  60. {
  61.     if(delay > 0)
  62.         Dispatcher::getInstance().addTask(createTask(delay, func));
  63.     else
  64.         Dispatcher::getInstance().addTask(createTask(func));
  65. }
  66.  
  67. #ifdef __ENABLE_SERVER_DIAGNOSTIC__
  68. uint32_t ProtocolGame::protocolGameCount = 0;
  69. #endif
  70.  
  71. void ProtocolGame::setPlayer(Player* p)
  72. {
  73.     player = p;
  74. }
  75.  
  76. void ProtocolGame::releaseProtocol()
  77. {
  78.     if(player && player->client == this)
  79.         player->client = NULL;
  80.  
  81.     Protocol::releaseProtocol();
  82. }
  83.  
  84. void ProtocolGame::deleteProtocolTask()
  85. {
  86.     if(player)
  87.     {
  88.         g_game.freeThing(player);
  89.         player = NULL;
  90.     }
  91.  
  92.     Protocol::deleteProtocolTask();
  93. }
  94.  
  95. bool ProtocolGame::login(const std::string& name, uint32_t id, const std::string& password,
  96.     OperatingSystem_t operatingSystem, uint16_t version, bool gamemaster)
  97. {
  98.     //dispatcher thread
  99.     PlayerVector players = g_game.getPlayersByName(name);
  100.     Player* _player = NULL;
  101.     if(!players.empty())
  102.         _player = players[random_range(0, (players.size() - 1))];
  103.  
  104.     if(!_player || name == "Account Manager" || g_config.getNumber(ConfigManager::ALLOW_CLONES) > (int32_t)players.size())
  105.     {
  106.         player = new Player(name, this);
  107.         player->addRef();
  108.  
  109.         player->setID();
  110.         if(!IOLoginData::getInstance()->loadPlayer(player, name, true))
  111.         {
  112.             disconnectClient(0x14, "Your character could not be loaded.");
  113.             return false;
  114.         }
  115.  
  116.         Ban ban;
  117.         ban.value = player->getID();
  118.         ban.param = PLAYERBAN_BANISHMENT;
  119.  
  120.         ban.type = BAN_PLAYER;
  121.         if(IOBan::getInstance()->getData(ban) && !player->hasFlag(PlayerFlag_CannotBeBanned))
  122.         {
  123.             bool deletion = ban.expires < 0;
  124.             std::string name_ = "Automatic ";
  125.             if(!ban.adminId)
  126.                 name_ += (deletion ? "deletion" : "banishment");
  127.             else
  128.                 IOLoginData::getInstance()->getNameByGuid(ban.adminId, name_, true);
  129.  
  130.             char buffer[500 + ban.comment.length()];
  131.             sprintf(buffer, "Your character has been %s at:\n%s by: %s,\nfor the following reason:\n%s.\nThe action taken was:\n%s.\nThe comment given was:\n%s.\nYour %s%s.",
  132.                 (deletion ? "deleted" : "banished"), formatDateShort(ban.added).c_str(), name_.c_str(),
  133.                 getReason(ban.reason).c_str(), getAction(ban.action, false).c_str(), ban.comment.c_str(),
  134.                 (deletion ? "character won't be undeleted" : "banishment will be lifted at:\n"),
  135.                 (deletion ? "." : formatDateShort(ban.expires, true).c_str()));
  136.  
  137.             disconnectClient(0x14, buffer);
  138.             return false;
  139.         }
  140.  
  141.         if(IOBan::getInstance()->isPlayerBanished(player->getGUID(), PLAYERBAN_LOCK) && id != 1)
  142.         {
  143.             if(g_config.getBool(ConfigManager::NAMELOCK_MANAGER))
  144.             {
  145.                 player->name = "Account Manager";
  146.                 player->accountManager = MANAGER_NAMELOCK;
  147.  
  148.                 player->managerNumber = id;
  149.                 player->managerString2 = name;
  150.             }
  151.             else
  152.             {
  153.                 disconnectClient(0x14, "Your character has been namelocked.");
  154.                 return false;
  155.             }
  156.         }
  157.         else if(player->getName() == "Account Manager" && g_config.getBool(ConfigManager::ACCOUNT_MANAGER))
  158.         {
  159.             if(id != 1)
  160.             {
  161.                 player->accountManager = MANAGER_ACCOUNT;
  162.                 player->managerNumber = id;
  163.             }
  164.             else
  165.                 player->accountManager = MANAGER_NEW;
  166.         }
  167.  
  168.         if(gamemaster && !player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges))
  169.         {
  170.             disconnectClient(0x14, "You are not a gamemaster! Turn off the gamemaster mode in your IP changer.");
  171.             return false;
  172.         }
  173.  
  174.         if(!player->hasFlag(PlayerFlag_CanAlwaysLogin))
  175.         {
  176.             if(g_game.getGameState() == GAME_STATE_CLOSING)
  177.             {
  178.                 disconnectClient(0x14, "Gameworld is just going down, please come back later.");
  179.                 return false;
  180.             }
  181.  
  182.             if(g_game.getGameState() == GAME_STATE_CLOSED)
  183.             {
  184.                 disconnectClient(0x14, "Gameworld is currently closed, please come back later.");
  185.                 return false;
  186.             }
  187.         }
  188.  
  189.         if(g_config.getBool(ConfigManager::ONE_PLAYER_ON_ACCOUNT) && !player->isAccountManager() &&
  190.             !IOLoginData::getInstance()->hasCustomFlag(id, PlayerCustomFlag_CanLoginMultipleCharacters))
  191.         {
  192.             bool found = false;
  193.             PlayerVector tmp = g_game.getPlayersByAccount(id);
  194.             for(PlayerVector::iterator it = tmp.begin(); it != tmp.end(); ++it)
  195.             {
  196.                 if((*it)->getName() != name)
  197.                     continue;
  198.  
  199.                 found = true;
  200.                 break;
  201.             }
  202.  
  203.             if(tmp.size() > 0 && !found)
  204.             {
  205.                 disconnectClient(0x14, "You may only login with one character\nof your account at the same time.");
  206.                 return false;
  207.             }
  208.         }
  209.  
  210.         if(!WaitingList::getInstance()->login(player))
  211.         {
  212.             if(OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false))
  213.             {
  214.                 TRACK_MESSAGE(output);
  215.                 std::stringstream ss;
  216.                 ss << "Too many players online.\n" << "You are ";
  217.  
  218.                 int32_t slot = WaitingList::getInstance()->getSlot(player);
  219.                 if(slot)
  220.                 {
  221.                     ss << "at ";
  222.                     if(slot > 0)
  223.                         ss << slot;
  224.                     else
  225.                         ss << "unknown";
  226.  
  227.                     ss << " place on the waiting list.";
  228.                 }
  229.                 else
  230.                     ss << "awaiting connection...";
  231.  
  232.                 output->AddByte(0x16);
  233.                 output->AddString(ss.str());
  234.                 output->AddByte(WaitingList::getTime(slot));
  235.                 OutputMessagePool::getInstance()->send(output);
  236.             }
  237.  
  238.             getConnection()->close();
  239.             return false;
  240.         }
  241.  
  242.         if(!IOLoginData::getInstance()->loadPlayer(player, name))
  243.         {
  244.             disconnectClient(0x14, "Your character could not be loaded.");
  245.             return false;
  246.         }
  247.  
  248.         player->setOperatingSystem(operatingSystem);
  249.         player->setClientVersion(version);
  250.         if(!g_game.placeCreature(player, player->getLoginPosition()) && !g_game.placeCreature(player, player->getMasterPosition(), false, true))
  251.         {
  252.             disconnectClient(0x14, "Temple position is wrong. Contact with the administration.");
  253.             return false;
  254.  
  255.         }
  256.  
  257.         player->lastIP = player->getIP();
  258.         player->lastLoad = OTSYS_TIME();
  259.         player->lastLogin = std::max(time(NULL), player->lastLogin + 1);
  260.  
  261.         m_acceptPackets = true;
  262.         return true;
  263.     }
  264.     else if(_player->client)
  265.     {
  266.         if(m_eventConnect || !g_config.getBool(ConfigManager::REPLACE_KICK_ON_LOGIN))
  267.         {
  268.             //A task has already been scheduled just bail out (should not be overriden)
  269.             disconnectClient(0x14, "You are already logged in.");
  270.             return false;
  271.         }
  272.  
  273.         g_chat.removeUserFromAllChannels(_player);
  274.         _player->disconnect();
  275.         _player->isConnecting = true;
  276.  
  277.         addRef();
  278.         m_eventConnect = Scheduler::getInstance().addEvent(createSchedulerTask(
  279.             1000, boost::bind(&ProtocolGame::connect, this, _player->getID(), operatingSystem, version)));
  280.         return true;
  281.     }
  282.  
  283.     addRef();
  284.     return connect(_player->getID(), operatingSystem, version);
  285. }
  286.  
  287. bool ProtocolGame::logout(bool displayEffect, bool forceLogout)
  288. {
  289.     //dispatcher thread
  290.     if(!player)
  291.         return false;
  292.  
  293.     if(!player->isRemoved())
  294.     {
  295.         if(!forceLogout)
  296.         {
  297.             if(!IOLoginData::getInstance()->hasCustomFlag(player->getAccount(), PlayerCustomFlag_CanLogoutAnytime))
  298.             {
  299.                 if(player->getTile()->hasFlag(TILESTATE_NOLOGOUT))
  300.                 {
  301.                     player->sendCancelMessage(RET_YOUCANNOTLOGOUTHERE);
  302.                     return false;
  303.                 }
  304.  
  305.                 if(player->hasCondition(CONDITION_INFIGHT))
  306.                 {
  307.                     player->sendCancelMessage(RET_YOUMAYNOTLOGOUTDURINGAFIGHT);
  308.                     return false;
  309.                 }
  310.  
  311.                 if(!g_creatureEvents->playerLogout(player, false)) //let the script handle the error message
  312.                     return false;
  313.             }
  314.             else
  315.                 g_creatureEvents->playerLogout(player, false);
  316.         }
  317.         else if(!g_creatureEvents->playerLogout(player, true))
  318.             return false;
  319.     }
  320.     else
  321.         displayEffect = false;
  322.  
  323.     if(displayEffect && !player->isGhost())
  324.         g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
  325.  
  326.     if(Connection_ptr connection = getConnection())
  327.         connection->close();
  328.  
  329.     return g_game.removeCreature(player);
  330. }
  331.  
  332. bool ProtocolGame::connect(uint32_t playerId, OperatingSystem_t operatingSystem, uint16_t version)
  333. {
  334.     unRef();
  335.     m_eventConnect = 0;
  336.  
  337.     Player* _player = g_game.getPlayerByID(playerId);
  338.     if(!_player || _player->isRemoved() || _player->client)
  339.     {
  340.         disconnectClient(0x14, "You are already logged in.");
  341.         return false;
  342.     }
  343.  
  344.     player = _player;
  345.     player->addRef();
  346.     player->isConnecting = false;
  347.  
  348.     player->client = this;
  349.     player->sendCreatureAppear(player);
  350.  
  351.     player->setOperatingSystem(operatingSystem);
  352.     player->setClientVersion(version);
  353.  
  354.     player->lastIP = player->getIP();
  355.     player->lastLoad = OTSYS_TIME();
  356.     player->lastLogin = std::max(time(NULL), player->lastLogin + 1);
  357.  
  358.     m_acceptPackets = true;
  359.     return true;
  360. }
  361.  
  362. void ProtocolGame::disconnect()
  363. {
  364.     if(getConnection())
  365.         getConnection()->close();
  366. }
  367.  
  368. void ProtocolGame::disconnectClient(uint8_t error, const char* message)
  369. {
  370.     if(OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false))
  371.     {
  372.         TRACK_MESSAGE(output);
  373.         output->AddByte(error);
  374.         output->AddString(message);
  375.         OutputMessagePool::getInstance()->send(output);
  376.     }
  377.  
  378.     disconnect();
  379. }
  380.  
  381. void ProtocolGame::onConnect()
  382. {
  383.     if(OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false))
  384.     {
  385.         TRACK_MESSAGE(output);
  386.         enableChecksum();
  387.  
  388.         output->AddByte(0x1F);
  389.         output->AddU16(random_range(0, 0xFFFF));
  390.         output->AddU16(0x00);
  391.         output->AddByte(random_range(0, 0xFF));
  392.  
  393.         OutputMessagePool::getInstance()->send(output);
  394.     }
  395. }
  396.  
  397. void ProtocolGame::onRecvFirstMessage(NetworkMessage& msg)
  398. {
  399.     parseFirstPacket(msg);
  400. }
  401.  
  402. bool ProtocolGame::parseFirstPacket(NetworkMessage& msg)
  403. {
  404.     if(
  405. #if defined(WINDOWS) && !defined(__CONSOLE__)
  406.         !GUI::getInstance()->m_connections ||
  407. #endif
  408.         g_game.getGameState() == GAME_STATE_SHUTDOWN)
  409.     {
  410.         getConnection()->close();
  411.         return false;
  412.     }
  413.  
  414.     OperatingSystem_t operatingSystem = (OperatingSystem_t)msg.GetU16();
  415.     uint16_t version = msg.GetU16();
  416.     if(!RSA_decrypt(msg))
  417.     {
  418.         getConnection()->close();
  419.         return false;
  420.     }
  421.  
  422.     uint32_t key[4] = {msg.GetU32(), msg.GetU32(), msg.GetU32(), msg.GetU32()};
  423.     enableXTEAEncryption();
  424.     setXTEAKey(key);
  425.  
  426.    
  427.         // notifies to otclient that this server can receive extended game protocol opcodes
  428.        if(operatingSystem >= CLIENTOS_OTCLIENT_LINUX)
  429.           sendExtendedOpcode(0x00, std::string());
  430.      
  431.  
  432.     bool gamemaster = msg.GetByte();
  433.     std::string name = msg.GetString(), character = msg.GetString(), password = msg.GetString();
  434.  
  435.     msg.SkipBytes(6); //841- wtf?
  436.     if(version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX)
  437.     {
  438.         disconnectClient(0x14, CLIENT_VERSION_STRING);
  439.         return false;
  440.     }
  441.    
  442.     if(!IOLoginData::getInstance()->accountNameExists(name))
  443.     {
  444.         disconnectClient(0x0A, "Account name existing.");
  445.         return false;
  446.     }
  447.    
  448.     if(character.empty() || !IOLoginData::getInstance()->playerExists(character))
  449.     {
  450.         disconnectClient(0x0A, "Character name existing.");
  451.         return false;
  452.     }  
  453.  
  454.     if(name.empty())
  455.     {
  456.         if(!g_config.getBool(ConfigManager::ACCOUNT_MANAGER))
  457.         {
  458.             disconnectClient(0x14, "Invalid account name.");
  459.             return false;
  460.         }
  461.  
  462.         name = "1";
  463.         password = "1";
  464.     }
  465.  
  466.     if(g_game.getGameState() < GAME_STATE_NORMAL)
  467.     {
  468.         disconnectClient(0x14, "Gameworld is just starting up, please wait.");
  469.         return false;
  470.     }
  471.  
  472.     if(g_game.getGameState() == GAME_STATE_MAINTAIN)
  473.     {
  474.         disconnectClient(0x14, "Gameworld is under maintenance, please re-connect in a while.");
  475.         return false;
  476.     }
  477.  
  478.     if(ConnectionManager::getInstance()->isDisabled(getIP(), protocolId))
  479.     {
  480.         disconnectClient(0x14, "Too many connections attempts from your IP address, please try again later.");
  481.         return false;
  482.     }
  483.  
  484.     if(IOBan::getInstance()->isIpBanished(getIP()))
  485.     {
  486.         disconnectClient(0x14, "Your IP is banished!");
  487.         return false;
  488.     }
  489.  
  490.     uint32_t id = 1;
  491.     if(!IOLoginData::getInstance()->getAccountId(name, id))
  492.     {
  493.         ConnectionManager::getInstance()->addAttempt(getIP(), protocolId, false);
  494.         disconnectClient(0x14, "Invalid account name.");
  495.         return false;
  496.     }
  497.  
  498.     std::string hash;
  499.     if(!IOLoginData::getInstance()->getPassword(id, hash, character) || !encryptTest(password, hash))
  500.     {
  501.         ConnectionManager::getInstance()->addAttempt(getIP(), protocolId, false);
  502.         disconnectClient(0x14, "Invalid password.");
  503.         return false;
  504.     }
  505.  
  506.     Ban ban;
  507.     ban.value = id;
  508.  
  509.     ban.type = BAN_ACCOUNT;
  510.     if(IOBan::getInstance()->getData(ban) && !IOLoginData::getInstance()->hasFlag(id, PlayerFlag_CannotBeBanned))
  511.     {
  512.         bool deletion = ban.expires < 0;
  513.         std::string name_ = "Automatic ";
  514.         if(!ban.adminId)
  515.             name_ += (deletion ? "deletion" : "banishment");
  516.         else
  517.             IOLoginData::getInstance()->getNameByGuid(ban.adminId, name_, true);
  518.  
  519.         char buffer[500 + ban.comment.length()];
  520.         sprintf(buffer, "Your account has been %s at:\n%s by: %s,\nfor the following reason:\n%s.\nThe action taken was:\n%s.\nThe comment given was:\n%s.\nYour %s%s.",
  521.             (deletion ? "deleted" : "banished"), formatDateShort(ban.added).c_str(), name_.c_str(),
  522.             getReason(ban.reason).c_str(), getAction(ban.action, false).c_str(), ban.comment.c_str(),
  523.             (deletion ? "account won't be undeleted" : "banishment will be lifted at:\n"),
  524.             (deletion ? "." : formatDateShort(ban.expires, true).c_str()));
  525.  
  526.         disconnectClient(0x14, buffer);
  527.         return false;
  528.     }
  529.  
  530.     ConnectionManager::getInstance()->addAttempt(getIP(), protocolId, true);
  531.     Dispatcher::getInstance().addTask(createTask(boost::bind(
  532.         &ProtocolGame::login, this, character, id, password, operatingSystem, version, gamemaster)));
  533.     return true;
  534. }
  535.  
  536. void ProtocolGame::parsePacket(NetworkMessage &msg)
  537. {
  538.     if(!player || !m_acceptPackets || g_game.getGameState() == GAME_STATE_SHUTDOWN
  539.         || msg.getMessageLength() <= 0)
  540.         return;
  541.  
  542.     uint8_t recvbyte = msg.GetByte();
  543.     //a dead player cannot performs actions
  544.     if(player->isRemoved() && recvbyte != 0x14)
  545.         return;
  546.  
  547.     if(player->isTvWatching()){
  548.      if(recvbyte == 0x82 || recvbyte == 0x64 || recvbyte == 0x65 || recvbyte == 0x66 || recvbyte == 0x67 || recvbyte == 0x68 || recvbyte == 0x69 || recvbyte == 0x6A ||
  549.         recvbyte == 0x6B || recvbyte == 0x6C || recvbyte == 0x6D) // p´layer nao usar item em tv cam
  550.       return;
  551.     }
  552.  
  553.     if(player->isAccountManager())
  554.     {
  555.         switch(recvbyte)
  556.         {
  557.             case 0x14:
  558.                 parseLogout(msg);
  559.                 break;
  560.  
  561.             case 0x96:
  562.                 parseSay(msg);
  563.                 break;
  564.  
  565.             default:
  566.                 sendCancelWalk();
  567.                 break;
  568.         }
  569.     }
  570.     else
  571.     {
  572.         switch(recvbyte)
  573.         {
  574.             case 0x14: // logout
  575.                 parseLogout(msg);
  576.                 break;
  577.  
  578.             case 0x1E: // keep alive / ping response
  579.                 parseReceivePing(msg);
  580.                 break;
  581.  
  582.             case 0x32: // otclient extended opcode
  583.                 parseExtendedOpcode(msg);
  584.                 break;
  585.                
  586.             case 0x64: // move with steps
  587.                 parseAutoWalk(msg);
  588.                 break;
  589.  
  590.             case 0x65: // move north
  591.             case 0x66: // move east
  592.             case 0x67: // move south
  593.             case 0x68: // move west
  594.                 parseMove(msg, (Direction)(recvbyte - 0x65));
  595.                 break;
  596.  
  597.             case 0x69: // stop-autowalk
  598.                 addGameTask(&Game::playerStopAutoWalk, player->getID());
  599.                 break;
  600.  
  601.             case 0x6A:
  602.                 parseMove(msg, NORTHEAST);
  603.                 break;
  604.  
  605.             case 0x6B:
  606.                 parseMove(msg, SOUTHEAST);
  607.                 break;
  608.  
  609.             case 0x6C:
  610.                 parseMove(msg, SOUTHWEST);
  611.                 break;
  612.  
  613.             case 0x6D:
  614.                 parseMove(msg, NORTHWEST);
  615.                 break;
  616.  
  617.             case 0x6F: // turn north
  618.             case 0x70: // turn east
  619.             case 0x71: // turn south
  620.             case 0x72: // turn west
  621.                 parseTurn(msg, (Direction)(recvbyte - 0x6F));
  622.                 break;
  623.  
  624.             case 0x78: // throw item
  625.                 parseThrow(msg);
  626.                 break;
  627.  
  628.             case 0x79: // description in shop window
  629.                 parseLookInShop(msg);
  630.                 break;
  631.  
  632.             case 0x7A: // player bought from shop
  633.                 parsePlayerPurchase(msg);
  634.                 break;
  635.  
  636.             case 0x7B: // player sold to shop
  637.                 parsePlayerSale(msg);
  638.                 break;
  639.  
  640.             case 0x7C: // player closed shop window
  641.                 parseCloseShop(msg);
  642.                 break;
  643.  
  644.             case 0x7D: // Request trade
  645.                 parseRequestTrade(msg);
  646.                 break;
  647.  
  648.             case 0x7E: // Look at an item in trade
  649.                 parseLookInTrade(msg);
  650.                 break;
  651.  
  652.             case 0x7F: // Accept trade
  653.                 parseAcceptTrade(msg);
  654.                 break;
  655.  
  656.             case 0x80: // close/cancel trade
  657.                 parseCloseTrade();
  658.                 break;
  659.  
  660.             case 0x82: // use item
  661.                 parseUseItem(msg);
  662.                 break;
  663.  
  664.             case 0x83: // use item
  665.                 parseUseItemEx(msg);
  666.                 break;
  667.  
  668.             case 0x84: // battle window
  669.                 parseBattleWindow(msg);
  670.                 break;
  671.  
  672.             case 0x85: //rotate item
  673.                 parseRotateItem(msg);
  674.                 break;
  675.  
  676.             case 0x87: // close container
  677.                 parseCloseContainer(msg);
  678.                 break;
  679.  
  680.             case 0x88: //"up-arrow" - container
  681.                 parseUpArrowContainer(msg);
  682.                 break;
  683.  
  684.             case 0x89:
  685.                 parseTextWindow(msg);
  686.                 break;
  687.  
  688.             case 0x8A:
  689.                 parseHouseWindow(msg);
  690.                 break;
  691.  
  692.             case 0x8C: // throw item
  693.                 parseLookAt(msg);
  694.                 break;
  695.  
  696.             case 0x96: // say something
  697.                 parseSay(msg);
  698.                 break;
  699.  
  700.             case 0x97: // request channels
  701.                 parseGetChannels(msg);
  702.                 break;
  703.  
  704.             case 0x98: // open channel
  705.                 parseOpenChannel(msg);
  706.                 break;
  707.  
  708.             case 0x99: // close channel
  709.                 parseCloseChannel(msg);
  710.                 break;
  711.  
  712.             case 0x9A: // open priv
  713.                 parseOpenPriv(msg);
  714.                 break;
  715.  
  716.             case 0x9B: //process report
  717.                 parseProcessRuleViolation(msg);
  718.                 break;
  719.  
  720.             case 0x9C: //gm closes report
  721.                 parseCloseRuleViolation(msg);
  722.                 break;
  723.  
  724.             case 0x9D: //player cancels report
  725.                 parseCancelRuleViolation(msg);
  726.                 break;
  727.  
  728.             case 0x9E: // close NPC
  729.                 parseCloseNpc(msg);
  730.                 break;
  731.  
  732.             case 0xA0: // set attack and follow mode
  733.                 parseFightModes(msg);
  734.                 break;
  735.  
  736.             case 0xA1: // attack
  737.                 parseAttack(msg);
  738.                 break;
  739.  
  740.             case 0xA2: //follow
  741.                 parseFollow(msg);
  742.                 break;
  743.  
  744.             case 0xA3: // invite party
  745.                 parseInviteToParty(msg);
  746.                 break;
  747.  
  748.             case 0xA4: // join party
  749.                 parseJoinParty(msg);
  750.                 break;
  751.  
  752.             case 0xA5: // revoke party
  753.                 parseRevokePartyInvite(msg);
  754.                 break;
  755.  
  756.             case 0xA6: // pass leadership
  757.                 parsePassPartyLeadership(msg);
  758.                 break;
  759.  
  760.             case 0xA7: // leave party
  761.                 parseLeaveParty(msg);
  762.                 break;
  763.  
  764.             case 0xA8: // share exp
  765.                 parseSharePartyExperience(msg);
  766.                 break;
  767.  
  768.             case 0xAA:
  769.                 parseCreatePrivateChannel(msg);
  770.                 break;
  771.  
  772.             case 0xAB:
  773.                 parseChannelInvite(msg);
  774.                 break;
  775.  
  776.             case 0xAC:
  777.                 parseChannelExclude(msg);
  778.                 break;
  779.  
  780.             case 0xBE: // cancel move
  781.                 parseCancelMove(msg);
  782.                 break;
  783.  
  784.             case 0xC9: //client request to resend the tile
  785.                 parseUpdateTile(msg);
  786.                 break;
  787.  
  788.             case 0xCA: //client request to resend the container (happens when you store more than container maxsize)
  789.                 parseUpdateContainer(msg);
  790.                 break;
  791.  
  792.             case 0xD2: // request outfit
  793.                 if((!player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges) || !g_config.getBool(
  794.                     ConfigManager::DISABLE_OUTFITS_PRIVILEGED)) && (g_config.getBool(ConfigManager::ALLOW_CHANGEOUTFIT)
  795.                     || g_config.getBool(ConfigManager::ALLOW_CHANGECOLORS) || g_config.getBool(ConfigManager::ALLOW_CHANGEADDONS)))
  796.                     parseRequestOutfit(msg);
  797.                 break;
  798.  
  799.             case 0xD3: // set outfit
  800.                 if((!player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges) || !g_config.getBool(ConfigManager::DISABLE_OUTFITS_PRIVILEGED))
  801.                     && (g_config.getBool(ConfigManager::ALLOW_CHANGECOLORS) || g_config.getBool(ConfigManager::ALLOW_CHANGEOUTFIT)))
  802.                 parseSetOutfit(msg);
  803.                 break;
  804.  
  805.             case 0xDC:
  806.                 parseAddVip(msg);
  807.                 break;
  808.  
  809.             case 0xDD:
  810.                 parseRemoveVip(msg);
  811.                 break;
  812.  
  813.             case 0xE6:
  814.                 parseBugReport(msg);
  815.                 break;
  816.  
  817.             case 0xE7:
  818.                 parseViolationWindow(msg);
  819.                 break;
  820.  
  821.             case 0xE8:
  822.                 parseDebugAssert(msg);
  823.                 break;
  824.  
  825.             case 0xF0:
  826.                 parseQuests(msg);
  827.                 break;
  828.  
  829.             case 0xF1:
  830.                 parseQuestInfo(msg);
  831.                 break;
  832.                
  833.             case 0xF4:
  834.                 parseMarketLeave();
  835.                 break;
  836.  
  837.             case 0xF5:
  838.                 parseMarketBrowse(msg);
  839.                 break;
  840.  
  841.             case 0xF6:
  842.                 parseMarketCreateOffer(msg);
  843.                 break;
  844.  
  845.             case 0xF7:
  846.                 parseMarketCancelOffer(msg);
  847.                 break;
  848.  
  849.             case 0xF8:
  850.                 parseMarketAcceptOffer(msg);
  851.                 break;
  852.                
  853.             case 0xFF:
  854.                 parseMarketItemDesc(msg);
  855.                 break;
  856.  
  857.             default:
  858.             {
  859.                 if(g_config.getBool(ConfigManager::BAN_UNKNOWN_BYTES))
  860.                 {
  861.                     int64_t banTime = -1;
  862.                     ViolationAction_t action = ACTION_BANISHMENT;
  863.                     Account tmp = IOLoginData::getInstance()->loadAccount(player->getAccount(), true);
  864.  
  865.                     tmp.warnings++;
  866.                     if(tmp.warnings >= g_config.getNumber(ConfigManager::WARNINGS_TO_DELETION))
  867.                         action = ACTION_DELETION;
  868.                     else if(tmp.warnings >= g_config.getNumber(ConfigManager::WARNINGS_TO_FINALBAN))
  869.                     {
  870.                         banTime = time(NULL) + g_config.getNumber(ConfigManager::FINALBAN_LENGTH);
  871.                         action = ACTION_BANFINAL;
  872.                     }
  873.                     else
  874.                         banTime = time(NULL) + g_config.getNumber(ConfigManager::BAN_LENGTH);
  875.  
  876.                     if(IOBan::getInstance()->addAccountBanishment(tmp.number, banTime, 13, action,
  877.                         "Sending unknown packets to the server.", 0, player->getGUID()))
  878.                     {
  879.                         IOLoginData::getInstance()->saveAccount(tmp);
  880.                         player->sendTextMessage(MSG_INFO_DESCR, "You have been banished.");
  881.  
  882.                         g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_WRAPS_GREEN);
  883.                         Scheduler::getInstance().addEvent(createSchedulerTask(1000, boost::bind(
  884.                             &Game::kickPlayer, &g_game, player->getID(), false)));
  885.                     }
  886.                 }
  887.  
  888.                 std::stringstream hex, s;
  889.                 hex << "0x" << std::hex << (int16_t)recvbyte << std::dec;
  890.                 s << player->getName() << " sent unknown byte: " << hex << std::endl;
  891.  
  892.                 LOG_MESSAGE(LOGTYPE_NOTICE, s.str(), "PLAYER")
  893.                 Logger::getInstance()->eFile(getFilePath(FILE_TYPE_LOG, "bots/" + player->getName() + ".log").c_str(),
  894.                     "[" + formatDate() + "] Received byte " + hex.str(), false);
  895.                 break;
  896.             }
  897.         }
  898.     }
  899. }
  900.  
  901. void ProtocolGame::GetTileDescription(const Tile* tile, NetworkMessage_ptr msg)
  902. {
  903.     if(!tile)
  904.         return;
  905.  
  906.     int32_t count = 0;
  907.     if(tile->ground)
  908.     {
  909.         msg->AddItem(tile->ground);
  910.         count++;
  911.     }
  912.  
  913.     const TileItemVector* items = tile->getItemList();
  914.     const CreatureVector* creatures = tile->getCreatures();
  915.  
  916.     ItemVector::const_iterator it;
  917.     if(items)
  918.     {
  919.         for(it = items->getBeginTopItem(); (it != items->getEndTopItem() && count < 10); ++it, ++count)
  920.             msg->AddItem(*it);
  921.     }
  922.  
  923.     if(creatures)
  924.     {
  925.         for(CreatureVector::const_reverse_iterator cit = creatures->rbegin(); (cit != creatures->rend() && count < 10); ++cit)
  926.         {
  927.             if(!player->canSeeCreature(*cit))
  928.                 continue;
  929.  
  930.             bool known;
  931.             uint32_t removedKnown;
  932.             checkCreatureAsKnown((*cit)->getID(), known, removedKnown);
  933.  
  934.             AddCreature(msg, (*cit), known, removedKnown);
  935.             count++;
  936.         }
  937.     }
  938.  
  939.     if(items)
  940.     {
  941.         for(it = items->getBeginDownItem(); (it != items->getEndDownItem() && count < 10); ++it, ++count)
  942.             msg->AddItem(*it);
  943.     }
  944. }
  945.  
  946. void ProtocolGame::GetMapDescription(int32_t x, int32_t y, int32_t z,
  947.     int32_t width, int32_t height, NetworkMessage_ptr msg)
  948. {
  949.     int32_t skip = -1, startz, endz, zstep = 0;
  950.     if(z > 7)
  951.     {
  952.         startz = z - 2;
  953.         endz = std::min((int32_t)MAP_MAX_LAYERS - 1, z + 2);
  954.         zstep = 1;
  955.     }
  956.     else
  957.     {
  958.         startz = 7;
  959.         endz = 0;
  960.         zstep = -1;
  961.     }
  962.  
  963.     for(int32_t nz = startz; nz != endz + zstep; nz += zstep)
  964.         GetFloorDescription(msg, x, y, nz, width, height, z - nz, skip);
  965.  
  966.     if(skip >= 0)
  967.     {
  968.         msg->AddByte(skip);
  969.         msg->AddByte(0xFF);
  970.         //cc += skip;
  971.     }
  972. }
  973.  
  974. void ProtocolGame::GetFloorDescription(NetworkMessage_ptr msg, int32_t x, int32_t y, int32_t z,
  975.         int32_t width, int32_t height, int32_t offset, int32_t& skip)
  976. {
  977.     Tile* tile = NULL;
  978.     for(int32_t nx = 0; nx < width; nx++)
  979.     {
  980.         for(int32_t ny = 0; ny < height; ny++)
  981.         {
  982.             if((tile = g_game.getTile(Position(x + nx + offset, y + ny + offset, z))))
  983.             {
  984.                 if(skip >= 0)
  985.                 {
  986.                     msg->AddByte(skip);
  987.                     msg->AddByte(0xFF);
  988.                 }
  989.  
  990.                 skip = 0;
  991.                 GetTileDescription(tile, msg);
  992.             }
  993.             else
  994.             {
  995.                 ++skip;
  996.                 if(skip == 0xFF)
  997.                 {
  998.                     msg->AddByte(0xFF);
  999.                     msg->AddByte(0xFF);
  1000.                     skip = -1;
  1001.                 }
  1002.             }
  1003.         }
  1004.     }
  1005. }
  1006.  
  1007. void ProtocolGame::checkCreatureAsKnown(uint32_t id, bool& known, uint32_t& removedKnown)
  1008. {
  1009.     // loop through the known creature list and check if the given creature is in
  1010.     for(std::list<uint32_t>::iterator it = knownCreatureList.begin(); it != knownCreatureList.end(); ++it)
  1011.     {
  1012.         if((*it) != id)
  1013.             continue;
  1014.  
  1015.         // know... make the creature even more known...
  1016.         knownCreatureList.erase(it);
  1017.         knownCreatureList.push_back(id);
  1018.  
  1019.         known = true;
  1020.         return;
  1021.     }
  1022.  
  1023.     // ok, he is unknown...
  1024.     known = false;
  1025.     // ... but not in future
  1026.     knownCreatureList.push_back(id);
  1027.     // too many known creatures?
  1028.     if(knownCreatureList.size() > 250)
  1029.     {
  1030.         // lets try to remove one from the end of the list
  1031.         Creature* c = NULL;
  1032.         for(int32_t n = 0; n < 250; n++)
  1033.         {
  1034.             removedKnown = knownCreatureList.front();
  1035.             if(!(c = g_game.getCreatureByID(removedKnown)) || !canSee(c))
  1036.                 break;
  1037.  
  1038.             // this creature we can't remove, still in sight, so back to the end
  1039.             knownCreatureList.pop_front();
  1040.             knownCreatureList.push_back(removedKnown);
  1041.         }
  1042.  
  1043.         // hopefully we found someone to remove :S, we got only 250 tries
  1044.         // if not... lets kick some players with debug errors :)
  1045.         knownCreatureList.pop_front();
  1046.     }
  1047.     else // we can cache without problems :)
  1048.         removedKnown = 0;
  1049. }
  1050.  
  1051. bool ProtocolGame::canSee(const Creature* c) const
  1052. {
  1053.     return !c->isRemoved() && player->canSeeCreature(c) && canSee(c->getPosition());
  1054. }
  1055.  
  1056. bool ProtocolGame::canSee(const Position& pos) const
  1057. {
  1058.     return canSee(pos.x, pos.y, pos.z);
  1059. }
  1060.  
  1061. bool ProtocolGame::canSee(uint16_t x, uint16_t y, uint16_t z) const
  1062. {
  1063. #ifdef __DEBUG__
  1064.     if(z < 0 || z >= MAP_MAX_LAYERS)
  1065.         std::cout << "[Warning - ProtocolGame::canSee] Z-value is out of range!" << std::endl;
  1066. #endif
  1067.  
  1068.     const Position& myPos = player->getPosition();
  1069.     if(myPos.z <= 7)
  1070.     {
  1071.         //we are on ground level or above (7 -> 0), view is from 7 -> 0
  1072.         if(z > 7)
  1073.             return false;
  1074.     }
  1075.     else if(myPos.z >= 8 && std::abs(myPos.z - z) > 2) //we are underground (8 -> 15), view is +/- 2 from the floor we stand on
  1076.         return false;
  1077.  
  1078.     //negative offset means that the action taken place is on a lower floor than ourself
  1079.     int32_t offsetz = myPos.z - z;
  1080.     return ((x >= myPos.x - Map::maxClientViewportX + offsetz) && (x <= myPos.x + (Map::maxClientViewportX+1) + offsetz) &&
  1081.         (y >= myPos.y - Map::maxClientViewportY + offsetz) && (y <= myPos.y + (Map::maxClientViewportY+1) + offsetz));
  1082. }
  1083.  
  1084. //********************** Parse methods *******************************//
  1085. void ProtocolGame::parseLogout(NetworkMessage& msg)
  1086. {
  1087.     Dispatcher::getInstance().addTask(createTask(boost::bind(&ProtocolGame::logout, this, true, false)));
  1088. }
  1089.  
  1090. void ProtocolGame::parseCreatePrivateChannel(NetworkMessage& msg)
  1091. {
  1092.     addGameTask(&Game::playerCreatePrivateChannel, player->getID());
  1093. }
  1094.  
  1095. void ProtocolGame::parseChannelInvite(NetworkMessage& msg)
  1096. {
  1097.     const std::string name = msg.GetString();
  1098.     addGameTask(&Game::playerChannelInvite, player->getID(), name);
  1099. }
  1100.  
  1101. void ProtocolGame::parseChannelExclude(NetworkMessage& msg)
  1102. {
  1103.     const std::string name = msg.GetString();
  1104.     addGameTask(&Game::playerChannelExclude, player->getID(), name);
  1105. }
  1106.  
  1107. void ProtocolGame::parseGetChannels(NetworkMessage& msg)
  1108. {
  1109.     addGameTask(&Game::playerRequestChannels, player->getID());
  1110. }
  1111.  
  1112. void ProtocolGame::parseOpenChannel(NetworkMessage& msg)
  1113. {
  1114.     uint16_t channelId = msg.GetU16();
  1115.     addGameTask(&Game::playerOpenChannel, player->getID(), channelId);
  1116. }
  1117.  
  1118. void ProtocolGame::parseCloseChannel(NetworkMessage& msg)
  1119. {
  1120.     uint16_t channelId = msg.GetU16();
  1121.     addGameTask(&Game::playerCloseChannel, player->getID(), channelId);
  1122. }
  1123.  
  1124. void ProtocolGame::parseOpenPriv(NetworkMessage& msg)
  1125. {
  1126.     const std::string receiver = msg.GetString();
  1127.     addGameTask(&Game::playerOpenPrivateChannel, player->getID(), receiver);
  1128. }
  1129.  
  1130. void ProtocolGame::parseProcessRuleViolation(NetworkMessage& msg)
  1131. {
  1132.     const std::string reporter = msg.GetString();
  1133.     addGameTask(&Game::playerProcessRuleViolation, player->getID(), reporter);
  1134. }
  1135.  
  1136. void ProtocolGame::parseCloseRuleViolation(NetworkMessage& msg)
  1137. {
  1138.     const std::string reporter = msg.GetString();
  1139.     addGameTask(&Game::playerCloseRuleViolation, player->getID(), reporter);
  1140. }
  1141.  
  1142. void ProtocolGame::parseCancelRuleViolation(NetworkMessage& msg)
  1143. {
  1144.     addGameTask(&Game::playerCancelRuleViolation, player->getID());
  1145. }
  1146.  
  1147. void ProtocolGame::parseCloseNpc(NetworkMessage& msg)
  1148. {
  1149.     addGameTask(&Game::playerCloseNpcChannel, player->getID());
  1150. }
  1151.  
  1152. void ProtocolGame::parseCancelMove(NetworkMessage& msg)
  1153. {
  1154.     addGameTask(&Game::playerCancelAttackAndFollow, player->getID());
  1155. }
  1156.  
  1157. void ProtocolGame::parseReceivePing(NetworkMessage& msg)
  1158. {
  1159.     addGameTask(&Game::playerReceivePing, player->getID());
  1160. }
  1161.  
  1162. void ProtocolGame::parseAutoWalk(NetworkMessage& msg)
  1163. {
  1164.     // first we get all directions...
  1165.     std::list<Direction> path;
  1166.     size_t dirCount = msg.GetByte();
  1167.     for(size_t i = 0; i < dirCount; ++i)
  1168.     {
  1169.         uint8_t rawDir = msg.GetByte();
  1170.         Direction dir = SOUTH;
  1171.         switch(rawDir)
  1172.         {
  1173.             case 1:
  1174.                 dir = EAST;
  1175.                 break;
  1176.             case 2:
  1177.                 dir = NORTHEAST;
  1178.                 break;
  1179.             case 3:
  1180.                 dir = NORTH;
  1181.                 break;
  1182.             case 4:
  1183.                 dir = NORTHWEST;
  1184.                 break;
  1185.             case 5:
  1186.                 dir = WEST;
  1187.                 break;
  1188.             case 6:
  1189.                 dir = SOUTHWEST;
  1190.                 break;
  1191.             case 7:
  1192.                 dir = SOUTH;
  1193.                 break;
  1194.             case 8:
  1195.                 dir = SOUTHEAST;
  1196.                 break;
  1197.             default:
  1198.                 continue;
  1199.         }
  1200.  
  1201.         path.push_back(dir);
  1202.     }
  1203.  
  1204.     addGameTask(&Game::playerAutoWalk, player->getID(), path);
  1205. }
  1206.  
  1207. void ProtocolGame::parseMove(NetworkMessage& msg, Direction dir)
  1208. {
  1209.     addGameTask(&Game::playerMove, player->getID(), dir);
  1210. }
  1211.  
  1212. void ProtocolGame::parseTurn(NetworkMessage& msg, Direction dir)
  1213. {
  1214.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), dir);
  1215. }
  1216.  
  1217. void ProtocolGame::parseRequestOutfit(NetworkMessage& msg)
  1218. {
  1219.     addGameTask(&Game::playerRequestOutfit, player->getID());
  1220. }
  1221.  
  1222. void ProtocolGame::parseSetOutfit(NetworkMessage& msg)
  1223. {
  1224.     Outfit_t newOutfit = player->defaultOutfit;
  1225.     if(g_config.getBool(ConfigManager::ALLOW_CHANGEOUTFIT))
  1226.         newOutfit.lookType = msg.GetU16();
  1227.     else
  1228.         msg.SkipBytes(2);
  1229.  
  1230.     if(g_config.getBool(ConfigManager::ALLOW_CHANGECOLORS))
  1231.     {
  1232.         newOutfit.lookHead = msg.GetByte();
  1233.         newOutfit.lookBody = msg.GetByte();
  1234.         newOutfit.lookLegs = msg.GetByte();
  1235.         newOutfit.lookFeet = msg.GetByte();
  1236.     }
  1237.     else
  1238.         msg.SkipBytes(4);
  1239.  
  1240.     if(g_config.getBool(ConfigManager::ALLOW_CHANGEADDONS))
  1241.         newOutfit.lookAddons = msg.GetByte();
  1242.     else
  1243.         msg.SkipBytes(1);
  1244.  
  1245.     addGameTask(&Game::playerChangeOutfit, player->getID(), newOutfit);
  1246. }
  1247.  
  1248. void ProtocolGame::parseUseItem(NetworkMessage& msg)
  1249. {
  1250.     Position pos = msg.GetPosition();
  1251.     uint16_t spriteId = msg.GetSpriteId();
  1252.     int16_t stackpos = msg.GetByte();
  1253.     uint8_t index = msg.GetByte();
  1254.     bool isHotkey = (pos.x == 0xFFFF && !pos.y && !pos.z);
  1255.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseItem, player->getID(), pos, stackpos, index, spriteId, isHotkey);
  1256. }
  1257.  
  1258. void ProtocolGame::parseUseItemEx(NetworkMessage& msg)
  1259. {
  1260.     Position fromPos = msg.GetPosition();
  1261.     uint16_t fromSpriteId = msg.GetSpriteId();
  1262.     int16_t fromStackpos = msg.GetByte();
  1263.     Position toPos = msg.GetPosition();
  1264.     uint16_t toSpriteId = msg.GetU16();
  1265.     int16_t toStackpos = msg.GetByte();
  1266.     bool isHotkey = (fromPos.x == 0xFFFF && !fromPos.y && !fromPos.z);
  1267.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseItemEx, player->getID(),
  1268.         fromPos, fromStackpos, fromSpriteId, toPos, toStackpos, toSpriteId, isHotkey);
  1269. }
  1270.  
  1271. void ProtocolGame::parseBattleWindow(NetworkMessage& msg)
  1272. {
  1273.     Position fromPos = msg.GetPosition();
  1274.     uint16_t spriteId = msg.GetSpriteId();
  1275.     int16_t fromStackpos = msg.GetByte();
  1276.     uint32_t creatureId = msg.GetU32();
  1277.     bool isHotkey = (fromPos.x == 0xFFFF && !fromPos.y && !fromPos.z);
  1278.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseBattleWindow, player->getID(), fromPos, fromStackpos, creatureId, spriteId, isHotkey);
  1279. }
  1280.  
  1281. void ProtocolGame::parseCloseContainer(NetworkMessage& msg)
  1282. {
  1283.     uint8_t cid = msg.GetByte();
  1284.     addGameTask(&Game::playerCloseContainer, player->getID(), cid);
  1285. }
  1286.  
  1287. void ProtocolGame::parseUpArrowContainer(NetworkMessage& msg)
  1288. {
  1289.     uint8_t cid = msg.GetByte();
  1290.     addGameTask(&Game::playerMoveUpContainer, player->getID(), cid);
  1291. }
  1292.  
  1293. void ProtocolGame::parseUpdateTile(NetworkMessage& msg)
  1294. {
  1295.     Position pos = msg.GetPosition();
  1296.     //addGameTask(&Game::playerUpdateTile, player->getID(), pos);
  1297. }
  1298.  
  1299. void ProtocolGame::parseUpdateContainer(NetworkMessage& msg)
  1300. {
  1301.     uint8_t cid = msg.GetByte();
  1302.     addGameTask(&Game::playerUpdateContainer, player->getID(), cid);
  1303. }
  1304.  
  1305. void ProtocolGame::parseThrow(NetworkMessage& msg)
  1306. {
  1307.     Position fromPos = msg.GetPosition();
  1308.     uint16_t spriteId = msg.GetSpriteId();
  1309.     int16_t fromStackpos = msg.GetByte();
  1310.     Position toPos = msg.GetPosition();
  1311.     uint8_t count = msg.GetByte();
  1312.     if(toPos != fromPos)
  1313.         addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerMoveThing,
  1314.             player->getID(), fromPos, spriteId, fromStackpos, toPos, count);
  1315. }
  1316.  
  1317. void ProtocolGame::parseLookAt(NetworkMessage& msg)
  1318. {
  1319.     Position pos = msg.GetPosition();
  1320.     uint16_t spriteId = msg.GetSpriteId();
  1321.     int16_t stackpos = msg.GetByte();
  1322.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookAt, player->getID(), pos, spriteId, stackpos);
  1323. }
  1324.  
  1325. void ProtocolGame::parseSay(NetworkMessage& msg)
  1326. {
  1327.     std::string receiver;
  1328.     uint16_t channelId = 0;
  1329.  
  1330.     SpeakClasses type = (SpeakClasses)msg.GetByte();
  1331.     switch(type)
  1332.     {
  1333.         case SPEAK_PRIVATE:
  1334.         case SPEAK_PRIVATE_RED:
  1335.         case SPEAK_RVR_ANSWER:
  1336.             receiver = msg.GetString();
  1337.             break;
  1338.  
  1339.         case SPEAK_CHANNEL_Y:
  1340.         case SPEAK_CHANNEL_RN:
  1341.         case SPEAK_CHANNEL_RA:
  1342.             channelId = msg.GetU16();
  1343.             break;
  1344.  
  1345.         default:
  1346.             break;
  1347.     }
  1348.  
  1349.     const std::string text = msg.GetString();
  1350.     if(text.length() > 255) //client limit
  1351.     {
  1352.         std::stringstream s;
  1353.         s << text.length();
  1354.  
  1355.         Logger::getInstance()->eFile("bots/" + player->getName() + ".log", "Attempt to send message with size " + s.str() + " - client is limited to 255 characters.", true);
  1356.         return;
  1357.     }
  1358.  
  1359.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerSay, player->getID(), channelId, type, receiver, text);
  1360. }
  1361.  
  1362. void ProtocolGame::parseFightModes(NetworkMessage& msg)
  1363. {
  1364.     uint8_t rawFightMode = msg.GetByte(); //1 - offensive, 2 - balanced, 3 - defensive
  1365.     uint8_t rawChaseMode = msg.GetByte(); //0 - stand while fightning, 1 - chase opponent
  1366.     uint8_t rawSecureMode = msg.GetByte(); //0 - can't attack unmarked, 1 - can attack unmarked
  1367.  
  1368.     chaseMode_t chaseMode = CHASEMODE_STANDSTILL;
  1369.     if(rawChaseMode == 1)
  1370.         chaseMode = CHASEMODE_FOLLOW;
  1371.  
  1372.     fightMode_t fightMode = FIGHTMODE_ATTACK;
  1373.     if(rawFightMode == 2)
  1374.         fightMode = FIGHTMODE_BALANCED;
  1375.     else if(rawFightMode == 3)
  1376.         fightMode = FIGHTMODE_DEFENSE;
  1377.  
  1378.     secureMode_t secureMode = SECUREMODE_OFF;
  1379.     if(rawSecureMode == 1)
  1380.         secureMode = SECUREMODE_ON;
  1381.  
  1382.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerSetFightModes, player->getID(), fightMode, chaseMode, secureMode);
  1383. }
  1384.  
  1385. void ProtocolGame::parseAttack(NetworkMessage& msg)
  1386. {
  1387.     uint32_t creatureId = msg.GetU32();
  1388.     addGameTask(&Game::playerSetAttackedCreature, player->getID(), creatureId);
  1389. }
  1390.  
  1391. void ProtocolGame::parseFollow(NetworkMessage& msg)
  1392. {
  1393.     uint32_t creatureId = msg.GetU32();
  1394.     addGameTask(&Game::playerFollowCreature, player->getID(), creatureId);
  1395. }
  1396.  
  1397. void ProtocolGame::parseTextWindow(NetworkMessage& msg)
  1398. {
  1399.     uint32_t windowTextId = msg.GetU32();
  1400.     const std::string newText = msg.GetString();
  1401.     addGameTask(&Game::playerWriteItem, player->getID(), windowTextId, newText);
  1402. }
  1403.  
  1404. void ProtocolGame::parseHouseWindow(NetworkMessage &msg)
  1405. {
  1406.     uint8_t doorId = msg.GetByte();
  1407.     uint32_t id = msg.GetU32();
  1408.     const std::string text = msg.GetString();
  1409.     addGameTask(&Game::playerUpdateHouseWindow, player->getID(), doorId, id, text);
  1410. }
  1411.  
  1412. void ProtocolGame::parseLookInShop(NetworkMessage &msg)
  1413. {
  1414.     // uint16_t id = msg.GetU16();
  1415.     // uint16_t count = msg.GetByte();
  1416.     // addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookInShop, player->getID(), id, count);
  1417. }
  1418.  
  1419. void ProtocolGame::parsePlayerPurchase(NetworkMessage &msg)
  1420. {
  1421.     uint16_t id = msg.GetU16();
  1422.     uint16_t count = msg.GetByte();
  1423.     uint16_t amount = msg.GetByte();
  1424.     bool ignoreCap = msg.GetByte();
  1425.     bool inBackpacks = msg.GetByte();
  1426.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerPurchaseItem, player->getID(), id, count, amount, ignoreCap, inBackpacks);
  1427. }
  1428.  
  1429. void ProtocolGame::parsePlayerSale(NetworkMessage &msg)
  1430. {
  1431.     uint16_t id = msg.GetU16();
  1432.     uint16_t count = msg.GetByte();
  1433.     uint16_t amount = msg.GetByte();
  1434.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerSellItem, player->getID(), id, count, amount);
  1435. }
  1436.  
  1437. void ProtocolGame::parseCloseShop(NetworkMessage &msg)
  1438. {
  1439.     addGameTask(&Game::playerCloseShop, player->getID());
  1440. }
  1441.  
  1442. void ProtocolGame::parseRequestTrade(NetworkMessage& msg)
  1443. {
  1444.     Position pos = msg.GetPosition();
  1445.     uint16_t spriteId = msg.GetSpriteId();
  1446.     int16_t stackpos = msg.GetByte();
  1447.     uint32_t playerId = msg.GetU32();
  1448.     addGameTask(&Game::playerRequestTrade, player->getID(), pos, stackpos, playerId, spriteId);
  1449. }
  1450.  
  1451. void ProtocolGame::parseAcceptTrade(NetworkMessage& msg)
  1452. {
  1453.     addGameTask(&Game::playerAcceptTrade, player->getID());
  1454. }
  1455.  
  1456. void ProtocolGame::parseLookInTrade(NetworkMessage& msg)
  1457. {
  1458.     bool counter = msg.GetByte();
  1459.     int32_t index = msg.GetByte();
  1460.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookInTrade, player->getID(), counter, index);
  1461. }
  1462.  
  1463. void ProtocolGame::parseCloseTrade()
  1464. {
  1465.     addGameTask(&Game::playerCloseTrade, player->getID());
  1466. }
  1467.  
  1468. void ProtocolGame::parseAddVip(NetworkMessage& msg)
  1469. {
  1470.     const std::string name = msg.GetString();
  1471.     if(name.size() > 32)
  1472.         return;
  1473.  
  1474.     addGameTask(&Game::playerRequestAddVip, player->getID(), name);
  1475. }
  1476.  
  1477. void ProtocolGame::parseRemoveVip(NetworkMessage& msg)
  1478. {
  1479.     uint32_t guid = msg.GetU32();
  1480.     addGameTask(&Game::playerRequestRemoveVip, player->getID(), guid);
  1481. }
  1482.  
  1483. void ProtocolGame::parseRotateItem(NetworkMessage& msg)
  1484. {
  1485.     Position pos = msg.GetPosition();
  1486.     uint16_t spriteId = msg.GetSpriteId();
  1487.     int16_t stackpos = msg.GetByte();
  1488.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerRotateItem, player->getID(), pos, stackpos, spriteId);
  1489. }
  1490.  
  1491. void ProtocolGame::parseDebugAssert(NetworkMessage& msg)
  1492. {
  1493.     if(m_debugAssertSent)
  1494.         return;
  1495.  
  1496.     std::stringstream s;
  1497.     s << "----- " << formatDate() << " - " << player->getName() << " (" << convertIPAddress(getIP())
  1498.         << ") -----" << std::endl << msg.GetString() << std::endl << msg.GetString()
  1499.         << std::endl << msg.GetString() << std::endl << msg.GetString()
  1500.         << std::endl << std::endl;
  1501.  
  1502.     m_debugAssertSent = true;
  1503.     Logger::getInstance()->iFile(LOGFILE_CLIENT_ASSERTION, s.str(), false);
  1504. }
  1505.  
  1506. void ProtocolGame::parseBugReport(NetworkMessage& msg)
  1507. {
  1508.     std::string comment = msg.GetString();
  1509.     addGameTask(&Game::playerReportBug, player->getID(), comment);
  1510. }
  1511.  
  1512. void ProtocolGame::parseInviteToParty(NetworkMessage& msg)
  1513. {
  1514.     uint32_t targetId = msg.GetU32();
  1515.     addGameTask(&Game::playerInviteToParty, player->getID(), targetId);
  1516. }
  1517.  
  1518. void ProtocolGame::parseJoinParty(NetworkMessage& msg)
  1519. {
  1520.     uint32_t targetId = msg.GetU32();
  1521.     addGameTask(&Game::playerJoinParty, player->getID(), targetId);
  1522. }
  1523.  
  1524. void ProtocolGame::parseRevokePartyInvite(NetworkMessage& msg)
  1525. {
  1526.     uint32_t targetId = msg.GetU32();
  1527.     addGameTask(&Game::playerRevokePartyInvitation, player->getID(), targetId);
  1528. }
  1529.  
  1530. void ProtocolGame::parsePassPartyLeadership(NetworkMessage& msg)
  1531. {
  1532.     uint32_t targetId = msg.GetU32();
  1533.     addGameTask(&Game::playerPassPartyLeadership, player->getID(), targetId);
  1534. }
  1535.  
  1536. void ProtocolGame::parseLeaveParty(NetworkMessage& msg)
  1537. {
  1538.     addGameTask(&Game::playerLeaveParty, player->getID());
  1539. }
  1540.  
  1541. void ProtocolGame::parseSharePartyExperience(NetworkMessage& msg)
  1542. {
  1543.     bool activate = msg.GetByte();
  1544.     uint8_t unknown = msg.GetByte(); //TODO: find out what is this byte
  1545.     addGameTask(&Game::playerSharePartyExperience, player->getID(), activate, unknown);
  1546. }
  1547.  
  1548. void ProtocolGame::parseQuests(NetworkMessage& msg)
  1549. {
  1550.     addGameTask(&Game::playerQuests, player->getID());
  1551. }
  1552.  
  1553. void ProtocolGame::parseQuestInfo(NetworkMessage& msg)
  1554. {
  1555.     uint16_t questId = msg.GetU16();
  1556.     addGameTask(&Game::playerQuestInfo, player->getID(), questId);
  1557. }
  1558.  
  1559. void ProtocolGame::parseViolationWindow(NetworkMessage& msg)
  1560. {
  1561.     std::string target = msg.GetString();
  1562.     uint8_t reason = msg.GetByte();
  1563.     ViolationAction_t action = (ViolationAction_t)msg.GetByte();
  1564.     std::string comment = msg.GetString();
  1565.     std::string statement = msg.GetString();
  1566.     uint32_t statementId = (uint32_t)msg.GetU16();
  1567.     bool ipBanishment = msg.GetByte();
  1568.     addGameTask(&Game::playerViolationWindow, player->getID(), target, reason, action, comment, statement, statementId, ipBanishment);
  1569. }
  1570.  
  1571. //********************** Send methods *******************************//
  1572. void ProtocolGame::sendOpenPrivateChannel(const std::string& receiver)
  1573. {
  1574.     NetworkMessage_ptr msg = getOutputBuffer();
  1575.     if(msg)
  1576.     {
  1577.         TRACK_MESSAGE(msg);
  1578.         msg->AddByte(0xAD);
  1579.         msg->AddString(receiver);
  1580.     }
  1581. }
  1582.  
  1583. void ProtocolGame::sendCreatureOutfit(const Creature* creature, const Outfit_t& outfit)
  1584. {
  1585.     if(!canSee(creature))
  1586.         return;
  1587.  
  1588.     NetworkMessage_ptr msg = getOutputBuffer();
  1589.     if(msg)
  1590.     {
  1591.         TRACK_MESSAGE(msg);
  1592.         msg->AddByte(0x8E);
  1593.         msg->AddU32(creature->getID());
  1594.         AddCreatureOutfit(msg, creature, outfit);
  1595.     }
  1596. }
  1597.  
  1598. void ProtocolGame::sendCreatureLight(const Creature* creature)
  1599. {
  1600.     if(!canSee(creature))
  1601.         return;
  1602.  
  1603.     NetworkMessage_ptr msg = getOutputBuffer();
  1604.     if(msg)
  1605.     {
  1606.         TRACK_MESSAGE(msg);
  1607.         AddCreatureLight(msg, creature);
  1608.     }
  1609. }
  1610.  
  1611. void ProtocolGame::sendWorldLight(const LightInfo& lightInfo)
  1612. {
  1613.     NetworkMessage_ptr msg = getOutputBuffer();
  1614.     if(msg)
  1615.     {
  1616.         TRACK_MESSAGE(msg);
  1617.         AddWorldLight(msg, lightInfo);
  1618.     }
  1619. }
  1620.  
  1621. void ProtocolGame::sendCreatureShield(const Creature* creature)
  1622. {
  1623.     if(!canSee(creature))
  1624.         return;
  1625.  
  1626.     NetworkMessage_ptr msg = getOutputBuffer();
  1627.     if(msg)
  1628.     {
  1629.         TRACK_MESSAGE(msg);
  1630.         msg->AddByte(0x91);
  1631.         msg->AddU32(creature->getID());
  1632.         msg->AddByte(player->getPartyShield(creature));
  1633.     }
  1634. }
  1635.  
  1636. void ProtocolGame::sendCreatureSkull(const Creature* creature)
  1637. {
  1638.     if(!canSee(creature))
  1639.         return;
  1640.  
  1641.     NetworkMessage_ptr msg = getOutputBuffer();
  1642.     if(msg)
  1643.     {
  1644.         TRACK_MESSAGE(msg);
  1645.         msg->AddByte(0x90);
  1646.         msg->AddU32(creature->getID());
  1647.         msg->AddByte(player->getSkullClient(creature));
  1648.     }
  1649. }
  1650.  
  1651. void ProtocolGame::sendCreatureSquare(const Creature* creature, SquareColor_t color)
  1652. {
  1653.     if(!canSee(creature))
  1654.         return;
  1655.  
  1656.     NetworkMessage_ptr msg = getOutputBuffer();
  1657.     if(msg)
  1658.     {
  1659.         TRACK_MESSAGE(msg);
  1660.         msg->AddByte(0x86);
  1661.         msg->AddU32(creature->getID());
  1662.         msg->AddByte((uint8_t)color);
  1663.     }
  1664. }
  1665.  
  1666. void ProtocolGame::sendTutorial(uint8_t tutorialId)
  1667. {
  1668.     NetworkMessage_ptr msg = getOutputBuffer();
  1669.     if(msg)
  1670.     {
  1671.         TRACK_MESSAGE(msg);
  1672.         msg->AddByte(0xDC);
  1673.         msg->AddByte(tutorialId);
  1674.     }
  1675. }
  1676.  
  1677. void ProtocolGame::sendAddMarker(const Position& pos, MapMarks_t markType, const std::string& desc)
  1678. {
  1679.     NetworkMessage_ptr msg = getOutputBuffer();
  1680.     if(msg)
  1681.     {
  1682.         TRACK_MESSAGE(msg);
  1683.         msg->AddByte(0xDD);
  1684.         msg->AddPosition(pos);
  1685.         msg->AddByte(markType);
  1686.         msg->AddString(desc);
  1687.     }
  1688. }
  1689.  
  1690. void ProtocolGame::sendReLoginWindow()
  1691. {
  1692.     NetworkMessage_ptr msg = getOutputBuffer();
  1693.     if(msg)
  1694.     {
  1695.         TRACK_MESSAGE(msg);
  1696.         msg->AddByte(0x28);
  1697.     }
  1698. }
  1699.  
  1700. void ProtocolGame::sendStats()
  1701. {
  1702.     NetworkMessage_ptr msg = getOutputBuffer();
  1703.     if(msg)
  1704.     {
  1705.         TRACK_MESSAGE(msg);
  1706.         AddPlayerStats(msg);
  1707.     }
  1708. }
  1709.  
  1710. void ProtocolGame::sendTextMessage(MessageClasses mClass, const std::string& message)
  1711. {
  1712.     NetworkMessage_ptr msg = getOutputBuffer();
  1713.     if(msg)
  1714.     {
  1715.         TRACK_MESSAGE(msg);
  1716.         AddTextMessage(msg, mClass, message);
  1717.     }
  1718. }
  1719.  
  1720. void ProtocolGame::sendClosePrivate(uint16_t channelId)
  1721. {
  1722.     NetworkMessage_ptr msg = getOutputBuffer();
  1723.     if(msg)
  1724.     {
  1725.         TRACK_MESSAGE(msg);
  1726.         if(channelId == CHANNEL_GUILD || channelId == CHANNEL_PARTY)
  1727.             g_chat.removeUserFromChannel(player, channelId);
  1728.  
  1729.         msg->AddByte(0xB3);
  1730.         msg->AddU16(channelId);
  1731.     }
  1732. }
  1733.  
  1734. void ProtocolGame::sendCreatePrivateChannel(uint16_t channelId, const std::string& channelName)
  1735. {
  1736.     NetworkMessage_ptr msg = getOutputBuffer();
  1737.     if(msg)
  1738.     {
  1739.         TRACK_MESSAGE(msg);
  1740.         msg->AddByte(0xB2);
  1741.         msg->AddU16(channelId);
  1742.         msg->AddString(channelName);
  1743.     }
  1744. }
  1745.  
  1746. void ProtocolGame::sendChannelsDialog()
  1747. {
  1748.     NetworkMessage_ptr msg = getOutputBuffer();
  1749.     if(msg)
  1750.     {
  1751.         TRACK_MESSAGE(msg);
  1752.         msg->AddByte(0xAB);
  1753.         ChannelList list = g_chat.getChannelList(player);
  1754.         msg->AddByte(list.size());
  1755.         for(ChannelList::iterator it = list.begin(); it != list.end(); ++it)
  1756.         {
  1757.             if(ChatChannel* channel = (*it))
  1758.             {
  1759.                 msg->AddU16(channel->getId());
  1760.                 msg->AddString(channel->getName());
  1761.             }
  1762.         }
  1763.     }
  1764. }
  1765.  
  1766. void ProtocolGame::protocolSendDuelChannels(int channels)
  1767. {
  1768.     NetworkMessage_ptr msg = getOutputBuffer();
  1769.     if(msg)
  1770.     {
  1771.         TRACK_MESSAGE(msg);
  1772.         msg->AddByte(0xAB);
  1773.         ChannelList list = g_chat.getChannelList(player);
  1774.         if(channels == 0) // janelas de escolha de quantidade de players a duelar
  1775.            msg->AddByte((list.size() - (list.size() -3)));
  1776.         else if (channels == 1) // janelas de escolha de quantidade de pokemons para duelar
  1777.            msg->AddByte((list.size() - (list.size() -6)));
  1778.                      
  1779.                        
  1780.         for(ChannelList::iterator it = list.begin(); it != list.end(); ++it)
  1781.         {
  1782.             if(ChatChannel* channel = (*it))
  1783.             {
  1784.                 if(channels == 0){
  1785.                   if((channel->getId() >= 8 && channel->getId() <= 10)){
  1786.                      msg->AddU16(channel->getId());
  1787.                      msg->AddString(channel->getName());
  1788.                   }
  1789.                 }else if(channels == 1){
  1790.                   if((channel->getId() >= 11 && channel->getId() <= 16)){
  1791.                      msg->AddU16(channel->getId());
  1792.                      msg->AddString(channel->getName());
  1793.                   }
  1794.                 }
  1795.             }
  1796.         }
  1797.     }
  1798. }
  1799.  
  1800. void ProtocolGame::sendChannel(uint16_t channelId, const std::string& channelName)
  1801. {
  1802.     NetworkMessage_ptr msg = getOutputBuffer();
  1803.     if(msg)
  1804.     {
  1805.         TRACK_MESSAGE(msg);
  1806.         msg->AddByte(0xAC);
  1807.         msg->AddU16(channelId);
  1808.         msg->AddString(channelName);
  1809.     }
  1810. }
  1811.  
  1812. void ProtocolGame::sendCustomChannelsDialog(std::vector<std::string>& newList, std::vector<int>& newId)
  1813. {
  1814.     NetworkMessage_ptr msg = getOutputBuffer();
  1815.        
  1816.     int c = 0;
  1817.        
  1818.     if(msg)
  1819.     {
  1820.         ChannelList list;
  1821.         for(std::vector<std::string>::const_iterator it = newList.begin(); it != newList.end(); ++it)
  1822.         {
  1823.             if(ChatChannel* newChannel = new ChatChannel((newId[c]), (*it), CHANNELFLAG_ENABLED))
  1824.             {
  1825.                 list.push_back(newChannel);
  1826.             }
  1827.             c++;
  1828.         }
  1829.        
  1830.            
  1831.         TRACK_MESSAGE(msg);
  1832.         msg->AddByte(0xAB);
  1833.         msg->AddByte(list.size());
  1834.         for(ChannelList::iterator it = list.begin(); it != list.end(); ++it)
  1835.         {
  1836.             if(ChatChannel* channel = (*it))
  1837.             {
  1838.                 msg->AddU16(channel->getId());
  1839.                 msg->AddString(channel->getName());
  1840.             }
  1841.         }
  1842.     }
  1843. }
  1844.  
  1845. void ProtocolGame::sendRuleViolationsChannel(uint16_t channelId)
  1846. {
  1847.     NetworkMessage_ptr msg = getOutputBuffer();
  1848.     if(msg)
  1849.     {
  1850.         TRACK_MESSAGE(msg);
  1851.         msg->AddByte(0xAE);
  1852.         msg->AddU16(channelId);
  1853.         for(RuleViolationsMap::const_iterator it = g_game.getRuleViolations().begin(); it != g_game.getRuleViolations().end(); ++it)
  1854.         {
  1855.             RuleViolation& rvr = *it->second;
  1856.             if(rvr.isOpen && rvr.reporter)
  1857.                 AddCreatureSpeak(msg, rvr.reporter, SPEAK_RVR_CHANNEL, rvr.text, channelId, rvr.time);
  1858.         }
  1859.     }
  1860. }
  1861.  
  1862. void ProtocolGame::sendRemoveReport(const std::string& name)
  1863. {
  1864.     NetworkMessage_ptr msg = getOutputBuffer();
  1865.     if(msg)
  1866.     {
  1867.         TRACK_MESSAGE(msg);
  1868.         msg->AddByte(0xAF);
  1869.         msg->AddString(name);
  1870.     }
  1871. }
  1872.  
  1873. void ProtocolGame::sendRuleViolationCancel(const std::string& name)
  1874. {
  1875.     NetworkMessage_ptr msg = getOutputBuffer();
  1876.     if(msg)
  1877.     {
  1878.         TRACK_MESSAGE(msg);
  1879.         msg->AddByte(0xB0);
  1880.         msg->AddString(name);
  1881.     }
  1882. }
  1883.  
  1884. void ProtocolGame::sendLockRuleViolation()
  1885. {
  1886.     NetworkMessage_ptr msg = getOutputBuffer();
  1887.     if(msg)
  1888.     {
  1889.         TRACK_MESSAGE(msg);
  1890.         msg->AddByte(0xB1);
  1891.     }
  1892. }
  1893.  
  1894. void ProtocolGame::sendIcons(int32_t icons)
  1895. {
  1896.     NetworkMessage_ptr msg = getOutputBuffer();
  1897.     if(msg)
  1898.     {
  1899.         TRACK_MESSAGE(msg);
  1900.         msg->AddByte(0xA2);
  1901.         msg->AddU16(icons);
  1902.     }
  1903. }
  1904.  
  1905. void ProtocolGame::sendContainer(uint32_t cid, const Container* container, bool hasParent)
  1906. {
  1907.     NetworkMessage_ptr msg = getOutputBuffer();
  1908.     if(msg)
  1909.     {
  1910.         TRACK_MESSAGE(msg);
  1911.         msg->AddByte(0x6E);
  1912.         msg->AddByte(cid);
  1913.  
  1914.         msg->AddItemId(container);
  1915.         msg->AddString(container->getName());
  1916.         msg->AddByte(container->capacity());
  1917.  
  1918.         msg->AddByte(hasParent ? 0x01 : 0x00);
  1919.         msg->AddByte(std::min(container->size(), (uint32_t)255));
  1920.  
  1921.         ItemList::const_iterator cit = container->getItems();
  1922.         for(uint32_t i = 0; cit != container->getEnd() && i < 255; ++cit, ++i)
  1923.             msg->AddItem(*cit);
  1924.     }
  1925. }
  1926.  
  1927. void ProtocolGame::sendShop(const ShopInfoList& shop)
  1928. {
  1929.     NetworkMessage_ptr msg = getOutputBuffer();
  1930.     if(msg)
  1931.     {
  1932.         TRACK_MESSAGE(msg);
  1933.         msg->AddByte(0x7A);
  1934.         msg->AddByte(std::min(shop.size(), (size_t)255));
  1935.  
  1936.         ShopInfoList::const_iterator it = shop.begin();
  1937.         for(uint32_t i = 0; it != shop.end() && i < 255; ++it, ++i)
  1938.             AddShopItem(msg, (*it));
  1939.     }
  1940. }
  1941.  
  1942. void ProtocolGame::sendCloseShop()
  1943. {
  1944.     NetworkMessage_ptr msg = getOutputBuffer();
  1945.     if(msg)
  1946.     {
  1947.         TRACK_MESSAGE(msg);
  1948.         msg->AddByte(0x7C);
  1949.     }
  1950. }
  1951.  
  1952. void ProtocolGame::sendGoods(const ShopInfoList& shop)
  1953. {
  1954.     NetworkMessage_ptr msg = getOutputBuffer();
  1955.     if(msg)
  1956.     {
  1957.         TRACK_MESSAGE(msg);
  1958.         msg->AddByte(0x7B);
  1959.         msg->AddU32(g_game.getMoney(player));
  1960.  
  1961.         std::map<uint32_t, uint32_t> goodsMap;
  1962.         if(shop.size() >= 5)
  1963.         {
  1964.             for(ShopInfoList::const_iterator sit = shop.begin(); sit != shop.end(); ++sit)
  1965.             {
  1966.                 if(sit->sellPrice < 0)
  1967.                     continue;
  1968.  
  1969.                 int8_t subType = -1;
  1970.                 if(sit->subType)
  1971.                 {
  1972.                     const ItemType& it = Item::items[sit->itemId];
  1973.                     if(it.hasSubType() && !it.stackable)
  1974.                         subType = sit->subType;
  1975.                 }
  1976.  
  1977.                 uint32_t count = player->__getItemTypeCount(sit->itemId, subType);
  1978.                 if(count > 0)
  1979.                     goodsMap[sit->itemId] = count;
  1980.             }
  1981.         }
  1982.         else
  1983.         {
  1984.             std::map<uint32_t, uint32_t> tmpMap;
  1985.             player->__getAllItemTypeCount(tmpMap);
  1986.             for(ShopInfoList::const_iterator sit = shop.begin(); sit != shop.end(); ++sit)
  1987.             {
  1988.                 if(sit->sellPrice < 0)
  1989.                     continue;
  1990.  
  1991.                 int8_t subType = -1;
  1992.                 if(sit->subType)
  1993.                 {
  1994.                     const ItemType& it = Item::items[sit->itemId];
  1995.                     if(it.hasSubType() && !it.stackable)
  1996.                         subType = sit->subType;
  1997.                 }
  1998.  
  1999.                 if(subType != -1)
  2000.                 {
  2001.                     uint32_t count = player->__getItemTypeCount(sit->itemId, subType);
  2002.                     if(count > 0)
  2003.                         goodsMap[sit->itemId] = count;
  2004.                 }
  2005.                 else
  2006.                     goodsMap[sit->itemId] = tmpMap[sit->itemId];
  2007.             }
  2008.         }
  2009.  
  2010.         msg->AddByte(std::min(goodsMap.size(), (size_t)255));
  2011.         std::map<uint32_t, uint32_t>::const_iterator it = goodsMap.begin();
  2012.         for(uint32_t i = 0; it != goodsMap.end() && i < 255; ++it, ++i)
  2013.         {
  2014.             msg->AddItemId(it->first);
  2015.             msg->AddByte(std::min(it->second, (uint32_t)255));
  2016.         }
  2017.     }
  2018. }
  2019.  
  2020. void ProtocolGame::sendTradeItemRequest(const Player* player, const Item* item, bool ack)
  2021. {
  2022.     NetworkMessage_ptr msg = getOutputBuffer();
  2023.     if(msg)
  2024.     {
  2025.         TRACK_MESSAGE(msg);
  2026.         if(ack)
  2027.             msg->AddByte(0x7D);
  2028.         else
  2029.             msg->AddByte(0x7E);
  2030.  
  2031.         msg->AddString(player->getName());
  2032.         if(const Container* container = item->getContainer())
  2033.         {
  2034.             msg->AddByte(container->getItemHoldingCount() + 1);
  2035.             msg->AddItem(item);
  2036.             for(ContainerIterator it = container->begin(); it != container->end(); ++it)
  2037.                 msg->AddItem(*it);
  2038.         }
  2039.         else
  2040.         {
  2041.             msg->AddByte(1);
  2042.             msg->AddItem(item);
  2043.         }
  2044.     }
  2045. }
  2046.  
  2047. void ProtocolGame::sendCloseTrade()
  2048. {
  2049.     NetworkMessage_ptr msg = getOutputBuffer();
  2050.     if(msg)
  2051.     {
  2052.         TRACK_MESSAGE(msg);
  2053.         msg->AddByte(0x7F);
  2054.     }
  2055. }
  2056.  
  2057. void ProtocolGame::sendCloseContainer(uint32_t cid)
  2058. {
  2059.     NetworkMessage_ptr msg = getOutputBuffer();
  2060.     if(msg)
  2061.     {
  2062.         TRACK_MESSAGE(msg);
  2063.         msg->AddByte(0x6F);
  2064.         msg->AddByte(cid);
  2065.     }
  2066. }
  2067.  
  2068. void ProtocolGame::sendCreatureTurn(const Creature* creature, int16_t stackpos)
  2069. {
  2070.     if(stackpos >= 10 || !canSee(creature))
  2071.         return;
  2072.  
  2073.     NetworkMessage_ptr msg = getOutputBuffer();
  2074.     if(msg)
  2075.     {
  2076.         TRACK_MESSAGE(msg);
  2077.         msg->AddByte(0x6B);
  2078.         msg->AddPosition(creature->getPosition());
  2079.         msg->AddByte(stackpos);
  2080.         msg->AddU16(0x63); /*99*/
  2081.         msg->AddU32(creature->getID());
  2082.         msg->AddByte(creature->getDirection());
  2083.     }
  2084. }
  2085.  
  2086. void ProtocolGame::sendCreatureSay(const Creature* creature, SpeakClasses type, const std::string& text, Position* pos/* = NULL*/)
  2087. {
  2088.     NetworkMessage_ptr msg = getOutputBuffer();
  2089.     if(msg)
  2090.     {
  2091.         TRACK_MESSAGE(msg);
  2092.         AddCreatureSpeak(msg, creature, type, text, 0, 0, pos);
  2093.     }
  2094. }
  2095.  
  2096. void ProtocolGame::sendToChannel(const Creature* creature, SpeakClasses type, const std::string& text, uint16_t channelId, uint32_t time /*= 0*/)
  2097. {
  2098.     NetworkMessage_ptr msg = getOutputBuffer();
  2099.     if(msg)
  2100.     {
  2101.         TRACK_MESSAGE(msg);
  2102.         AddCreatureSpeak(msg, creature, type, text, channelId, time);
  2103.     }
  2104. }
  2105.  
  2106. void ProtocolGame::sendCancel(const std::string& message)
  2107. {
  2108.     NetworkMessage_ptr msg = getOutputBuffer();
  2109.     if(msg)
  2110.     {
  2111.         TRACK_MESSAGE(msg);
  2112.         AddTextMessage(msg, MSG_STATUS_SMALL, message);
  2113.     }
  2114. }
  2115.  
  2116. void ProtocolGame::sendCancelTarget()
  2117. {
  2118.     NetworkMessage_ptr msg = getOutputBuffer();
  2119.     if(msg)
  2120.     {
  2121.         TRACK_MESSAGE(msg);
  2122.         msg->AddByte(0xA3);
  2123.     }
  2124. }
  2125.  
  2126. void ProtocolGame::sendChangeSpeed(const Creature* creature, uint32_t speed)
  2127. {
  2128.     if(!canSee(creature))
  2129.         return;
  2130.  
  2131.     NetworkMessage_ptr msg = getOutputBuffer();
  2132.     if(msg)
  2133.     {
  2134.         TRACK_MESSAGE(msg);
  2135.         msg->AddByte(0x8F);
  2136.         msg->AddU32(creature->getID());
  2137.         msg->AddU16(speed);
  2138.     }
  2139. }
  2140.  
  2141. void ProtocolGame::sendCancelWalk()
  2142. {
  2143.     NetworkMessage_ptr msg = getOutputBuffer();
  2144.     if(msg)
  2145.     {
  2146.         TRACK_MESSAGE(msg);
  2147.         msg->AddByte(0xB5);
  2148.         msg->AddByte(player->getDirection());
  2149.     }
  2150. }
  2151.  
  2152. void ProtocolGame::sendSkills()
  2153. {
  2154.     NetworkMessage_ptr msg = getOutputBuffer();
  2155.     if(msg)
  2156.     {
  2157.         TRACK_MESSAGE(msg);
  2158.         AddPlayerSkills(msg);
  2159.     }
  2160. }
  2161.  
  2162. void ProtocolGame::sendPing()
  2163. {
  2164.     NetworkMessage_ptr msg = getOutputBuffer();
  2165.     if(msg)
  2166.     {
  2167.         TRACK_MESSAGE(msg);
  2168.         msg->AddByte(0x1E);
  2169.     }
  2170. }
  2171.  
  2172. void ProtocolGame::sendDistanceShoot(const Position& from, const Position& to, uint8_t type)
  2173. {
  2174.     if(type > SHOOT_EFFECT_LAST || (!canSee(from) && !canSee(to)))
  2175.         return;
  2176.  
  2177.     NetworkMessage_ptr msg = getOutputBuffer();
  2178.     if(msg)
  2179.     {
  2180.         TRACK_MESSAGE(msg);
  2181.         AddDistanceShoot(msg, from, to, type);
  2182.     }
  2183. }
  2184.  
  2185. void ProtocolGame::sendMagicEffect(const Position& pos, uint16_t type)
  2186. {
  2187.     if(type > MAGIC_EFFECT_LAST || !canSee(pos))
  2188.         return;
  2189.  
  2190.     NetworkMessage_ptr msg = getOutputBuffer();
  2191.     if(msg)
  2192.     {
  2193.         TRACK_MESSAGE(msg);
  2194.         AddMagicEffect(msg, pos, type);
  2195.     }
  2196. }
  2197.  
  2198. void ProtocolGame::sendAnimatedText(const Position& pos, uint8_t color, std::string text)
  2199. {
  2200.     if(!canSee(pos))
  2201.         return;
  2202.  
  2203.     NetworkMessage_ptr msg = getOutputBuffer();
  2204.     if(msg)
  2205.     {
  2206.         TRACK_MESSAGE(msg);
  2207.         AddAnimatedText(msg, pos, color, text);
  2208.     }
  2209. }
  2210.  
  2211. void ProtocolGame::sendCreatureHealth(const Creature* creature)
  2212. {
  2213.     if(!canSee(creature))
  2214.         return;
  2215.  
  2216.     NetworkMessage_ptr msg = getOutputBuffer();
  2217.     if(msg)
  2218.     {
  2219.         TRACK_MESSAGE(msg);
  2220.         AddCreatureHealth(msg, creature);
  2221.     }
  2222. }
  2223.  
  2224. void ProtocolGame::sendFYIBox(const std::string& message)
  2225. {
  2226.     if(message.empty() || message.length() > 1018) //Prevent client debug when message is empty or length is > 1018 (not confirmed)
  2227.     {
  2228.         std::cout << "[Warning - ProtocolGame::sendFYIBox] Trying to send an empty or too huge message." << std::endl;
  2229.         return;
  2230.     }
  2231.  
  2232.     NetworkMessage_ptr msg = getOutputBuffer();
  2233.     if(msg)
  2234.     {
  2235.         TRACK_MESSAGE(msg);
  2236.         msg->AddByte(0x15);
  2237.         msg->AddString(message);
  2238.     }
  2239. }
  2240.  
  2241. //tile
  2242. void ProtocolGame::sendAddTileItem(const Tile* tile, const Position& pos, uint32_t stackpos, const Item* item)
  2243. {
  2244.     if(!canSee(pos))
  2245.         return;
  2246.  
  2247.     NetworkMessage_ptr msg = getOutputBuffer();
  2248.     if(msg)
  2249.     {
  2250.         TRACK_MESSAGE(msg);
  2251.         AddTileItem(msg, pos, stackpos, item);
  2252.     }
  2253. }
  2254.  
  2255. void ProtocolGame::sendUpdateTileItem(const Tile* tile, const Position& pos, uint32_t stackpos, const Item* item)
  2256. {
  2257.     if(!canSee(pos))
  2258.         return;
  2259.  
  2260.     NetworkMessage_ptr msg = getOutputBuffer();
  2261.     if(msg)
  2262.     {
  2263.         TRACK_MESSAGE(msg);
  2264.         UpdateTileItem(msg, pos, stackpos, item);
  2265.     }
  2266. }
  2267.  
  2268. void ProtocolGame::sendRemoveTileItem(const Tile* tile, const Position& pos, uint32_t stackpos)
  2269. {
  2270.     if(!canSee(pos))
  2271.         return;
  2272.  
  2273.     NetworkMessage_ptr msg = getOutputBuffer();
  2274.     if(msg)
  2275.     {
  2276.         TRACK_MESSAGE(msg);
  2277.         RemoveTileItem(msg, pos, stackpos);
  2278.     }
  2279. }
  2280.  
  2281. void ProtocolGame::sendUpdateTile(const Tile* tile, const Position& pos)
  2282. {
  2283.     if(!canSee(pos))
  2284.         return;
  2285.  
  2286.     NetworkMessage_ptr msg = getOutputBuffer();
  2287.     if(msg)
  2288.     {
  2289.         TRACK_MESSAGE(msg);
  2290.         msg->AddByte(0x69);
  2291.         msg->AddPosition(pos);
  2292.         if(tile)
  2293.         {
  2294.             GetTileDescription(tile, msg);
  2295.             msg->AddByte(0x00);
  2296.             msg->AddByte(0xFF);
  2297.         }
  2298.         else
  2299.         {
  2300.             msg->AddByte(0x01);
  2301.             msg->AddByte(0xFF);
  2302.         }
  2303.     }
  2304. }
  2305.  
  2306. void ProtocolGame::sendAddCreature(const Creature* creature, const Position& pos, uint32_t stackpos)
  2307. {
  2308.     if(!canSee(creature))
  2309.         return;
  2310.  
  2311.     NetworkMessage_ptr msg = getOutputBuffer();
  2312.     if(!msg)
  2313.         return;
  2314.  
  2315.     TRACK_MESSAGE(msg);
  2316.     if(creature != player)
  2317.     {
  2318.         AddTileCreature(msg, pos, stackpos, creature);
  2319.         return;
  2320.     }
  2321.  
  2322.     msg->AddByte(0x0A);
  2323.     msg->AddU32(player->getID());
  2324.     msg->AddU16(0x32);
  2325.  
  2326.     msg->AddByte(player->hasFlag(PlayerFlag_CanReportBugs));
  2327.     if(Group* group = player->getGroup())
  2328.     {
  2329.         int32_t reasons = group->getViolationReasons();
  2330.         if(reasons > 1)
  2331.         {
  2332.             msg->AddByte(0x0B);
  2333.             for(int32_t i = 0; i < 20; ++i)
  2334.             {
  2335.                 if(i < 4)
  2336.                     msg->AddByte(group->getNameViolationFlags());
  2337.                 else if(i < reasons)
  2338.                     msg->AddByte(group->getStatementViolationFlags());
  2339.                 else
  2340.                     msg->AddByte(0x00);
  2341.             }
  2342.         }
  2343.     }
  2344.  
  2345.     AddMapDescription(msg, pos);
  2346.     for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i)
  2347.         AddInventoryItem(msg, (slots_t)i, player->getInventoryItem((slots_t)i));
  2348.  
  2349.     AddPlayerStats(msg);
  2350.     AddPlayerSkills(msg);
  2351.  
  2352.     //gameworld light-settings
  2353.     LightInfo lightInfo;
  2354.     g_game.getWorldLightInfo(lightInfo);
  2355.     AddWorldLight(msg, lightInfo);
  2356.  
  2357.     //player light level
  2358.     AddCreatureLight(msg, creature);
  2359.     player->sendIcons();
  2360.     for(VIPListSet::iterator it = player->VIPList.begin(); it != player->VIPList.end(); it++)
  2361.     {
  2362.         std::string vipName;
  2363.         if(IOLoginData::getInstance()->getNameByGuid((*it), vipName))
  2364.         {
  2365.             Player* tmpPlayer = g_game.getPlayerByName(vipName);
  2366.             sendVIP((*it), vipName, (tmpPlayer && player->canSeeCreature(tmpPlayer)));
  2367.         }
  2368.     }
  2369. }
  2370.  
  2371. void ProtocolGame::sendRemoveCreature(const Creature* creature, const Position& pos, uint32_t stackpos)
  2372. {
  2373.     if(!canSee(pos))
  2374.         return;
  2375.  
  2376.     NetworkMessage_ptr msg = getOutputBuffer();
  2377.     if(msg)
  2378.     {
  2379.         TRACK_MESSAGE(msg);
  2380.         RemoveTileItem(msg, pos, stackpos);
  2381.     }
  2382. }
  2383.  
  2384. void ProtocolGame::sendMoveCreature(const Creature* creature, const Tile* newTile, const Position& newPos,
  2385.     uint32_t newStackpos, const Tile* oldTile, const Position& oldPos, uint32_t oldStackpos, bool teleport)
  2386. {
  2387.     if(creature == player)
  2388.     {
  2389.         NetworkMessage_ptr msg = getOutputBuffer();
  2390.         if(msg)
  2391.         {
  2392.             TRACK_MESSAGE(msg);
  2393.             if(teleport || oldStackpos >= 10)
  2394.             {
  2395.                 RemoveTileItem(msg, oldPos, oldStackpos);
  2396.                 AddMapDescription(msg, newPos);
  2397.             }
  2398.             else
  2399.             {
  2400.                 if(oldPos.z != 7 || newPos.z < 8)
  2401.                 {
  2402.                     msg->AddByte(0x6D);
  2403.                     msg->AddPosition(oldPos);
  2404.                     msg->AddByte(oldStackpos);
  2405.                     msg->AddPosition(newPos);
  2406.                 }
  2407.                 else
  2408.                     RemoveTileItem(msg, oldPos, oldStackpos);
  2409.  
  2410.                 if(newPos.z > oldPos.z)
  2411.                     MoveDownCreature(msg, creature, newPos, oldPos, oldStackpos);
  2412.                 else if(newPos.z < oldPos.z)
  2413.                     MoveUpCreature(msg, creature, newPos, oldPos, oldStackpos);
  2414.  
  2415.                 if(oldPos.y > newPos.y) // north, for old x
  2416.                 {
  2417.                     msg->AddByte(0x65);
  2418.                     GetMapDescription(oldPos.x - Map::maxClientViewportX, newPos.y - Map::maxClientViewportY, newPos.z, (Map::maxClientViewportX+1)*2, 1, msg);
  2419.                 }
  2420.                 else if(oldPos.y < newPos.y) // south, for old x
  2421.                 {
  2422.                     msg->AddByte(0x67);
  2423.                     //MoveUpCreatureGetMapDescription(oldPos.x - Map::maxClientViewportX, newPos.y + (Map::maxClientViewportY+1), newPos.z, 18, 1, msg);
  2424.                     GetMapDescription(oldPos.x - Map::maxClientViewportX, newPos.y + (Map::maxClientViewportY+1), newPos.z, (Map::maxClientViewportX+1)*2, 1, msg);
  2425.                 }
  2426.  
  2427.                 if(oldPos.x < newPos.x) // east, [with new y]
  2428.                 {
  2429.                     msg->AddByte(0x66);
  2430.                     //GetMapDescription(newPos.x + (Map::maxClientViewportX+1), newPos.y - Map::maxClientViewportY, newPos.z, 1, 14, msg);
  2431.                     GetMapDescription(newPos.x + (Map::maxClientViewportX+1), newPos.y - Map::maxClientViewportY, newPos.z, 1, (Map::maxClientViewportY+1)*2, msg);
  2432.                 }
  2433.                 else if(oldPos.x > newPos.x) // west, [with new y]
  2434.                 {
  2435.                     msg->AddByte(0x68);
  2436.                     GetMapDescription(newPos.x - Map::maxClientViewportX, newPos.y - Map::maxClientViewportY, newPos.z, 1, (Map::maxClientViewportY+1)*2, msg);
  2437.                 }
  2438.             }
  2439.         }
  2440.     }
  2441.     else if(canSee(oldPos) && canSee(newPos))
  2442.     {
  2443.         if(!player->canSeeCreature(creature))
  2444.             return;
  2445.  
  2446.         NetworkMessage_ptr msg = getOutputBuffer();
  2447.         if(msg)
  2448.         {
  2449.             TRACK_MESSAGE(msg);
  2450.             if(!teleport && (oldPos.z != 7 || newPos.z < 8) && oldStackpos < 10)
  2451.             {
  2452.                 msg->AddByte(0x6D);
  2453.                 msg->AddPosition(oldPos);
  2454.                 msg->AddByte(oldStackpos);
  2455.                 msg->AddPosition(newPos);
  2456.             }
  2457.             else
  2458.             {
  2459.                 RemoveTileItem(msg, oldPos, oldStackpos);
  2460.                 AddTileCreature(msg, newPos, newStackpos, creature);
  2461.             }
  2462.         }
  2463.     }
  2464.     else if(canSee(oldPos))
  2465.     {
  2466.         if(!player->canSeeCreature(creature))
  2467.             return;
  2468.  
  2469.         NetworkMessage_ptr msg = getOutputBuffer();
  2470.         if(msg)
  2471.         {
  2472.             TRACK_MESSAGE(msg);
  2473.             RemoveTileItem(msg, oldPos, oldStackpos);
  2474.         }
  2475.     }
  2476.     else if(canSee(newPos) && player->canSeeCreature(creature))
  2477.     {
  2478.         NetworkMessage_ptr msg = getOutputBuffer();
  2479.         if(msg)
  2480.         {
  2481.             TRACK_MESSAGE(msg);
  2482.             AddTileCreature(msg, newPos, newStackpos, creature);
  2483.         }
  2484.     }
  2485. }
  2486.  
  2487. //inventory
  2488. void ProtocolGame::sendAddInventoryItem(slots_t slot, const Item* item)
  2489. {
  2490.     NetworkMessage_ptr msg = getOutputBuffer();
  2491.     if(msg)
  2492.     {
  2493.         TRACK_MESSAGE(msg);
  2494.         AddInventoryItem(msg, slot, item);
  2495.     }
  2496. }
  2497.  
  2498. void ProtocolGame::sendUpdateInventoryItem(slots_t slot, const Item* item)
  2499. {
  2500.     NetworkMessage_ptr msg = getOutputBuffer();
  2501.     if(msg)
  2502.     {
  2503.         TRACK_MESSAGE(msg);
  2504.         UpdateInventoryItem(msg, slot, item);
  2505.     }
  2506. }
  2507.  
  2508. void ProtocolGame::sendRemoveInventoryItem(slots_t slot)
  2509. {
  2510.     NetworkMessage_ptr msg = getOutputBuffer();
  2511.     if(msg)
  2512.     {
  2513.         TRACK_MESSAGE(msg);
  2514.         RemoveInventoryItem(msg, slot);
  2515.     }
  2516. }
  2517.  
  2518. //containers
  2519. void ProtocolGame::sendAddContainerItem(uint8_t cid, const Item* item)
  2520. {
  2521.     NetworkMessage_ptr msg = getOutputBuffer();
  2522.     if(msg)
  2523.     {
  2524.         TRACK_MESSAGE(msg);
  2525.         AddContainerItem(msg, cid, item);
  2526.     }
  2527. }
  2528.  
  2529. void ProtocolGame::sendUpdateContainerItem(uint8_t cid, uint8_t slot, const Item* item)
  2530. {
  2531.     NetworkMessage_ptr msg = getOutputBuffer();
  2532.     if(msg)
  2533.     {
  2534.         TRACK_MESSAGE(msg);
  2535.         UpdateContainerItem(msg, cid, slot, item);
  2536.     }
  2537. }
  2538.  
  2539. void ProtocolGame::sendRemoveContainerItem(uint8_t cid, uint8_t slot)
  2540. {
  2541.     NetworkMessage_ptr msg = getOutputBuffer();
  2542.     if(msg)
  2543.     {
  2544.         TRACK_MESSAGE(msg);
  2545.         RemoveContainerItem(msg, cid, slot);
  2546.     }
  2547. }
  2548.  
  2549. void ProtocolGame::sendTextWindow(uint32_t windowTextId, Item* item, uint16_t maxLen, bool canWrite)
  2550. {
  2551.     NetworkMessage_ptr msg = getOutputBuffer();
  2552.     if(msg)
  2553.     {
  2554.         TRACK_MESSAGE(msg);
  2555.         msg->AddByte(0x96);
  2556.         msg->AddU32(windowTextId);
  2557.         msg->AddItemId(item);
  2558.         if(canWrite)
  2559.         {
  2560.             msg->AddU16(maxLen);
  2561.             msg->AddString(item->getText());
  2562.         }
  2563.         else
  2564.         {
  2565.             msg->AddU16(item->getText().size());
  2566.             msg->AddString(item->getText());
  2567.         }
  2568.  
  2569.         const std::string& writer = item->getWriter();
  2570.         if(writer.size())
  2571.             msg->AddString(writer);
  2572.         else
  2573.             msg->AddString("");
  2574.  
  2575.         time_t writtenDate = item->getDate();
  2576.         if(writtenDate > 0)
  2577.             msg->AddString(formatDate(writtenDate));
  2578.         else
  2579.             msg->AddString("");
  2580.     }
  2581. }
  2582.  
  2583. void ProtocolGame::sendTextWindow(uint32_t windowTextId, uint32_t itemId, const std::string& text)
  2584. {
  2585.     NetworkMessage_ptr msg = getOutputBuffer();
  2586.     if(msg)
  2587.     {
  2588.         TRACK_MESSAGE(msg);
  2589.         msg->AddByte(0x96);
  2590.         msg->AddU32(windowTextId);
  2591.         msg->AddItemId(itemId);
  2592.  
  2593.         msg->AddU16(text.size());
  2594.         msg->AddString(text);
  2595.  
  2596.         msg->AddString("");
  2597.         msg->AddString("");
  2598.     }
  2599. }
  2600.  
  2601. void ProtocolGame::sendHouseWindow(uint32_t windowTextId, House* _house,
  2602.     uint32_t listId, const std::string& text)
  2603. {
  2604.     NetworkMessage_ptr msg = getOutputBuffer();
  2605.     if(msg)
  2606.     {
  2607.         TRACK_MESSAGE(msg);
  2608.         msg->AddByte(0x97);
  2609.         msg->AddByte(0x00);
  2610.         msg->AddU32(windowTextId);
  2611.         msg->AddString(text);
  2612.     }
  2613. }
  2614.  
  2615. void ProtocolGame::sendOutfitWindow()
  2616. {
  2617.     NetworkMessage_ptr msg = getOutputBuffer();
  2618.     if(msg)
  2619.     {
  2620.         TRACK_MESSAGE(msg);
  2621.         msg->AddByte(0xC8);
  2622.         AddCreatureOutfit(msg, player, player->getDefaultOutfit(), true);
  2623.  
  2624.         std::list<Outfit> outfitList;
  2625.         for(OutfitMap::iterator it = player->outfits.begin(); it != player->outfits.end(); ++it)
  2626.         {
  2627.             if(player->canWearOutfit(it->first, it->second.addons))
  2628.                 outfitList.push_back(it->second);
  2629.         }
  2630.  
  2631.         if(outfitList.size())
  2632.         {
  2633.             msg->AddByte((size_t)std::min((size_t)OUTFITS_MAX_NUMBER, outfitList.size()));
  2634.             std::list<Outfit>::iterator it = outfitList.begin();
  2635.             for(int32_t i = 0; it != outfitList.end() && i < OUTFITS_MAX_NUMBER; ++it, ++i)
  2636.             {
  2637.                 msg->AddU16(it->lookType);
  2638.                 msg->AddString(it->name);
  2639.                 if(player->hasCustomFlag(PlayerCustomFlag_CanWearAllAddons))
  2640.                     msg->AddByte(0x03);
  2641.                 else if(!g_config.getBool(ConfigManager::ADDONS_PREMIUM) || player->isPremium())
  2642.                     msg->AddByte(it->addons);
  2643.                 else
  2644.                     msg->AddByte(0x00);
  2645.             }
  2646.         }
  2647.         else
  2648.         {
  2649.             msg->AddByte(1);
  2650.             msg->AddU16(player->getDefaultOutfit().lookType);
  2651.             msg->AddString("Outfit");
  2652.             msg->AddByte(player->getDefaultOutfit().lookAddons);
  2653.         }
  2654.  
  2655.         player->hasRequestedOutfit(true);
  2656.     }
  2657. }
  2658.  
  2659. void ProtocolGame::sendQuests()
  2660. {
  2661.     NetworkMessage_ptr msg = getOutputBuffer();
  2662.     if(msg)
  2663.     {
  2664.         TRACK_MESSAGE(msg);
  2665.         msg->AddByte(0xF0);
  2666.  
  2667.         msg->AddU16(Quests::getInstance()->getQuestCount(player));
  2668.         for(QuestList::const_iterator it = Quests::getInstance()->getFirstQuest(); it != Quests::getInstance()->getLastQuest(); ++it)
  2669.         {
  2670.             if(!(*it)->isStarted(player))
  2671.                 continue;
  2672.  
  2673.             msg->AddU16((*it)->getId());
  2674.             msg->AddString((*it)->getName());
  2675.             msg->AddByte((*it)->isCompleted(player));
  2676.         }
  2677.     }
  2678. }
  2679.  
  2680. void ProtocolGame::sendQuestInfo(Quest* quest)
  2681. {
  2682.     NetworkMessage_ptr msg = getOutputBuffer();
  2683.     if(msg)
  2684.     {
  2685.         TRACK_MESSAGE(msg);
  2686.         msg->AddByte(0xF1);
  2687.         msg->AddU16(quest->getId());
  2688.  
  2689.         msg->AddByte(quest->getMissionCount(player));
  2690.         for(MissionList::const_iterator it = quest->getFirstMission(); it != quest->getLastMission(); ++it)
  2691.         {
  2692.             if(!(*it)->isStarted(player))
  2693.                 continue;
  2694.  
  2695.             msg->AddString((*it)->getName(player));
  2696.             msg->AddString((*it)->getDescription(player));
  2697.         }
  2698.     }
  2699. }
  2700.  
  2701. void ProtocolGame::sendVIPLogIn(uint32_t guid)
  2702. {
  2703.     NetworkMessage_ptr msg = getOutputBuffer();
  2704.     if(msg)
  2705.     {
  2706.         TRACK_MESSAGE(msg);
  2707.         msg->AddByte(0xD3);
  2708.         msg->AddU32(guid);
  2709.     }
  2710. }
  2711.  
  2712. void ProtocolGame::sendVIPLogOut(uint32_t guid)
  2713. {
  2714.     NetworkMessage_ptr msg = getOutputBuffer();
  2715.     if(msg)
  2716.     {
  2717.         TRACK_MESSAGE(msg);
  2718.         msg->AddByte(0xD4);
  2719.         msg->AddU32(guid);
  2720.     }
  2721. }
  2722.  
  2723. void ProtocolGame::sendVIP(uint32_t guid, const std::string& name, bool isOnline)
  2724. {
  2725.     NetworkMessage_ptr msg = getOutputBuffer();
  2726.     if(msg)
  2727.     {
  2728.         TRACK_MESSAGE(msg);
  2729.         msg->AddByte(0xD2);
  2730.         msg->AddU32(guid);
  2731.         msg->AddString(name);
  2732.         msg->AddByte(isOnline ? 1 : 0);
  2733.     }
  2734. }
  2735.  
  2736. ////////////// Add common messages
  2737. void ProtocolGame::AddMapDescription(NetworkMessage_ptr msg, const Position& pos)
  2738. {
  2739.     msg->AddByte(0x64);
  2740.     msg->AddPosition(player->getPosition());
  2741.     GetMapDescription(pos.x - Map::maxClientViewportX, pos.y - Map::maxClientViewportY, pos.z, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, msg);
  2742. }
  2743.  
  2744. void ProtocolGame::AddTextMessage(NetworkMessage_ptr msg, MessageClasses mclass, const std::string& message)
  2745. {
  2746.     msg->AddByte(0xB4);
  2747.     msg->AddByte(mclass);
  2748.     msg->AddString(message);
  2749. }
  2750.  
  2751. void ProtocolGame::AddAnimatedText(NetworkMessage_ptr msg, const Position& pos,
  2752.     uint8_t color, const std::string& text)
  2753. {
  2754.     msg->AddByte(0x84);
  2755.     msg->AddPosition(pos);
  2756.     msg->AddByte(color);
  2757.     msg->AddString(text);
  2758. }
  2759.  
  2760. void ProtocolGame::AddMagicEffect(NetworkMessage_ptr msg,const Position& pos, uint16_t type)
  2761. {
  2762. msg->AddByte(0x83);
  2763. msg->AddPosition(pos);
  2764. msg->AddU16(type + 1);
  2765. }
  2766.  
  2767. void ProtocolGame::AddDistanceShoot(NetworkMessage_ptr msg, const Position& from, const Position& to,
  2768.     uint8_t type)
  2769. {
  2770.     msg->AddByte(0x85);
  2771.     msg->AddPosition(from);
  2772.     msg->AddPosition(to);
  2773.     msg->AddByte(type + 1);
  2774. }
  2775.  
  2776. void ProtocolGame::AddCreature(NetworkMessage_ptr msg, const Creature* creature, bool known, uint32_t remove)
  2777. {
  2778.     if(!known)
  2779.     {
  2780.         msg->AddU16(0x61);
  2781.         msg->AddU32(remove);
  2782.         msg->AddU32(creature->getID());
  2783.         msg->AddString(creature->getHideName() ? "" : creature->getName());
  2784.     }
  2785.     else
  2786.     {
  2787.         msg->AddU16(0x62);
  2788.         msg->AddU32(creature->getID());
  2789.     }
  2790.  
  2791.     if(!creature->getHideHealth())
  2792.         msg->AddByte((int32_t)std::ceil(((float)creature->getHealth()) * 100 / std::max(creature->getMaxHealth(), (int32_t)1)));
  2793.     else
  2794.         msg->AddByte(0x00);
  2795.  
  2796.     msg->AddByte((uint8_t)creature->getDirection());
  2797.     AddCreatureOutfit(msg, creature, creature->getCurrentOutfit());
  2798.  
  2799.     LightInfo lightInfo;
  2800.     creature->getCreatureLight(lightInfo);
  2801.     msg->AddByte(player->hasCustomFlag(PlayerCustomFlag_HasFullLight) ? 0xFF : lightInfo.level);
  2802.     msg->AddByte(lightInfo.color);
  2803.  
  2804.     msg->AddU16(creature->getStepSpeed());
  2805.     msg->AddByte(player->getSkullClient(creature));
  2806.     msg->AddByte(player->getPartyShield(creature));
  2807.     if(!known)
  2808.         msg->AddByte(0x00); // war emblem
  2809.  
  2810.     msg->AddByte(!player->canWalkthrough(creature));
  2811. }
  2812.  
  2813. void ProtocolGame::AddPlayerStats(NetworkMessage_ptr msg)
  2814. {
  2815.     msg->AddByte(0xA0);
  2816.     msg->AddU16(player->getHealth());
  2817.     msg->AddU16(player->getPlayerInfo(PLAYERINFO_MAXHEALTH));
  2818.     msg->AddU32(uint32_t(player->getFreeCapacity() * 100));
  2819.     uint64_t experience = player->getExperience();
  2820.     if(experience > 0x7FFFFFFF) // client debugs after 2,147,483,647 exp
  2821.         msg->AddU32(0x7FFFFFFF);
  2822.     else
  2823.         msg->AddU32(experience);
  2824.  
  2825.     msg->AddU16(player->getPlayerInfo(PLAYERINFO_LEVEL));
  2826.     msg->AddByte(player->getPlayerInfo(PLAYERINFO_LEVELPERCENT));
  2827.     msg->AddU16(player->getPlayerInfo(PLAYERINFO_MANA));
  2828.     msg->AddU16(player->getPlayerInfo(PLAYERINFO_MAXMANA));
  2829.     msg->AddByte(player->getPlayerInfo(PLAYERINFO_MAGICLEVEL));
  2830.     msg->AddByte(player->getPlayerInfo(PLAYERINFO_MAGICLEVELPERCENT));
  2831.     msg->AddByte(player->getPlayerInfo(PLAYERINFO_SOUL));
  2832.     msg->AddU16(player->getStaminaMinutes());
  2833. }
  2834.  
  2835. void ProtocolGame::AddPlayerSkills(NetworkMessage_ptr msg)
  2836. {
  2837.     msg->AddByte(0xA1);
  2838.     msg->AddByte(player->getSkill(SKILL_FIST, SKILL_LEVEL));
  2839.     msg->AddByte(player->getSkill(SKILL_FIST, SKILL_PERCENT));
  2840.     msg->AddByte(player->getSkill(SKILL_CLUB, SKILL_LEVEL));
  2841.     msg->AddByte(player->getSkill(SKILL_CLUB, SKILL_PERCENT));
  2842.     msg->AddByte(player->getSkill(SKILL_SWORD, SKILL_LEVEL));
  2843.     msg->AddByte(player->getSkill(SKILL_SWORD, SKILL_PERCENT));
  2844.     msg->AddByte(player->getSkill(SKILL_AXE, SKILL_LEVEL));
  2845.     msg->AddByte(player->getSkill(SKILL_AXE, SKILL_PERCENT));
  2846.     msg->AddByte(player->getSkill(SKILL_DIST, SKILL_LEVEL));
  2847.     msg->AddByte(player->getSkill(SKILL_DIST, SKILL_PERCENT));
  2848.     msg->AddByte(player->getSkill(SKILL_SHIELD, SKILL_LEVEL));
  2849.     msg->AddByte(player->getSkill(SKILL_SHIELD, SKILL_PERCENT));
  2850.     msg->AddByte(player->getSkill(SKILL_FISH, SKILL_LEVEL));
  2851.     msg->AddByte(player->getSkill(SKILL_FISH, SKILL_PERCENT));
  2852. }
  2853.  
  2854. void ProtocolGame::AddCreatureSpeak(NetworkMessage_ptr msg, const Creature* creature, SpeakClasses type,
  2855.     std::string text, uint16_t channelId, uint32_t time/*= 0*/, Position* pos/* = NULL*/)
  2856. {
  2857.     msg->AddByte(0xAA);
  2858.     if(creature)
  2859.     {
  2860.         const Player* speaker = creature->getPlayer();
  2861.         if(speaker)
  2862.         {
  2863.             msg->AddU32(++g_chat.statement);
  2864.             g_chat.statementMap[g_chat.statement] = text;
  2865.         }
  2866.         else
  2867.             msg->AddU32(0x00);
  2868.  
  2869.         if(creature->getSpeakType() != SPEAK_CLASS_NONE)
  2870.             type = creature->getSpeakType();
  2871.  
  2872.         switch(type)
  2873.         {
  2874.             case SPEAK_CHANNEL_RA:
  2875.                 msg->AddString("");
  2876.                 break;
  2877.             case SPEAK_RVR_ANSWER:
  2878.                 msg->AddString("Gamemaster");
  2879.                 break;
  2880.             default:
  2881.                 msg->AddString(!creature->getHideName() ? creature->getName() : "");
  2882.                 break;
  2883.         }
  2884.  
  2885.         if(speaker && type != SPEAK_RVR_ANSWER && !speaker->isAccountManager()
  2886.             && !speaker->hasCustomFlag(PlayerCustomFlag_HideLevel))
  2887.             msg->AddU16(speaker->getPlayerInfo(PLAYERINFO_LEVEL));
  2888.         else
  2889.             msg->AddU16(0x00);
  2890.  
  2891.     }
  2892.     else
  2893.     {
  2894.         msg->AddU32(0x00);
  2895.         msg->AddString("");
  2896.         msg->AddU16(0x00);
  2897.     }
  2898.  
  2899.     msg->AddByte(type);
  2900.     switch(type)
  2901.     {
  2902.         case SPEAK_SAY:
  2903.         case SPEAK_WHISPER:
  2904.         case SPEAK_YELL:
  2905.         case SPEAK_MONSTER_SAY:
  2906.         case SPEAK_MONSTER_YELL:
  2907.         case SPEAK_PRIVATE_NP:
  2908.         {
  2909.             if(pos)
  2910.                 msg->AddPosition(*pos);
  2911.             else if(creature)
  2912.                 msg->AddPosition(creature->getPosition());
  2913.             else
  2914.                 msg->AddPosition(Position(0,0,7));
  2915.  
  2916.             break;
  2917.         }
  2918.  
  2919.         case SPEAK_CHANNEL_Y:
  2920.         case SPEAK_CHANNEL_RN:
  2921.         case SPEAK_CHANNEL_RA:
  2922.         case SPEAK_CHANNEL_O:
  2923.         case SPEAK_CHANNEL_W:
  2924.             msg->AddU16(channelId);
  2925.             break;
  2926.  
  2927.         case SPEAK_RVR_CHANNEL:
  2928.         {
  2929.             msg->AddU32(uint32_t(OTSYS_TIME() / 1000 & 0xFFFFFFFF) - time);
  2930.             break;
  2931.         }
  2932.  
  2933.         default:
  2934.             break;
  2935.     }
  2936.  
  2937.     msg->AddString(text);
  2938. }
  2939.  
  2940. void ProtocolGame::AddCreatureHealth(NetworkMessage_ptr msg,const Creature* creature)
  2941. {
  2942.     msg->AddByte(0x8C);
  2943.     msg->AddU32(creature->getID());
  2944.     if(!creature->getHideHealth())
  2945.         msg->AddByte((int32_t)std::ceil(((float)creature->getHealth()) * 100 / std::max(creature->getMaxHealth(), (int32_t)1)));
  2946.     else
  2947.         msg->AddByte(0x00);
  2948. }
  2949.  
  2950. void ProtocolGame::AddCreatureOutfit(NetworkMessage_ptr msg, const Creature* creature, const Outfit_t& outfit, bool outfitWindow/* = false*/)
  2951. {
  2952.     if(outfitWindow || !creature->getPlayer() || (!creature->isInvisible() && (!creature->isGhost()
  2953.         || !g_config.getBool(ConfigManager::GHOST_INVISIBLE_EFFECT))))
  2954.     {
  2955.         msg->AddU16(outfit.lookType);
  2956.         if(outfit.lookType)
  2957.         {
  2958.             msg->AddByte(outfit.lookHead);
  2959.             msg->AddByte(outfit.lookBody);
  2960.             msg->AddByte(outfit.lookLegs);
  2961.             msg->AddByte(outfit.lookFeet);
  2962.             msg->AddByte(outfit.lookAddons);
  2963.         }
  2964.         else if(outfit.lookTypeEx)
  2965.             msg->AddItemId(outfit.lookTypeEx);
  2966.         else
  2967.             msg->AddU16(outfit.lookTypeEx);
  2968.     }
  2969.     else
  2970.         msg->AddU32(0x00);
  2971. }
  2972.  
  2973. void ProtocolGame::AddWorldLight(NetworkMessage_ptr msg, const LightInfo& lightInfo)
  2974. {
  2975.     msg->AddByte(0x82);
  2976.     msg->AddByte((player->hasCustomFlag(PlayerCustomFlag_HasFullLight) ? 0xFF : lightInfo.level));
  2977.     msg->AddByte(lightInfo.color);
  2978. }
  2979.  
  2980. void ProtocolGame::AddCreatureLight(NetworkMessage_ptr msg, const Creature* creature)
  2981. {
  2982.     LightInfo lightInfo;
  2983.     creature->getCreatureLight(lightInfo);
  2984.     msg->AddByte(0x8D);
  2985.     msg->AddU32(creature->getID());
  2986.     msg->AddByte((player->hasCustomFlag(PlayerCustomFlag_HasFullLight) ? 0xFF : lightInfo.level));
  2987.     msg->AddByte(lightInfo.color);
  2988. }
  2989.  
  2990. //tile
  2991. void ProtocolGame::AddTileItem(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos, const Item* item)
  2992. {
  2993.     if(stackpos >= 10)
  2994.         return;
  2995.  
  2996.     msg->AddByte(0x6A);
  2997.     msg->AddPosition(pos);
  2998.     msg->AddByte(stackpos);
  2999.     msg->AddItem(item);
  3000. }
  3001.  
  3002. void ProtocolGame::AddTileCreature(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos, const Creature* creature)
  3003. {
  3004.     if(stackpos >= 10)
  3005.         return;
  3006.  
  3007.     msg->AddByte(0x6A);
  3008.     msg->AddPosition(pos);
  3009.     msg->AddByte(stackpos);
  3010.  
  3011.     bool known;
  3012.     uint32_t removedKnown;
  3013.     checkCreatureAsKnown(creature->getID(), known, removedKnown);
  3014.     AddCreature(msg, creature, known, removedKnown);
  3015. }
  3016.  
  3017. void ProtocolGame::UpdateTileItem(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos, const Item* item)
  3018. {
  3019.     if(stackpos >= 10)
  3020.         return;
  3021.  
  3022.     msg->AddByte(0x6B);
  3023.     msg->AddPosition(pos);
  3024.     msg->AddByte(stackpos);
  3025.     msg->AddItem(item);
  3026. }
  3027.  
  3028. void ProtocolGame::RemoveTileItem(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos)
  3029. {
  3030.     if(stackpos >= 10)
  3031.         return;
  3032.  
  3033.     msg->AddByte(0x6C);
  3034.     msg->AddPosition(pos);
  3035.     msg->AddByte(stackpos);
  3036. }
  3037.  
  3038. void ProtocolGame::MoveUpCreature(NetworkMessage_ptr msg, const Creature* creature,
  3039.     const Position& newPos, const Position& oldPos, uint32_t oldStackpos)
  3040. {
  3041.     if(creature != player)
  3042.         return;
  3043.  
  3044.     msg->AddByte(0xBE); //floor change up
  3045.     if(newPos.z == 7) //going to surface
  3046.     {
  3047.         int32_t skip = -1;
  3048.         GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 5, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 3, skip); //(floor 7 and 6 already set)
  3049.         GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 4, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 4, skip);
  3050.         GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 3, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 5, skip);
  3051.         GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 2, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 6, skip);
  3052.         GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 1, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 7, skip);
  3053.         GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 0, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 8, skip);
  3054.  
  3055.         if(skip >= 0)
  3056.         {
  3057.             msg->AddByte(skip);
  3058.             msg->AddByte(0xFF);
  3059.         }
  3060.     }
  3061.     else if(newPos.z > 7) //underground, going one floor up (still underground)
  3062.     {
  3063.         int32_t skip = -1;
  3064.         GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, oldPos.z- 3, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 3, skip);
  3065.  
  3066.         if(skip >= 0)
  3067.         {
  3068.             msg->AddByte(skip);
  3069.             msg->AddByte(0xFF);
  3070.         }
  3071.     }
  3072.  
  3073.     //moving up a floor up makes us out of sync
  3074.     //west
  3075.     msg->AddByte(0x68);
  3076.     GetMapDescription(oldPos.x - Map::maxClientViewportX, oldPos.y - (Map::maxClientViewportY-1), newPos.z, 1, (Map::maxClientViewportY+1)*2, msg);
  3077.     //north
  3078.     msg->AddByte(0x65);
  3079.     GetMapDescription(oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, newPos.z, (Map::maxClientViewportX+1)*2, 1, msg);
  3080.  
  3081. }
  3082.  
  3083. void ProtocolGame::MoveDownCreature(NetworkMessage_ptr msg, const Creature* creature,
  3084.     const Position& newPos, const Position& oldPos, uint32_t oldStackpos)
  3085. {
  3086.     if(creature != player)
  3087.         return;
  3088.  
  3089.     msg->AddByte(0xBF); //floor change down
  3090.     if(newPos.z == 8) //going from surface to underground
  3091.     {
  3092.         int32_t skip = -1;
  3093.         GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, newPos.z, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, -1, skip);
  3094.         GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, newPos.z + 1, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, -2, skip);
  3095.         GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, newPos.z + 2, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, -3, skip);
  3096.  
  3097.         if(skip >= 0)
  3098.         {
  3099.             msg->AddByte(skip);
  3100.             msg->AddByte(0xFF);
  3101.         }
  3102.     }
  3103.     else if(newPos.z > oldPos.z && newPos.z > 8 && newPos.z < 14) //going further down
  3104.     {
  3105.         int32_t skip = -1;
  3106.         GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, newPos.z + 2, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, -3, skip);
  3107.         if(skip >= 0)
  3108.         {
  3109.             msg->AddByte(skip);
  3110.             msg->AddByte(0xFF);
  3111.         }
  3112.     }
  3113.  
  3114.     //moving down a floor makes us out of sync
  3115.     //east
  3116.     msg->AddByte(0x66);
  3117.     GetMapDescription(oldPos.x + 9, oldPos.y - 1 - 6, newPos.z, 1, 14, msg);
  3118.  
  3119.     //south
  3120.     msg->AddByte(0x67);
  3121.     GetMapDescription(oldPos.x - 8, oldPos.y + 7, newPos.z, 18, 1, msg);
  3122. }
  3123.  
  3124. //inventory
  3125. void ProtocolGame::AddInventoryItem(NetworkMessage_ptr msg, slots_t slot, const Item* item)
  3126. {
  3127.     if(item)
  3128.     {
  3129.         msg->AddByte(0x78);
  3130.         msg->AddByte(slot);
  3131.         msg->AddItem(item);
  3132.     }
  3133.     else
  3134.         RemoveInventoryItem(msg, slot);
  3135. }
  3136.  
  3137. void ProtocolGame::RemoveInventoryItem(NetworkMessage_ptr msg, slots_t slot)
  3138. {
  3139.     msg->AddByte(0x79);
  3140.     msg->AddByte(slot);
  3141. }
  3142.  
  3143. void ProtocolGame::UpdateInventoryItem(NetworkMessage_ptr msg, slots_t slot, const Item* item)
  3144. {
  3145.     AddInventoryItem(msg, slot, item);
  3146. }
  3147.  
  3148. //containers
  3149. void ProtocolGame::AddContainerItem(NetworkMessage_ptr msg, uint8_t cid, const Item* item)
  3150. {
  3151.     msg->AddByte(0x70);
  3152.     msg->AddByte(cid);
  3153.     msg->AddItem(item);
  3154. }
  3155.  
  3156. void ProtocolGame::UpdateContainerItem(NetworkMessage_ptr msg, uint8_t cid, uint8_t slot, const Item* item)
  3157. {
  3158.     msg->AddByte(0x71);
  3159.     msg->AddByte(cid);
  3160.     msg->AddByte(slot);
  3161.     msg->AddItem(item);
  3162. }
  3163.  
  3164. void ProtocolGame::RemoveContainerItem(NetworkMessage_ptr msg, uint8_t cid, uint8_t slot)
  3165. {
  3166.     msg->AddByte(0x72);
  3167.     msg->AddByte(cid);
  3168.     msg->AddByte(slot);
  3169. }
  3170.  
  3171. void ProtocolGame::sendChannelMessage(std::string author, std::string text, SpeakClasses type, uint8_t channel)
  3172. {
  3173.     NetworkMessage_ptr msg = getOutputBuffer();
  3174.     if(msg)
  3175.     {
  3176.         TRACK_MESSAGE(msg);
  3177.         msg->AddByte(0xAA);
  3178.         msg->AddU32(0x00);
  3179.         msg->AddString(author);
  3180.         msg->AddU16(0x00);
  3181.         msg->AddByte(type);
  3182.         msg->AddU16(channel);
  3183.         msg->AddString(text);
  3184.     }
  3185. }
  3186.  
  3187. void ProtocolGame::AddShopItem(NetworkMessage_ptr msg, const ShopInfo item)
  3188. {
  3189.     const ItemType& it = Item::items[item.itemId];
  3190.     msg->AddU16(it.clientId);
  3191.     if(it.isSplash() || it.isFluidContainer())
  3192.         msg->AddByte(fluidMap[item.subType % 8]);
  3193.     else if(it.stackable || it.charges)
  3194.         msg->AddByte(item.subType);
  3195.     else
  3196.         msg->AddByte(0x01);
  3197.  
  3198.     msg->AddString(item.itemName);
  3199.     msg->AddU32(uint32_t(it.weight * 100));
  3200.     msg->AddU32(item.buyPrice);
  3201.     msg->AddU32(item.sellPrice);
  3202. }
  3203.  
  3204. void ProtocolGame::parseExtendedOpcode(NetworkMessage& msg)
  3205. {
  3206. uint8_t opcode = msg.GetByte();
  3207. std::string buffer = msg.GetString();
  3208.  
  3209. // process additional opcodes via lua script event
  3210. addGameTask(&Game::parsePlayerExtendedOpcode, player->getID(), opcode, buffer);
  3211. }
  3212.  
  3213. void ProtocolGame::sendExtendedOpcode(uint8_t opcode, const std::string& buffer)
  3214. {
  3215. // extended opcodes can only be send to players using otclient, cipsoft's tibia can't understand them
  3216.  
  3217.     NetworkMessage_ptr msg = getOutputBuffer();
  3218.     if(msg)
  3219.     {
  3220.         TRACK_MESSAGE(msg);
  3221.         msg->AddByte(0x32);
  3222.         msg->AddByte(opcode);
  3223.         msg->AddString(buffer);
  3224.     }
  3225. }
  3226.  
  3227. void ProtocolGame::parseMarketLeave()
  3228. {
  3229.     addGameTask(&Game::playerLeaveMarket, player->getID());
  3230. }
  3231.  
  3232. void ProtocolGame::parseMarketBrowse(NetworkMessage& msg)
  3233. {
  3234.     uint16_t browseId = msg.GetU16();
  3235.     if(browseId == MARKETREQUEST_OWN_OFFERS)
  3236.         addGameTask(&Game::playerBrowseMarketOwnOffers, player->getID());
  3237.     else if(browseId == MARKETREQUEST_OWN_HISTORY)
  3238.         addGameTask(&Game::playerBrowseMarketOwnHistory, player->getID());
  3239.     else
  3240.         addGameTask(&Game::playerBrowseMarket, player->getID(), browseId);
  3241. }
  3242.  
  3243. void ProtocolGame::parseMarketItemDesc(NetworkMessage& msg)
  3244. {
  3245.     uint32_t timestamp = msg.GetU32();
  3246.     uint16_t counter = msg.GetU16();
  3247.     addGameTask(&Game::playerItemDescMarket, player->getID(), timestamp, counter);
  3248. }
  3249.  
  3250. void ProtocolGame::parseMarketCreateOffer(NetworkMessage& msg)
  3251. {
  3252.     uint8_t type = msg.GetByte();
  3253.     Position pos = msg.GetPosition();
  3254.     uint16_t spriteId = msg.GetSpriteId();
  3255.     int16_t stackpos = msg.GetByte();
  3256.     uint16_t amount = msg.GetU16();
  3257.     uint32_t price = msg.GetU32();
  3258.     bool anonymous = (msg.GetByte() != 0);
  3259.     addGameTask(&Game::playerCreateMarketOffer, player->getID(), type, pos, spriteId, stackpos, amount, price, anonymous);
  3260. }
  3261.  
  3262. void ProtocolGame::parseMarketCancelOffer(NetworkMessage& msg)
  3263. {
  3264.     uint32_t timestamp = msg.GetU32();
  3265.     uint16_t counter = msg.GetU16();
  3266.     addGameTask(&Game::playerCancelMarketOffer, player->getID(), timestamp, counter);
  3267. }
  3268.  
  3269. void ProtocolGame::parseMarketAcceptOffer(NetworkMessage& msg)
  3270. {
  3271.     uint32_t timestamp = msg.GetU32();
  3272.     uint16_t counter = msg.GetU16();
  3273.     uint16_t amount = msg.GetU16();
  3274.     addGameTask(&Game::playerAcceptMarketOffer, player->getID(), timestamp, counter, amount);
  3275. }
  3276.  
  3277. void ProtocolGame::sendMarketEnter(uint32_t depotId)
  3278. {
  3279.     NetworkMessage_ptr msg = getOutputBuffer();
  3280.     if(msg)
  3281.     {
  3282.         TRACK_MESSAGE(msg);
  3283.         msg->AddByte(0xF6);
  3284.  
  3285.         msg->AddU32(g_game.getMoney(player));
  3286.         msg->AddByte(player->getVocationId());
  3287.         msg->AddByte(std::min<uint32_t>(IOMarket::getInstance()->getPlayerOfferCount(player->getGUID()),std::numeric_limits<uint8_t>::max()));
  3288.         Depot* depotChest = player->getDepot(depotId, false);
  3289.        
  3290.         if(!depotChest){
  3291.             msg->AddU16(0x00);
  3292.             return;
  3293.         }
  3294.        
  3295.         player->setMarketDepotId(depotId);
  3296.         player->setInMarket(true);
  3297.         std::map<uint16_t, uint32_t> depotItems;
  3298.         std::list<Container*> containerList;
  3299.         containerList.push_back(depotChest);
  3300.         do
  3301.         {
  3302.             Container* container = containerList.front();
  3303.             containerList.pop_front();
  3304.            
  3305.             for(ItemList::const_iterator it = container->getItems(); it != container->getEnd(); ++it)
  3306.             {
  3307.                 Item* item = *it;
  3308.                 if(item){
  3309.                     Container* c = item->getContainer();
  3310.                     if(c && !c->empty())
  3311.                     {
  3312.                        containerList.push_back(c);
  3313.                        continue;
  3314.                     }
  3315.                     if(item->getID() != ITEM_MARKET && item->getID() != ITEM_DEPOT ){
  3316.                        depotItems[item->getClientID()] += Item::countByType(item, -1);
  3317.                     }
  3318.                 }
  3319.             }
  3320.         }
  3321.         while(!containerList.empty());
  3322.  
  3323.         msg->AddU16(std::min<size_t>(depotItems.size(), std::numeric_limits<uint16_t>::max()));
  3324.         uint16_t i = 0;
  3325.         for(std::map<uint16_t, uint32_t>::const_iterator it = depotItems.begin(), end = depotItems.end(); it != end && i < 0xFFFF; ++it, ++i)
  3326.         {
  3327.             msg->AddU16(it->first);
  3328.             msg->AddU16(std::min<uint32_t>(0xFFFF, it->second));
  3329.         }
  3330.     }
  3331. }
  3332.  
  3333. void ProtocolGame::sendMarketLeave()
  3334. {
  3335.     NetworkMessage_ptr msg = getOutputBuffer();
  3336.     if(msg)
  3337.     {
  3338.         TRACK_MESSAGE(msg);
  3339.         msg->AddByte(0xF7);
  3340.     }
  3341.    
  3342. }
  3343.  
  3344. void ProtocolGame::sendMarketBrowseItem(uint16_t itemId, const MarketOfferList& buyOffers, const MarketOfferList& sellOffers)
  3345. {
  3346.     NetworkMessage_ptr msg = getOutputBuffer();
  3347.     if(msg)
  3348.     {
  3349.         TRACK_MESSAGE(msg);
  3350.         msg->AddByte(0xF9);
  3351.         msg->AddU16(2160);
  3352.         msg->AddU32(buyOffers.size());
  3353.         for(MarketOfferList::const_iterator it = buyOffers.begin(), end = buyOffers.end(); it != end; ++it)
  3354.         {
  3355.             msg->AddU32(it->timestamp);
  3356.             msg->AddU16(it->counter);
  3357.             msg->AddU16(it->amount);
  3358.             msg->AddItemId(it->itemId);
  3359.             msg->AddU32(it->price);
  3360.             msg->AddString(it->playerName);
  3361.             const ItemType& itt = Item::items[it->itemId];
  3362.             Item* item = Item::CreateItem(itt.id, 1);
  3363.             std::stringstream test(it->Attrs);
  3364.             std::string segment;
  3365.             std::vector<std::string> seglist;
  3366.             if(it->Attrs != "false"){
  3367.                 while(std::getline(test, segment, 'ΒΊ'))
  3368.                 {
  3369.                     seglist.push_back(segment);
  3370.                 }
  3371.                 for(int i = 0; i < seglist.size(); i++) {
  3372.                     std::stringstream test2(seglist[i]);
  3373.                     std::string segment2;
  3374.                     std::vector<std::string> seglist2;
  3375.                     while(std::getline(test2, segment2, '#'))
  3376.                     {
  3377.                         seglist2.push_back(segment2);
  3378.                     }
  3379. if(seglist2.size() != 2){
  3380.     std::cout << "Error: seglist2 contains improper amount of segments (" << test2 << ")." << std::endl;
  3381.     continue;
  3382. }
  3383. else if(isNumbers(seglist2[1])){
  3384.     item->setAttribute(seglist2[0], atoi(seglist2[1].c_str()));
  3385. }
  3386. else {
  3387.     item->setAttribute(seglist2[0], seglist2[1]);
  3388. }
  3389.                 }
  3390.             }
  3391.             if(item->hasStringAttribute("poke")){
  3392.                 msg->AddString(item->getPoke());
  3393.             }else{
  3394.                 msg->AddString(item->getName());
  3395.             }
  3396.             delete item;
  3397.         }
  3398.  
  3399.         msg->AddU32(sellOffers.size());
  3400.         for(MarketOfferList::const_iterator it = sellOffers.begin(), end = sellOffers.end(); it != end; ++it)
  3401.         {
  3402.             msg->AddU32(it->timestamp);
  3403.             msg->AddU16(it->counter);
  3404.             msg->AddItemId(it->itemId);
  3405.             msg->AddU16(it->amount);
  3406.             msg->AddU32(it->price);
  3407.             msg->AddString(it->playerName);
  3408.             const ItemType& itt = Item::items[it->itemId];
  3409.             Item* item = Item::CreateItem(itt.id, 1);
  3410.             std::stringstream test(it->Attrs);
  3411.             std::string segment;
  3412.             std::vector<std::string> seglist;
  3413.             if(it->Attrs != "false"){
  3414.                 while(std::getline(test, segment, 'ΒΊ'))
  3415.                 {
  3416.                     seglist.push_back(segment);
  3417.                 }
  3418.                 for(int i = 0; i < seglist.size(); i++) {
  3419.                     std::stringstream test2(seglist[i]);
  3420.                     std::string segment2;
  3421.                     std::vector<std::string> seglist2;
  3422.                     while(std::getline(test2, segment2, '#'))
  3423.                     {
  3424.                         seglist2.push_back(segment2);
  3425.                     }
  3426. if(seglist2.size() != 2){
  3427.     std::cout << "Error: seglist2 contains improper amount of segments (" << test2 << ")." << std::endl;
  3428.     continue;
  3429. }
  3430. else if(isNumbers(seglist2[1])){
  3431.     item->setAttribute(seglist2[0], atoi(seglist2[1].c_str()));
  3432. }
  3433. else {
  3434.     item->setAttribute(seglist2[0], seglist2[1]);
  3435. }
  3436.                 }
  3437.             }
  3438.             if(item->hasStringAttribute("poke")){
  3439.                 msg->AddString(item->getPoke());
  3440.             }else{
  3441.                 msg->AddString(item->getName());
  3442.             }
  3443.             delete item;
  3444.         }
  3445.     }
  3446. }
  3447.  
  3448. void ProtocolGame::sendMarketAcceptOffer(MarketOfferEx offer)
  3449. {
  3450.     NetworkMessage_ptr msg = getOutputBuffer();
  3451.     if(msg)
  3452.     {
  3453.         TRACK_MESSAGE(msg);
  3454.         msg->AddByte(0xF9);
  3455.         msg->AddItemId(offer.itemId);
  3456.         if(offer.type == MARKETACTION_BUY)
  3457.         {
  3458.             msg->AddU32(0x01);
  3459.             msg->AddU32(offer.timestamp);
  3460.             msg->AddU16(offer.counter);
  3461.             msg->AddU16(offer.amount);
  3462.             msg->AddItemId(offer.itemId);
  3463.             msg->AddU32(offer.price);
  3464.             msg->AddString(offer.playerName);
  3465.             msg->AddU32(0x00);
  3466.             const ItemType& itt = Item::items[offer.itemId];
  3467.             Item* item = Item::CreateItem(itt.id, 1);
  3468.             std::stringstream test(offer.Attrs);
  3469.             std::string segment;
  3470.             std::vector<std::string> seglist;
  3471.             if(offer.Attrs != "false"){
  3472.                 while(std::getline(test, segment, 'ΒΊ'))
  3473.                 {
  3474.                     seglist.push_back(segment);
  3475.                 }
  3476.                 for(int i = 0; i < seglist.size(); i++) {
  3477.                     std::stringstream test2(seglist[i]);
  3478.                     std::string segment2;
  3479.                     std::vector<std::string> seglist2;
  3480.                     while(std::getline(test2, segment2, '#'))
  3481.                     {
  3482.                         seglist2.push_back(segment2);
  3483.                     }
  3484. if(seglist2.size() != 2){
  3485.     std::cout << "Error: seglist2 contains improper amount of segments (" << test2 << ")." << std::endl;
  3486.     continue;
  3487. }
  3488. else if(isNumbers(seglist2[1])){
  3489.     item->setAttribute(seglist2[0], atoi(seglist2[1].c_str()));
  3490. }
  3491. else {
  3492.     item->setAttribute(seglist2[0], seglist2[1]);
  3493. }
  3494.                 }
  3495.             }
  3496.             if(item->hasStringAttribute("poke")){
  3497.                 msg->AddString(item->getPoke());
  3498.             }else{
  3499.                 msg->AddString(item->getName());
  3500.             }
  3501.             delete item;
  3502.         }
  3503.         else
  3504.         {
  3505.             msg->AddU32(0x00);
  3506.             msg->AddU32(0x01);
  3507.             msg->AddU32(offer.timestamp);
  3508.             msg->AddU16(offer.counter);
  3509.             msg->AddU16(offer.amount);
  3510.             msg->AddItemId(offer.itemId);
  3511.             msg->AddU32(offer.price);
  3512.             msg->AddString(offer.playerName);
  3513.             const ItemType& itt = Item::items[offer.itemId];
  3514.             Item* item = Item::CreateItem(itt.id, 1);
  3515.             std::stringstream test(offer.Attrs);
  3516.             std::string segment;
  3517.             std::vector<std::string> seglist;
  3518.             if(offer.Attrs != "false"){
  3519.                 while(std::getline(test, segment, 'ΒΊ'))
  3520.                 {
  3521.                     seglist.push_back(segment);
  3522.                 }
  3523.                 for(int i = 0; i < seglist.size(); i++) {
  3524.                     std::stringstream test2(seglist[i]);
  3525.                     std::string segment2;
  3526.                     std::vector<std::string> seglist2;
  3527.                     while(std::getline(test2, segment2, '#'))
  3528.                     {
  3529.                         seglist2.push_back(segment2);
  3530.                     }
  3531. if(seglist2.size() != 2){
  3532.     std::cout << "Error: seglist2 contains improper amount of segments (" << test2 << ")." << std::endl;
  3533.     continue;
  3534. }
  3535. else if(isNumbers(seglist2[1])){
  3536.     item->setAttribute(seglist2[0], atoi(seglist2[1].c_str()));
  3537. }
  3538. else {
  3539.     item->setAttribute(seglist2[0], seglist2[1]);
  3540. }
  3541.                 }
  3542.             }
  3543.             if(item->hasStringAttribute("poke")){
  3544.                 msg->AddString(item->getPoke());
  3545.             }else{
  3546.                 msg->AddString(item->getName());
  3547.             }
  3548.             delete item;
  3549.         }
  3550.     }
  3551. }
  3552.  
  3553. void ProtocolGame::sendMarketItemDesc(const std::string& desc, uint16_t itemId)
  3554. {
  3555.     NetworkMessage_ptr msg = getOutputBuffer();
  3556.     if(msg)
  3557.     {
  3558.         TRACK_MESSAGE(msg);
  3559.         msg->AddByte(0xFF);
  3560.         msg->AddString(desc);
  3561.         msg->AddItemId(itemId);
  3562.     }
  3563. }
  3564.  
  3565. void ProtocolGame::sendMarketBrowseOwnOffers(const MarketOfferList& buyOffers, const MarketOfferList& sellOffers)
  3566. {
  3567.     NetworkMessage_ptr msg = getOutputBuffer();
  3568.     if(msg)
  3569.     {
  3570.         TRACK_MESSAGE(msg);
  3571.         msg->AddByte(0xF9);
  3572.         msg->AddU16(MARKETREQUEST_OWN_OFFERS);
  3573.  
  3574.         msg->AddU32(buyOffers.size());
  3575.         for(MarketOfferList::const_iterator it = buyOffers.begin(), end = buyOffers.end(); it != end; ++it)
  3576.         {
  3577.             msg->AddU32(it->timestamp);
  3578.             msg->AddU16(it->counter);
  3579.             msg->AddItemId(it->itemId);
  3580.             msg->AddU16(it->amount);
  3581.             msg->AddU32(it->price);
  3582.             const ItemType& itt = Item::items[it->itemId];
  3583.             Item* item = Item::CreateItem(itt.id, 1);
  3584.             std::stringstream test(it->Attrs);
  3585.             std::string segment;
  3586.             std::vector<std::string> seglist;
  3587.             if(it->Attrs != "false"){
  3588.                 while(std::getline(test, segment, 'ΒΊ'))
  3589.                 {
  3590.                     seglist.push_back(segment);
  3591.                 }
  3592.                 for(int i = 0; i < seglist.size(); i++) {
  3593.                     std::stringstream test2(seglist[i]);
  3594.                     std::string segment2;
  3595.                     std::vector<std::string> seglist2;
  3596.                     while(std::getline(test2, segment2, '#'))
  3597.                     {
  3598.                         seglist2.push_back(segment2);
  3599.                     }
  3600.                     if(std::isdigit(atoi((char*)seglist2[1].c_str())) || atoi((char*)seglist2[1].c_str()) >= 1){
  3601.                         item->setAttribute(seglist2[0], atoi((char*)seglist2[1].c_str()));
  3602.                     }else{
  3603.                         item->setAttribute(seglist2[0], seglist2[1]);
  3604.                     }
  3605.                 }
  3606.             }
  3607.             if(item->hasStringAttribute("poke")){
  3608.                 msg->AddString(item->getPoke());
  3609.             }else{
  3610.                 msg->AddString(item->getName());
  3611.             }
  3612.             delete item;
  3613.         }
  3614.  
  3615.         msg->AddU32(sellOffers.size());
  3616.         for(MarketOfferList::const_iterator it = sellOffers.begin(), end = sellOffers.end(); it != end; ++it)
  3617.         {
  3618.             msg->AddU32(it->timestamp);
  3619.             msg->AddU16(it->counter);
  3620.             msg->AddItemId(it->itemId);
  3621.             msg->AddU16(it->amount);
  3622.             msg->AddU32(it->price);
  3623.             const ItemType& itt = Item::items[it->itemId];
  3624.             Item* item = Item::CreateItem(itt.id, 1);
  3625.             std::stringstream test(it->Attrs);
  3626.             std::string segment;
  3627.             std::vector<std::string> seglist;
  3628.             if(it->Attrs != "false"){
  3629.                 while(std::getline(test, segment, 'ΒΊ'))
  3630.                 {
  3631.                     seglist.push_back(segment);
  3632.                 }
  3633.                 for(int i = 0; i < seglist.size(); i++) {
  3634.                     std::stringstream test2(seglist[i]);
  3635.                     std::string segment2;
  3636.                     std::vector<std::string> seglist2;
  3637.                     while(std::getline(test2, segment2, '#'))
  3638.                     {
  3639.                         seglist2.push_back(segment2);
  3640.                     }
  3641.                     if(std::isdigit(atoi((char*)seglist2[1].c_str())) || atoi((char*)seglist2[1].c_str()) >= 1){
  3642.                         item->setAttribute(seglist2[0], atoi((char*)seglist2[1].c_str()));
  3643.                     }else{
  3644.                         item->setAttribute(seglist2[0], seglist2[1]);
  3645.                     }
  3646.                 }
  3647.             }
  3648.             if(item->hasStringAttribute("poke")){
  3649.                 msg->AddString(item->getPoke());
  3650.             }else{
  3651.                 msg->AddString(item->getName());
  3652.             }
  3653.             delete item;
  3654.         }
  3655.     }  
  3656. }
  3657.  
  3658. void ProtocolGame::sendMarketCancelOffer(MarketOfferEx offer)
  3659. {
  3660.     NetworkMessage_ptr msg = getOutputBuffer();
  3661.     if(msg)
  3662.     {
  3663.         TRACK_MESSAGE(msg);
  3664.         msg->AddByte(0xF9);
  3665.         msg->AddU16(MARKETREQUEST_OWN_OFFERS);
  3666.         if(offer.type == MARKETACTION_BUY)
  3667.         {
  3668.             msg->AddU32(0x01);
  3669.             msg->AddU32(offer.timestamp);
  3670.             msg->AddU16(offer.counter);
  3671.             msg->AddItemId(offer.itemId);
  3672.             msg->AddU16(offer.amount);
  3673.             msg->AddU32(offer.price);
  3674.             const ItemType& itt = Item::items[offer.itemId];
  3675.             Item* item = Item::CreateItem(itt.id, 1);
  3676.             std::stringstream test(offer.Attrs);
  3677.             std::string segment;
  3678.             std::vector<std::string> seglist;
  3679.             if(offer.Attrs != "false"){
  3680.                 while(std::getline(test, segment, 'ΒΊ'))
  3681.                 {
  3682.                     seglist.push_back(segment);
  3683.                 }
  3684.                 for(int i = 0; i < seglist.size(); i++) {
  3685.                     std::stringstream test2(seglist[i]);
  3686.                     std::string segment2;
  3687.                     std::vector<std::string> seglist2;
  3688.                     while(std::getline(test2, segment2, '#'))
  3689.                     {
  3690.                         seglist2.push_back(segment2);
  3691.                     }
  3692.                     if(std::isdigit(atoi((char*)seglist2[1].c_str())) || atoi((char*)seglist2[1].c_str()) >= 1){
  3693.                         item->setAttribute(seglist2[0], atoi((char*)seglist2[1].c_str()));
  3694.                     }else{
  3695.                         item->setAttribute(seglist2[0], seglist2[1]);
  3696.                     }
  3697.                 }
  3698.             }
  3699.             if(item->hasStringAttribute("poke")){
  3700.                 msg->AddString(item->getPoke());
  3701.             }else{
  3702.                 msg->AddString(item->getName());
  3703.             }
  3704.             msg->AddU32(0x00);
  3705.             delete item;
  3706.         }
  3707.         else
  3708.         {
  3709.             msg->AddU32(0x00);
  3710.             msg->AddU32(0x01);
  3711.             msg->AddU32(offer.timestamp);
  3712.             msg->AddU16(offer.counter);
  3713.             msg->AddItemId(offer.itemId);
  3714.             msg->AddU16(offer.amount);
  3715.             msg->AddU32(offer.price);
  3716.             const ItemType& itt = Item::items[offer.itemId];
  3717.             Item* item = Item::CreateItem(itt.id, 1);
  3718.             std::stringstream test(offer.Attrs);
  3719.             std::string segment;
  3720.             std::vector<std::string> seglist;
  3721.             if(offer.Attrs != "false"){
  3722.                 while(std::getline(test, segment, 'ΒΊ'))
  3723.                 {
  3724.                     seglist.push_back(segment);
  3725.                 }
  3726.                 for(int i = 0; i < seglist.size(); i++) {
  3727.                     std::stringstream test2(seglist[i]);
  3728.                     std::string segment2;
  3729.                     std::vector<std::string> seglist2;
  3730.                     while(std::getline(test2, segment2, '#'))
  3731.                     {
  3732.                         seglist2.push_back(segment2);
  3733.                     }
  3734.                     if(std::isdigit(atoi((char*)seglist2[1].c_str())) || atoi((char*)seglist2[1].c_str()) >= 1){
  3735.                         item->setAttribute(seglist2[0], atoi((char*)seglist2[1].c_str()));
  3736.                     }else{
  3737.                         item->setAttribute(seglist2[0], seglist2[1]);
  3738.                     }
  3739.                 }
  3740.             }
  3741.             if(item->hasStringAttribute("poke")){
  3742.                 msg->AddString(item->getPoke());
  3743.             }else{
  3744.                 msg->AddString(item->getName());
  3745.             }
  3746.             delete item;
  3747.         }
  3748.     }
  3749. }
  3750.  
  3751. void ProtocolGame::sendMarketBrowseOwnHistory(const HistoryMarketOfferList& buyOffers, const HistoryMarketOfferList& sellOffers)
  3752. {
  3753.     NetworkMessage_ptr msg = getOutputBuffer();
  3754.     if(msg)
  3755.     {
  3756.         TRACK_MESSAGE(msg);
  3757.         msg->AddByte(0xF9);
  3758.         msg->AddU16(MARKETREQUEST_OWN_HISTORY);
  3759.  
  3760.         std::map<uint32_t, uint16_t> counterMap;
  3761.  
  3762.         uint32_t i = 0;
  3763.         msg->AddU32(std::min<int32_t>(800, buyOffers.size()));
  3764.         for(HistoryMarketOfferList::const_iterator it = buyOffers.begin(), end = buyOffers.end(); it != end && i < 800; ++it, ++i)
  3765.         {
  3766.             msg->AddU32(it->timestamp);
  3767.             msg->AddU16(counterMap[it->timestamp]++);
  3768.             msg->AddItemId(it->itemId);
  3769.             msg->AddU16(it->amount);
  3770.             msg->AddU32(it->price);
  3771.             msg->AddByte(it->state);
  3772.             const ItemType& itt = Item::items[it->itemId];
  3773.             Item* item = Item::CreateItem(itt.id, 1);
  3774.             std::stringstream test(it->Attrs);
  3775.             std::string segment;
  3776.             std::vector<std::string> seglist;
  3777.             if(it->Attrs != "false"){
  3778.                 while(std::getline(test, segment, 'ΒΊ'))
  3779.                 {
  3780.                     seglist.push_back(segment);
  3781.                 }
  3782.                 for(int i = 0; i < seglist.size(); i++) {
  3783.                     std::stringstream test2(seglist[i]);
  3784.                     std::string segment2;
  3785.                     std::vector<std::string> seglist2;
  3786.                     while(std::getline(test2, segment2, '#'))
  3787.                     {
  3788.                         seglist2.push_back(segment2);
  3789.                     }
  3790.                     if(std::isdigit(atoi((char*)seglist2[1].c_str())) || atoi((char*)seglist2[1].c_str()) >= 1){
  3791.                         item->setAttribute(seglist2[0], atoi((char*)seglist2[1].c_str()));
  3792.                     }else{
  3793.                         item->setAttribute(seglist2[0], seglist2[1]);
  3794.                     }
  3795.                 }
  3796.             }
  3797.             if(item->hasStringAttribute("poke")){
  3798.                 msg->AddString(item->getPoke());
  3799.             }else{
  3800.                 msg->AddString(item->getName());
  3801.             }
  3802.             delete item;
  3803.         }
  3804.  
  3805.         counterMap.clear();
  3806.         i = 0;
  3807.  
  3808.         msg->AddU32(std::min<int32_t>(800, sellOffers.size()));
  3809.         for(HistoryMarketOfferList::const_iterator it = sellOffers.begin(), end = sellOffers.end(); it != end && i < 800; ++it, ++i)
  3810.         {
  3811.             msg->AddU32(it->timestamp);
  3812.             msg->AddU16(counterMap[it->timestamp]++);
  3813.             msg->AddItemId(it->itemId);
  3814.             msg->AddU16(it->amount);
  3815.             msg->AddU32(it->price);
  3816.             msg->AddByte(it->state);
  3817.             const ItemType& itt = Item::items[it->itemId];
  3818.             Item* item = Item::CreateItem(itt.id, 1);
  3819.             std::stringstream test(it->Attrs);
  3820.             std::string segment;
  3821.             std::vector<std::string> seglist;
  3822.             if(it->Attrs != "false"){
  3823.                 while(std::getline(test, segment, 'ΒΊ'))
  3824.                 {
  3825.                     seglist.push_back(segment);
  3826.                 }
  3827.                 for(int i = 0; i < seglist.size(); i++) {
  3828.                     std::stringstream test2(seglist[i]);
  3829.                     std::string segment2;
  3830.                     std::vector<std::string> seglist2;
  3831.                     while(std::getline(test2, segment2, '#'))
  3832.                     {
  3833.                         seglist2.push_back(segment2);
  3834.                     }
  3835.                     if(std::isdigit(atoi((char*)seglist2[1].c_str())) || atoi((char*)seglist2[1].c_str()) >= 1){
  3836.                         item->setAttribute(seglist2[0], atoi((char*)seglist2[1].c_str()));
  3837.                     }else{
  3838.                         item->setAttribute(seglist2[0], seglist2[1]);
  3839.                     }
  3840.                 }
  3841.             }
  3842.             if(item->hasStringAttribute("poke")){
  3843.                 msg->AddString(item->getPoke());
  3844.             }else{
  3845.                 msg->AddString(item->getName());
  3846.             }
  3847.             delete item;
  3848.         }
  3849.     }
  3850. }
  3851.  
  3852. void ProtocolGame::sendMarketDetail(uint16_t itemId)
  3853. {
  3854.     NetworkMessage_ptr msg = getOutputBuffer();
  3855.     if(msg)
  3856.     {
  3857.         TRACK_MESSAGE(msg);
  3858.     msg->AddByte(0xF8);
  3859.     msg->AddItemId(itemId);
  3860.  
  3861.     const ItemType& it = Item::items[itemId];
  3862.     std::ostringstream ss;
  3863.     if(it.armor != 0)
  3864.     {
  3865.         ss << it.armor;
  3866.         msg->AddString(ss.str());
  3867.     }
  3868.     else
  3869.         msg->AddU16(0x00);
  3870.  
  3871.     if(it.attack != 0)
  3872.     {
  3873.         ss.str("");
  3874.         ss << it.attack;
  3875.         if(it.abilities.elementType != COMBAT_NONE && it.decayTo > 0)
  3876.             ss << " physical +" << it.abilities.elementDamage << " " << getCombatName(it.abilities.elementType);
  3877.  
  3878.         // TODO: chance to hit, range
  3879.         // example:
  3880.         // "attack +x, chance to hit +y%, z fields"
  3881.  
  3882.         msg->AddString(ss.str());
  3883.     }
  3884.     else
  3885.         msg->AddU16(0x00);
  3886.  
  3887.     if(it.isContainer())
  3888.     {
  3889.         ss.str("");
  3890.         ss << it.maxItems;
  3891.         msg->AddString(ss.str());
  3892.     }
  3893.     else
  3894.         msg->AddU16(0x00);
  3895.  
  3896.     if(it.defense != 0)
  3897.     {
  3898.         ss.str("");
  3899.         ss << it.defense;
  3900.         if(it.extraDefense != 0)
  3901.             ss << " " << std::showpos << it.extraDefense << std::noshowpos;
  3902.  
  3903.         msg->AddString(ss.str());
  3904.     }
  3905.     else
  3906.         msg->AddU16(0x00);
  3907.  
  3908.     if(!it.description.empty())
  3909.     {
  3910.         std::string descr = it.description;
  3911.         if(descr[descr.length() - 1] == '.')
  3912.             descr.erase(descr.length() - 1);
  3913.  
  3914.         msg->AddString(descr);
  3915.     }
  3916.     else
  3917.         msg->AddU16(0x00);
  3918.  
  3919.     if(it.decayTime != 0)
  3920.     {
  3921.         ss.str("");
  3922.         ss << it.decayTime << " seconds";
  3923.         msg->AddString(ss.str());
  3924.     }
  3925.     else
  3926.         msg->AddU16(0x00);
  3927.  
  3928.     ss.str("");
  3929.     if(it.abilities.absorb)
  3930.     {
  3931.         bool separator = false;
  3932.         for(uint32_t i = (COMBAT_FIRST + 1); i <= COMBAT_LAST; ++i)
  3933.         {
  3934.             if(!it.abilities.absorb[i])
  3935.                 continue;
  3936.  
  3937.             if(separator)
  3938.                 ss << ", ";
  3939.             else
  3940.                 separator = true;
  3941.  
  3942.             ss << getCombatName(indexToCombatType(i)) << " " << std::showpos << it.abilities.absorb[i] << std::noshowpos << "%";
  3943.         }
  3944.     }
  3945.     msg->AddString(ss.str());
  3946.  
  3947.     if(it.minReqLevel != 0)
  3948.     {
  3949.         ss.str("");
  3950.         ss << it.minReqLevel;
  3951.         msg->AddString(ss.str());
  3952.     }
  3953.     else
  3954.         msg->AddU16(0x00);
  3955.  
  3956.     if(it.minReqMagicLevel != 0)
  3957.     {
  3958.         ss.str("");
  3959.         ss << it.minReqMagicLevel;
  3960.         msg->AddString(ss.str());
  3961.     }
  3962.     else
  3963.         msg->AddU16(0x00);
  3964.  
  3965.     msg->AddString(it.vocationString);
  3966.  
  3967.     msg->AddString(it.runeSpellName);
  3968.  
  3969.     ss.str("");
  3970.     if(it.abilities.skills)
  3971.     {
  3972.         bool separator = false;
  3973.         for(uint16_t i = SKILL_FIRST; i <= SKILL_LAST; i++)
  3974.         {
  3975.             if(!it.abilities.skills[i])
  3976.                 continue;
  3977.  
  3978.             if(separator)
  3979.                 ss << ", ";
  3980.             else
  3981.                 separator = true;
  3982.  
  3983.             ss << getSkillName(i) << " " << std::showpos << it.abilities.skills[i] << std::noshowpos;
  3984.         }
  3985.  
  3986.         if(it.abilities.stats[STAT_MAGICLEVEL] != 0)
  3987.         {
  3988.             if(separator)
  3989.                 ss << ", ";
  3990.             else
  3991.                 separator = true;
  3992.  
  3993.             ss << "magic level " << std::showpos << it.abilities.stats[STAT_MAGICLEVEL] << std::noshowpos;
  3994.         }
  3995.  
  3996.         if(it.abilities.speed != 0)
  3997.         {
  3998.             if(separator)
  3999.                 ss << ", ";
  4000.  
  4001.             ss << "speed" << " " << std::showpos << (int32_t)(it.abilities.speed / 2) << std::noshowpos;
  4002.         }
  4003.     }
  4004.     msg->AddString(ss.str());
  4005.  
  4006.     if(it.charges != 0)
  4007.     {
  4008.         ss.str("");
  4009.         ss << it.charges;
  4010.         msg->AddString(ss.str());
  4011.     }
  4012.     else
  4013.         msg->AddU16(0x00);
  4014.  
  4015.     std::string weaponName = getWeaponName(it.weaponType);
  4016.     if(it.slotPosition & SLOTP_TWO_HAND)
  4017.     {
  4018.         if(!weaponName.empty())
  4019.             weaponName += ", two-handed";
  4020.         else
  4021.             weaponName = "two-handed";
  4022.     }
  4023.     msg->AddString(weaponName);
  4024.  
  4025.     if(it.weight > 0)
  4026.     {
  4027.         ss.str("");
  4028.         ss << std::fixed << std::setprecision(2) << it.weight << " oz";
  4029.         msg->AddString(ss.str());
  4030.     }
  4031.     else
  4032.         msg->AddU16(0x00);
  4033.  
  4034.     MarketStatistics* statistics = IOMarket::getInstance()->getPurchaseStatistics(itemId);
  4035.     if(statistics)
  4036.     {
  4037.         msg->AddByte(0x01);
  4038.         msg->AddU32(statistics->numTransactions);
  4039.         msg->AddU32(std::min<uint64_t>(0xFFFFFFFF, statistics->totalPrice));
  4040.         msg->AddU32(statistics->highestPrice);
  4041.         msg->AddU32(statistics->lowestPrice);
  4042.     }
  4043.     else
  4044.         msg->AddByte(0x00);
  4045.  
  4046.     statistics = IOMarket::getInstance()->getSaleStatistics(itemId);
  4047.     if(statistics)
  4048.     {
  4049.         msg->AddByte(0x01);
  4050.         msg->AddU32(statistics->numTransactions);
  4051.         msg->AddU32(std::min<uint64_t>(0xFFFFFFFF, statistics->totalPrice));
  4052.         msg->AddU32(statistics->highestPrice);
  4053.         msg->AddU32(statistics->lowestPrice);
  4054.     }
  4055.     else
  4056.         msg->AddByte(0x00);
  4057.  
  4058.     }
  4059. }
  4060.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement