Advertisement
Guest User

Untitled

a guest
Jun 8th, 2012
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 78.26 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.  
  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.         Account account = IOLoginData::getInstance()->loadAccount(player->getAccount());
  117.         if(version < account.charList[name]->getVersionMin() || version > account.charList[name]->getVersionMax())
  118.         {
  119.             disconnectClient(0x14, "Invalid client version!");
  120.             return false;
  121.         }
  122.  
  123.         Ban ban;
  124.         ban.value = player->getID();
  125.         ban.param = PLAYERBAN_BANISHMENT;
  126.  
  127.         ban.type = BAN_PLAYER;
  128.         if(IOBan::getInstance()->getData(ban) && !player->hasFlag(PlayerFlag_CannotBeBanned))
  129.         {
  130.             bool deletion = ban.expires < 0;
  131.             std::string name_ = "Automatic ";
  132.             if(!ban.adminId)
  133.                 name_ += (deletion ? "deletion" : "banishment");
  134.             else
  135.                 IOLoginData::getInstance()->getNameByGuid(ban.adminId, name_, true);
  136.  
  137.             char buffer[500 + ban.comment.length()];
  138.             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.",
  139.                 (deletion ? "deleted" : "banished"), formatDateShort(ban.added).c_str(), name_.c_str(),
  140.                 getReason(ban.reason).c_str(), getAction(ban.action, false).c_str(), ban.comment.c_str(),
  141.                 (deletion ? "character won't be undeleted" : "banishment will be lifted at:\n"),
  142.                 (deletion ? "." : formatDateShort(ban.expires, true).c_str()));
  143.  
  144.             disconnectClient(0x14, buffer);
  145.             return false;
  146.         }
  147.  
  148.         if(IOBan::getInstance()->isPlayerBanished(player->getGUID(), PLAYERBAN_LOCK) && id != 1)
  149.         {
  150.             if(g_config.getBool(ConfigManager::NAMELOCK_MANAGER))
  151.             {
  152.                 player->name = "Account Manager";
  153.                 player->accountManager = MANAGER_NAMELOCK;
  154.  
  155.                 player->managerNumber = id;
  156.                 player->managerString2 = name;
  157.             }
  158.             else
  159.             {
  160.                 disconnectClient(0x14, "Your character has been namelocked.");
  161.                 return false;
  162.             }
  163.         }
  164.         else if(player->getName() == "Account Manager" && g_config.getBool(ConfigManager::ACCOUNT_MANAGER))
  165.         {
  166.             if(id != 1)
  167.             {
  168.                 player->accountManager = MANAGER_ACCOUNT;
  169.                 player->managerNumber = id;
  170.             }
  171.             else
  172.                 player->accountManager = MANAGER_NEW;
  173.         }
  174.  
  175.         if(gamemaster && !player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges))
  176.         {
  177.             disconnectClient(0x14, "You are not a gamemaster! Turn off the gamemaster mode in your IP changer.");
  178.             return false;
  179.         }
  180.  
  181.         if(!player->hasFlag(PlayerFlag_CanAlwaysLogin))
  182.         {
  183.             if(g_game.getGameState() == GAME_STATE_CLOSING)
  184.             {
  185.                 disconnectClient(0x14, "Gameworld is just going down, please come back later.");
  186.                 return false;
  187.             }
  188.  
  189.             if(g_game.getGameState() == GAME_STATE_CLOSED)
  190.             {
  191.                 disconnectClient(0x14, "Gameworld is currently closed, please come back later.");
  192.                 return false;
  193.             }
  194.         }
  195.  
  196.         if(g_config.getBool(ConfigManager::ONE_PLAYER_ON_ACCOUNT) && !player->isAccountManager() &&
  197.             !IOLoginData::getInstance()->hasCustomFlag(id, PlayerCustomFlag_CanLoginMultipleCharacters))
  198.         {
  199.             bool found = false;
  200.             PlayerVector tmp = g_game.getPlayersByAccount(id);
  201.             for(PlayerVector::iterator it = tmp.begin(); it != tmp.end(); ++it)
  202.             {
  203.                 if((*it)->getName() != name)
  204.                     continue;
  205.  
  206.                 found = true;
  207.                 break;
  208.             }
  209.  
  210.             if(tmp.size() > 0 && !found)
  211.             {
  212.                 disconnectClient(0x14, "You may only login with one character\nof your account at the same time.");
  213.                 return false;
  214.             }
  215.         }
  216.  
  217.         if(!WaitingList::getInstance()->login(player))
  218.         {
  219.             if(OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false))
  220.             {
  221.                 TRACK_MESSAGE(output);
  222.                 std::stringstream ss;
  223.                 ss << "Too many players online.\n" << "You are ";
  224.  
  225.                 int32_t slot = WaitingList::getInstance()->getSlot(player);
  226.                 if(slot)
  227.                 {
  228.                     ss << "at ";
  229.                     if(slot > 0)
  230.                         ss << slot;
  231.                     else
  232.                         ss << "unknown";
  233.  
  234.                     ss << " place on the waiting list.";
  235.                 }
  236.                 else
  237.                     ss << "awaiting connection...";
  238.  
  239.                 output->AddByte(0x16);
  240.                 output->AddString(ss.str());
  241.                 output->AddByte(WaitingList::getTime(slot));
  242.                 OutputMessagePool::getInstance()->send(output);
  243.             }
  244.  
  245.             getConnection()->close();
  246.             return false;
  247.         }
  248.  
  249.         if(!IOLoginData::getInstance()->loadPlayer(player, name))
  250.         {
  251.             disconnectClient(0x14, "Your character could not be loaded.");
  252.             return false;
  253.         }
  254.  
  255.         player->setOperatingSystem(operatingSystem);
  256.         player->setClientVersion(version);
  257.         if(!g_game.placeCreature(player, player->getLoginPosition()) && !g_game.placeCreature(player, player->getMasterPosition(), false, true))
  258.         {
  259.             disconnectClient(0x14, "Temple position is wrong. Contact with the administration.");
  260.             return false;
  261.  
  262.         }
  263.  
  264.         player->lastIP = player->getIP();
  265.         player->lastLoad = OTSYS_TIME();
  266.         player->lastLogin = std::max(time(NULL), player->lastLogin + 1);
  267.  
  268.         m_acceptPackets = true;
  269.         return true;
  270.     }
  271.     else if(_player->client)
  272.     {
  273.         if(m_eventConnect || !g_config.getBool(ConfigManager::REPLACE_KICK_ON_LOGIN))
  274.         {
  275.             //A task has already been scheduled just bail out (should not be overriden)
  276.             disconnectClient(0x14, "You are already logged in.");
  277.             return false;
  278.         }
  279.  
  280.         g_chat.removeUserFromAllChannels(_player);
  281.         _player->disconnect();
  282.         _player->isConnecting = true;
  283.  
  284.         addRef();
  285.         m_eventConnect = Scheduler::getInstance().addEvent(createSchedulerTask(
  286.             1000, boost::bind(&ProtocolGame::connect, this, _player->getID(), operatingSystem, version)));
  287.         return true;
  288.     }
  289.  
  290.     addRef();
  291.     return connect(_player->getID(), operatingSystem, version);
  292. }
  293.  
  294. bool ProtocolGame::logout(bool displayEffect, bool forceLogout)
  295. {
  296.     //dispatcher thread
  297.     if(!player)
  298.         return false;
  299.  
  300.     if(!player->isRemoved())
  301.     {
  302.         if(!forceLogout)
  303.         {
  304.             if(!IOLoginData::getInstance()->hasCustomFlag(player->getAccount(), PlayerCustomFlag_CanLogoutAnytime))
  305.             {
  306.                 if(player->getTile()->hasFlag(TILESTATE_NOLOGOUT))
  307.                 {
  308.                     player->sendCancelMessage(RET_YOUCANNOTLOGOUTHERE);
  309.                     return false;
  310.                 }
  311.  
  312.                 if(player->hasCondition(CONDITION_INFIGHT))
  313.                 {
  314.                     player->sendCancelMessage(RET_YOUMAYNOTLOGOUTDURINGAFIGHT);
  315.                     return false;
  316.                 }
  317.  
  318.                 if(!g_creatureEvents->playerLogout(player, false)) //let the script handle the error message
  319.                     return false;
  320.             }
  321.             else
  322.                 g_creatureEvents->playerLogout(player, false);
  323.         }
  324.         else if(!g_creatureEvents->playerLogout(player, true))
  325.             return false;
  326.     }
  327.     else
  328.         displayEffect = false;
  329.  
  330.     if(displayEffect && !player->isGhost())
  331.         g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
  332.  
  333.     if(Connection_ptr connection = getConnection())
  334.         connection->close();
  335.  
  336.     return g_game.removeCreature(player);
  337. }
  338.  
  339. bool ProtocolGame::connect(uint32_t playerId, OperatingSystem_t operatingSystem, uint16_t version)
  340. {
  341.     unRef();
  342.     m_eventConnect = 0;
  343.  
  344.     Player* _player = g_game.getPlayerByID(playerId);
  345.     if(!_player || _player->isRemoved() || _player->client)
  346.     {
  347.         disconnectClient(0x14, "You are already logged in.");
  348.         return false;
  349.     }
  350.  
  351.     player = _player;
  352.     player->addRef();
  353.     player->isConnecting = false;
  354.  
  355.     player->client = this;
  356.     player->sendCreatureAppear(player);
  357.  
  358.     player->setOperatingSystem(operatingSystem);
  359.     player->setClientVersion(version);
  360.  
  361.     player->lastIP = player->getIP();
  362.     player->lastLoad = OTSYS_TIME();
  363.     player->lastLogin = std::max(time(NULL), player->lastLogin + 1);
  364.  
  365.     m_acceptPackets = true;
  366.     return true;
  367. }
  368.  
  369. void ProtocolGame::disconnect()
  370. {
  371.     if(getConnection())
  372.         getConnection()->close();
  373. }
  374.  
  375. void ProtocolGame::disconnectClient(uint8_t error, const char* message)
  376. {
  377.     if(OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false))
  378.     {
  379.         TRACK_MESSAGE(output);
  380.         output->AddByte(error);
  381.         output->AddString(message);
  382.         OutputMessagePool::getInstance()->send(output);
  383.     }
  384.  
  385.     disconnect();
  386. }
  387.  
  388. void ProtocolGame::onConnect()
  389. {
  390.     if(OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false))
  391.     {
  392.         TRACK_MESSAGE(output);
  393.         enableChecksum();
  394.  
  395.         output->AddByte(0x1F);
  396.         output->AddU16(random_range(0, 0xFFFF));
  397.         output->AddU16(0x00);
  398.         output->AddByte(random_range(0, 0xFF));
  399.  
  400.         OutputMessagePool::getInstance()->send(output);
  401.     }
  402. }
  403.  
  404. void ProtocolGame::onRecvFirstMessage(NetworkMessage& msg)
  405. {
  406.     parseFirstPacket(msg);
  407. }
  408.  
  409. bool ProtocolGame::parseFirstPacket(NetworkMessage& msg)
  410. {
  411.     if(
  412. #if defined(WINDOWS) && !defined(__CONSOLE__)
  413.         !GUI::getInstance()->m_connections ||
  414. #endif
  415.         g_game.getGameState() == GAME_STATE_SHUTDOWN)
  416.     {
  417.         getConnection()->close();
  418.         return false;
  419.     }
  420.  
  421.     OperatingSystem_t operatingSystem = (OperatingSystem_t)msg.GetU16();
  422.     uint16_t version = msg.GetU16();
  423.     if(!RSA_decrypt(msg))
  424.     {
  425.         getConnection()->close();
  426.         return false;
  427.     }
  428.  
  429.     uint32_t key[4] = {msg.GetU32(), msg.GetU32(), msg.GetU32(), msg.GetU32()};
  430.     enableXTEAEncryption();
  431.     setXTEAKey(key);
  432.  
  433.     bool gamemaster = msg.GetByte();
  434.     std::string name = msg.GetString(), character = msg.GetString(), password = msg.GetString();
  435.  
  436.     msg.SkipBytes(6); //841- wtf?
  437.     if(version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX)
  438.     {
  439.         disconnectClient(0x14, CLIENT_VERSION_STRING);
  440.         return false;
  441.     }
  442.  
  443.     if(name.empty())
  444.     {
  445.         if(!g_config.getBool(ConfigManager::ACCOUNT_MANAGER))
  446.         {
  447.             disconnectClient(0x14, "Invalid account name.");
  448.             return false;
  449.         }
  450.  
  451.         name = "1";
  452.         password = "1";
  453.     }
  454.  
  455.     if(g_game.getGameState() < GAME_STATE_NORMAL)
  456.     {
  457.         disconnectClient(0x14, "Gameworld is just starting up, please wait.");
  458.         return false;
  459.     }
  460.  
  461.     if(g_game.getGameState() == GAME_STATE_MAINTAIN)
  462.     {
  463.         disconnectClient(0x14, "Gameworld is under maintenance, please re-connect in a while.");
  464.         return false;
  465.     }
  466.  
  467.     if(ConnectionManager::getInstance()->isDisabled(getIP(), protocolId))
  468.     {
  469.         disconnectClient(0x14, "Too many connections attempts from your IP address, please try again later.");
  470.         return false;
  471.     }
  472.  
  473.     if(IOBan::getInstance()->isIpBanished(getIP()))
  474.     {
  475.         disconnectClient(0x14, "Your IP is banished!");
  476.         return false;
  477.     }
  478.  
  479.     uint32_t id = 1;
  480.     if(!IOLoginData::getInstance()->getAccountId(name, id))
  481.     {
  482.         ConnectionManager::getInstance()->addAttempt(getIP(), protocolId, false);
  483.         disconnectClient(0x14, "Invalid account name.");
  484.         return false;
  485.     }
  486.  
  487.     std::string hash;
  488.     if(!IOLoginData::getInstance()->getPassword(id, hash, character) || !encryptTest(password, hash))
  489.     {
  490.         ConnectionManager::getInstance()->addAttempt(getIP(), protocolId, false);
  491.         disconnectClient(0x14, "Invalid password.");
  492.         return false;
  493.     }
  494.  
  495.     Ban ban;
  496.     ban.value = id;
  497.  
  498.     ban.type = BAN_ACCOUNT;
  499.     if(IOBan::getInstance()->getData(ban) && !IOLoginData::getInstance()->hasFlag(id, PlayerFlag_CannotBeBanned))
  500.     {
  501.         bool deletion = ban.expires < 0;
  502.         std::string name_ = "Automatic ";
  503.         if(!ban.adminId)
  504.             name_ += (deletion ? "deletion" : "banishment");
  505.         else
  506.             IOLoginData::getInstance()->getNameByGuid(ban.adminId, name_, true);
  507.  
  508.         char buffer[500 + ban.comment.length()];
  509.         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.",
  510.             (deletion ? "deleted" : "banished"), formatDateShort(ban.added).c_str(), name_.c_str(),
  511.             getReason(ban.reason).c_str(), getAction(ban.action, false).c_str(), ban.comment.c_str(),
  512.             (deletion ? "account won't be undeleted" : "banishment will be lifted at:\n"),
  513.             (deletion ? "." : formatDateShort(ban.expires, true).c_str()));
  514.  
  515.         disconnectClient(0x14, buffer);
  516.         return false;
  517.     }
  518.  
  519.     ConnectionManager::getInstance()->addAttempt(getIP(), protocolId, true);
  520.     Dispatcher::getInstance().addTask(createTask(boost::bind(
  521.         &ProtocolGame::login, this, character, id, password, operatingSystem, version, gamemaster)));
  522.     return true;
  523. }
  524.  
  525. void ProtocolGame::parsePacket(NetworkMessage &msg)
  526. {
  527.     if(!player || !m_acceptPackets || g_game.getGameState() == GAME_STATE_SHUTDOWN
  528.         || msg.getMessageLength() <= 0)
  529.         return;
  530.  
  531.     uint8_t recvbyte = msg.GetByte();
  532.     //a dead player cannot performs actions
  533.     if(player->isRemoved() && recvbyte != 0x14)
  534.         return;
  535.  
  536.     if(player->isAccountManager())
  537.     {
  538.         switch(recvbyte)
  539.         {
  540.             case 0x14:
  541.                 parseLogout(msg);
  542.                 break;
  543.  
  544.             case 0x96:
  545.                 parseSay(msg);
  546.                 break;
  547.  
  548.             default:
  549.                 sendCancelWalk();
  550.                 break;
  551.         }
  552.     }
  553.     else
  554.     {
  555.         switch(recvbyte)
  556.         {
  557.             case 0x14: // logout
  558.                 parseLogout(msg);
  559.                 break;
  560.  
  561.             case 0x1E: // keep alive / ping response
  562.                 parseReceivePing(msg);
  563.                 break;
  564.  
  565.             case 0x64: // move with steps
  566.                 parseAutoWalk(msg);
  567.                 break;
  568.  
  569.             case 0x65: // move north
  570.             case 0x66: // move east
  571.             case 0x67: // move south
  572.             case 0x68: // move west
  573.                 parseMove(msg, (Direction)(recvbyte - 0x65));
  574.                 break;
  575.  
  576.             case 0x69: // stop-autowalk
  577.                 addGameTask(&Game::playerStopAutoWalk, player->getID());
  578.                 break;
  579.  
  580.             case 0x6A:
  581.                 parseMove(msg, NORTHEAST);
  582.                 break;
  583.  
  584.             case 0x6B:
  585.                 parseMove(msg, SOUTHEAST);
  586.                 break;
  587.  
  588.             case 0x6C:
  589.                 parseMove(msg, SOUTHWEST);
  590.                 break;
  591.  
  592.             case 0x6D:
  593.                 parseMove(msg, NORTHWEST);
  594.                 break;
  595.  
  596.             case 0x6F: // turn north
  597.             case 0x70: // turn east
  598.             case 0x71: // turn south
  599.             case 0x72: // turn west
  600.                 parseTurn(msg, (Direction)(recvbyte - 0x6F));
  601.                 break;
  602.  
  603.             case 0x78: // throw item
  604.                 parseThrow(msg);
  605.                 break;
  606.  
  607.             case 0x79: // description in shop window
  608.                 parseLookInShop(msg);
  609.                 break;
  610.  
  611.             case 0x7A: // player bought from shop
  612.                 parsePlayerPurchase(msg);
  613.                 break;
  614.  
  615.             case 0x7B: // player sold to shop
  616.                 parsePlayerSale(msg);
  617.                 break;
  618.  
  619.             case 0x7C: // player closed shop window
  620.                 parseCloseShop(msg);
  621.                 break;
  622.  
  623.             case 0x7D: // Request trade
  624.                 parseRequestTrade(msg);
  625.                 break;
  626.  
  627.             case 0x7E: // Look at an item in trade
  628.                 parseLookInTrade(msg);
  629.                 break;
  630.  
  631.             case 0x7F: // Accept trade
  632.                 parseAcceptTrade(msg);
  633.                 break;
  634.  
  635.             case 0x80: // close/cancel trade
  636.                 parseCloseTrade();
  637.                 break;
  638.  
  639.             case 0x82: // use item
  640.                 parseUseItem(msg);
  641.                 break;
  642.  
  643.             case 0x83: // use item
  644.                 parseUseItemEx(msg);
  645.                 break;
  646.  
  647.             case 0x84: // battle window
  648.                 parseBattleWindow(msg);
  649.                 break;
  650.  
  651.             case 0x85: //rotate item
  652.                 parseRotateItem(msg);
  653.                 break;
  654.  
  655.             case 0x87: // close container
  656.                 parseCloseContainer(msg);
  657.                 break;
  658.  
  659.             case 0x88: //"up-arrow" - container
  660.                 parseUpArrowContainer(msg);
  661.                 break;
  662.  
  663.             case 0x89:
  664.                 parseTextWindow(msg);
  665.                 break;
  666.  
  667.             case 0x8A:
  668.                 parseHouseWindow(msg);
  669.                 break;
  670.  
  671.             case 0x8C: // throw item
  672.                 parseLookAt(msg);
  673.                 break;
  674.  
  675.             case 0x96: // say something
  676.                 parseSay(msg);
  677.                 break;
  678.  
  679.             case 0x97: // request channels
  680.                 parseGetChannels(msg);
  681.                 break;
  682.  
  683.             case 0x98: // open channel
  684.                 parseOpenChannel(msg);
  685.                 break;
  686.  
  687.             case 0x99: // close channel
  688.                 parseCloseChannel(msg);
  689.                 break;
  690.  
  691.             case 0x9A: // open priv
  692.                 parseOpenPriv(msg);
  693.                 break;
  694.  
  695.             case 0x9B: //process report
  696.                 parseProcessRuleViolation(msg);
  697.                 break;
  698.  
  699.             case 0x9C: //gm closes report
  700.                 parseCloseRuleViolation(msg);
  701.                 break;
  702.  
  703.             case 0x9D: //player cancels report
  704.                 parseCancelRuleViolation(msg);
  705.                 break;
  706.  
  707.             case 0x9E: // close NPC
  708.                 parseCloseNpc(msg);
  709.                 break;
  710.  
  711.             case 0xA0: // set attack and follow mode
  712.                 parseFightModes(msg);
  713.                 break;
  714.  
  715.             case 0xA1: // attack
  716.                 parseAttack(msg);
  717.                 break;
  718.  
  719.             case 0xA2: //follow
  720.                 parseFollow(msg);
  721.                 break;
  722.  
  723.             case 0xA3: // invite party
  724.                 parseInviteToParty(msg);
  725.                 break;
  726.  
  727.             case 0xA4: // join party
  728.                 parseJoinParty(msg);
  729.                 break;
  730.  
  731.             case 0xA5: // revoke party
  732.                 parseRevokePartyInvite(msg);
  733.                 break;
  734.  
  735.             case 0xA6: // pass leadership
  736.                 parsePassPartyLeadership(msg);
  737.                 break;
  738.  
  739.             case 0xA7: // leave party
  740.                 parseLeaveParty(msg);
  741.                 break;
  742.  
  743.             case 0xA8: // share exp
  744.                 parseSharePartyExperience(msg);
  745.                 break;
  746.  
  747.             case 0xAA:
  748.                 parseCreatePrivateChannel(msg);
  749.                 break;
  750.  
  751.             case 0xAB:
  752.                 parseChannelInvite(msg);
  753.                 break;
  754.  
  755.             case 0xAC:
  756.                 parseChannelExclude(msg);
  757.                 break;
  758.  
  759.             case 0xBE: // cancel move
  760.                 parseCancelMove(msg);
  761.                 break;
  762.  
  763.             case 0xC9: //client request to resend the tile
  764.                 parseUpdateTile(msg);
  765.                 break;
  766.  
  767.             case 0xCA: //client request to resend the container (happens when you store more than container maxsize)
  768.                 parseUpdateContainer(msg);
  769.                 break;
  770.  
  771.             case 0xD2: // request outfit
  772.                 if((!player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges) || !g_config.getBool(
  773.                     ConfigManager::DISABLE_OUTFITS_PRIVILEGED)) && (g_config.getBool(ConfigManager::ALLOW_CHANGEOUTFIT)
  774.                     || g_config.getBool(ConfigManager::ALLOW_CHANGECOLORS) || g_config.getBool(ConfigManager::ALLOW_CHANGEADDONS)))
  775.                     parseRequestOutfit(msg);
  776.                 break;
  777.  
  778.             case 0xD3: // set outfit
  779.                 if((!player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges) || !g_config.getBool(ConfigManager::DISABLE_OUTFITS_PRIVILEGED))
  780.                     && (g_config.getBool(ConfigManager::ALLOW_CHANGECOLORS) || g_config.getBool(ConfigManager::ALLOW_CHANGEOUTFIT)))
  781.                 parseSetOutfit(msg);
  782.                 break;
  783.  
  784.             case 0xDC:
  785.                 parseAddVip(msg);
  786.                 break;
  787.  
  788.             case 0xDD:
  789.                 parseRemoveVip(msg);
  790.                 break;
  791.  
  792.             case 0xE6:
  793.                 parseBugReport(msg);
  794.                 break;
  795.  
  796.             case 0xE7:
  797.                 parseViolationWindow(msg);
  798.                 break;
  799.  
  800.             case 0xE8:
  801.                 parseDebugAssert(msg);
  802.                 break;
  803.  
  804.             case 0xF0:
  805.                 parseQuests(msg);
  806.                 break;
  807.  
  808.             case 0xF1:
  809.                 parseQuestInfo(msg);
  810.                 break;
  811.  
  812.             default:
  813.             {
  814.                 if(g_config.getBool(ConfigManager::BAN_UNKNOWN_BYTES))
  815.                 {
  816.                     int64_t banTime = -1;
  817.                     ViolationAction_t action = ACTION_BANISHMENT;
  818.                     Account tmp = IOLoginData::getInstance()->loadAccount(player->getAccount(), true);
  819.  
  820.                     tmp.warnings++;
  821.                     if(tmp.warnings >= g_config.getNumber(ConfigManager::WARNINGS_TO_DELETION))
  822.                         action = ACTION_DELETION;
  823.                     else if(tmp.warnings >= g_config.getNumber(ConfigManager::WARNINGS_TO_FINALBAN))
  824.                     {
  825.                         banTime = time(NULL) + g_config.getNumber(ConfigManager::FINALBAN_LENGTH);
  826.                         action = ACTION_BANFINAL;
  827.                     }
  828.                     else
  829.                         banTime = time(NULL) + g_config.getNumber(ConfigManager::BAN_LENGTH);
  830.  
  831.                     if(IOBan::getInstance()->addAccountBanishment(tmp.number, banTime, 13, action,
  832.                         "Sending unknown packets to the server.", 0, player->getGUID()))
  833.                     {
  834.                         IOLoginData::getInstance()->saveAccount(tmp);
  835.                         player->sendTextMessage(MSG_INFO_DESCR, "You have been banished.");
  836.  
  837.                         g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_WRAPS_GREEN);
  838.                         Scheduler::getInstance().addEvent(createSchedulerTask(1000, boost::bind(
  839.                             &Game::kickPlayer, &g_game, player->getID(), false)));
  840.                     }
  841.                 }
  842.  
  843.                 std::stringstream hex, s;
  844.                 hex << "0x" << std::hex << (int16_t)recvbyte << std::dec;
  845.                 s << player->getName() << " sent unknown byte: " << hex << std::endl;
  846.  
  847.                 LOG_MESSAGE(LOGTYPE_NOTICE, s.str(), "PLAYER")
  848.                 Logger::getInstance()->eFile(getFilePath(FILE_TYPE_LOG, "bots/" + player->getName() + ".log").c_str(),
  849.                     "[" + formatDate() + "] Received byte " + hex.str(), false);
  850.                 break;
  851.             }
  852.         }
  853.     }
  854. }
  855.  
  856. void ProtocolGame::GetTileDescription(const Tile* tile, NetworkMessage_ptr msg)
  857. {
  858.     if(!tile)
  859.         return;
  860.  
  861.     int32_t count = 0;
  862.     if(tile->ground)
  863.     {
  864.         msg->AddItem(tile->ground);
  865.         count++;
  866.     }
  867.  
  868.     const TileItemVector* items = tile->getItemList();
  869.     const CreatureVector* creatures = tile->getCreatures();
  870.  
  871.     ItemVector::const_iterator it;
  872.     if(items)
  873.     {
  874.         for(it = items->getBeginTopItem(); (it != items->getEndTopItem() && count < 10); ++it, ++count)
  875.             msg->AddItem(*it);
  876.     }
  877.  
  878.     if(creatures)
  879.     {
  880.         for(CreatureVector::const_reverse_iterator cit = creatures->rbegin(); (cit != creatures->rend() && count < 10); ++cit)
  881.         {
  882.             if(!player->canSeeCreature(*cit))
  883.                 continue;
  884.  
  885.             bool known;
  886.             uint32_t removedKnown;
  887.             checkCreatureAsKnown((*cit)->getID(), known, removedKnown);
  888.  
  889.             AddCreature(msg, (*cit), known, removedKnown);
  890.             count++;
  891.         }
  892.     }
  893.  
  894.     if(items)
  895.     {
  896.         for(it = items->getBeginDownItem(); (it != items->getEndDownItem() && count < 10); ++it, ++count)
  897.             msg->AddItem(*it);
  898.     }
  899. }
  900.  
  901. void ProtocolGame::GetMapDescription(int32_t x, int32_t y, int32_t z,
  902.     int32_t width, int32_t height, NetworkMessage_ptr msg)
  903. {
  904.     int32_t skip = -1, startz, endz, zstep = 0;
  905.     if(z > 7)
  906.     {
  907.         startz = z - 2;
  908.         endz = std::min((int32_t)MAP_MAX_LAYERS - 1, z + 2);
  909.         zstep = 1;
  910.     }
  911.     else
  912.     {
  913.         startz = 7;
  914.         endz = 0;
  915.         zstep = -1;
  916.     }
  917.  
  918.     for(int32_t nz = startz; nz != endz + zstep; nz += zstep)
  919.         GetFloorDescription(msg, x, y, nz, width, height, z - nz, skip);
  920.  
  921.     if(skip >= 0)
  922.     {
  923.         msg->AddByte(skip);
  924.         msg->AddByte(0xFF);
  925.         //cc += skip;
  926.     }
  927. }
  928.  
  929. void ProtocolGame::GetFloorDescription(NetworkMessage_ptr msg, int32_t x, int32_t y, int32_t z,
  930.         int32_t width, int32_t height, int32_t offset, int32_t& skip)
  931. {
  932.     Tile* tile = NULL;
  933.     for(int32_t nx = 0; nx < width; nx++)
  934.     {
  935.         for(int32_t ny = 0; ny < height; ny++)
  936.         {
  937.             if((tile = g_game.getTile(Position(x + nx + offset, y + ny + offset, z))))
  938.             {
  939.                 if(skip >= 0)
  940.                 {
  941.                     msg->AddByte(skip);
  942.                     msg->AddByte(0xFF);
  943.                 }
  944.  
  945.                 skip = 0;
  946.                 GetTileDescription(tile, msg);
  947.             }
  948.             else
  949.             {
  950.                 ++skip;
  951.                 if(skip == 0xFF)
  952.                 {
  953.                     msg->AddByte(0xFF);
  954.                     msg->AddByte(0xFF);
  955.                     skip = -1;
  956.                 }
  957.             }
  958.         }
  959.     }
  960. }
  961.  
  962. void ProtocolGame::checkCreatureAsKnown(uint32_t id, bool& known, uint32_t& removedKnown)
  963. {
  964.     // loop through the known creature list and check if the given creature is in
  965.     for(std::list<uint32_t>::iterator it = knownCreatureList.begin(); it != knownCreatureList.end(); ++it)
  966.     {
  967.         if((*it) != id)
  968.             continue;
  969.  
  970.         // know... make the creature even more known...
  971.         knownCreatureList.erase(it);
  972.         knownCreatureList.push_back(id);
  973.  
  974.         known = true;
  975.         return;
  976.     }
  977.  
  978.     // ok, he is unknown...
  979.     known = false;
  980.     // ... but not in future
  981.     knownCreatureList.push_back(id);
  982.     // too many known creatures?
  983.     if(knownCreatureList.size() > 250)
  984.     {
  985.         // lets try to remove one from the end of the list
  986.         Creature* c = NULL;
  987.         for(int32_t n = 0; n < 250; n++)
  988.         {
  989.             removedKnown = knownCreatureList.front();
  990.             if(!(c = g_game.getCreatureByID(removedKnown)) || !canSee(c))
  991.                 break;
  992.  
  993.             // this creature we can't remove, still in sight, so back to the end
  994.             knownCreatureList.pop_front();
  995.             knownCreatureList.push_back(removedKnown);
  996.         }
  997.  
  998.         // hopefully we found someone to remove :S, we got only 250 tries
  999.         // if not... lets kick some players with debug errors :)
  1000.         knownCreatureList.pop_front();
  1001.     }
  1002.     else // we can cache without problems :)
  1003.         removedKnown = 0;
  1004. }
  1005.  
  1006. bool ProtocolGame::canSee(const Creature* c) const
  1007. {
  1008.     return !c->isRemoved() && player->canSeeCreature(c) && canSee(c->getPosition());
  1009. }
  1010.  
  1011. bool ProtocolGame::canSee(const Position& pos) const
  1012. {
  1013.     return canSee(pos.x, pos.y, pos.z);
  1014. }
  1015.  
  1016. bool ProtocolGame::canSee(uint16_t x, uint16_t y, uint16_t z) const
  1017. {
  1018. #ifdef __DEBUG__
  1019.     if(z < 0 || z >= MAP_MAX_LAYERS)
  1020.         std::cout << "[Warning - ProtocolGame::canSee] Z-value is out of range!" << std::endl;
  1021. #endif
  1022.  
  1023.     const Position& myPos = player->getPosition();
  1024.     if(myPos.z <= 7)
  1025.     {
  1026.         //we are on ground level or above (7 -> 0), view is from 7 -> 0
  1027.         if(z > 7)
  1028.             return false;
  1029.     }
  1030.     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
  1031.         return false;
  1032.  
  1033.     //negative offset means that the action taken place is on a lower floor than ourself
  1034.     int32_t offsetz = myPos.z - z;
  1035.     return ((x >= myPos.x - 8 + offsetz) && (x <= myPos.x + 9 + offsetz) &&
  1036.         (y >= myPos.y - 6 + offsetz) && (y <= myPos.y + 7 + offsetz));
  1037. }
  1038.  
  1039. //********************** Parse methods *******************************//
  1040. void ProtocolGame::parseLogout(NetworkMessage& msg)
  1041. {
  1042.     Dispatcher::getInstance().addTask(createTask(boost::bind(&ProtocolGame::logout, this, true, false)));
  1043. }
  1044.  
  1045. void ProtocolGame::parseCreatePrivateChannel(NetworkMessage& msg)
  1046. {
  1047.     addGameTask(&Game::playerCreatePrivateChannel, player->getID());
  1048. }
  1049.  
  1050. void ProtocolGame::parseChannelInvite(NetworkMessage& msg)
  1051. {
  1052.     const std::string name = msg.GetString();
  1053.     addGameTask(&Game::playerChannelInvite, player->getID(), name);
  1054. }
  1055.  
  1056. void ProtocolGame::parseChannelExclude(NetworkMessage& msg)
  1057. {
  1058.     const std::string name = msg.GetString();
  1059.     addGameTask(&Game::playerChannelExclude, player->getID(), name);
  1060. }
  1061.  
  1062. void ProtocolGame::parseGetChannels(NetworkMessage& msg)
  1063. {
  1064.     addGameTask(&Game::playerRequestChannels, player->getID());
  1065. }
  1066.  
  1067. void ProtocolGame::parseOpenChannel(NetworkMessage& msg)
  1068. {
  1069.     uint16_t channelId = msg.GetU16();
  1070.     addGameTask(&Game::playerOpenChannel, player->getID(), channelId);
  1071. }
  1072.  
  1073. void ProtocolGame::parseCloseChannel(NetworkMessage& msg)
  1074. {
  1075.     uint16_t channelId = msg.GetU16();
  1076.     addGameTask(&Game::playerCloseChannel, player->getID(), channelId);
  1077. }
  1078.  
  1079. void ProtocolGame::parseOpenPriv(NetworkMessage& msg)
  1080. {
  1081.     const std::string receiver = msg.GetString();
  1082.     addGameTask(&Game::playerOpenPrivateChannel, player->getID(), receiver);
  1083. }
  1084.  
  1085. void ProtocolGame::parseProcessRuleViolation(NetworkMessage& msg)
  1086. {
  1087.     const std::string reporter = msg.GetString();
  1088.     addGameTask(&Game::playerProcessRuleViolation, player->getID(), reporter);
  1089. }
  1090.  
  1091. void ProtocolGame::parseCloseRuleViolation(NetworkMessage& msg)
  1092. {
  1093.     const std::string reporter = msg.GetString();
  1094.     addGameTask(&Game::playerCloseRuleViolation, player->getID(), reporter);
  1095. }
  1096.  
  1097. void ProtocolGame::parseCancelRuleViolation(NetworkMessage& msg)
  1098. {
  1099.     addGameTask(&Game::playerCancelRuleViolation, player->getID());
  1100. }
  1101.  
  1102. void ProtocolGame::parseCloseNpc(NetworkMessage& msg)
  1103. {
  1104.     addGameTask(&Game::playerCloseNpcChannel, player->getID());
  1105. }
  1106.  
  1107. void ProtocolGame::parseCancelMove(NetworkMessage& msg)
  1108. {
  1109.     addGameTask(&Game::playerCancelAttackAndFollow, player->getID());
  1110. }
  1111.  
  1112. void ProtocolGame::parseReceivePing(NetworkMessage& msg)
  1113. {
  1114.     addGameTask(&Game::playerReceivePing, player->getID());
  1115. }
  1116.  
  1117. void ProtocolGame::parseAutoWalk(NetworkMessage& msg)
  1118. {
  1119.     // first we get all directions...
  1120.     std::list<Direction> path;
  1121.     size_t dirCount = msg.GetByte();
  1122.     for(size_t i = 0; i < dirCount; ++i)
  1123.     {
  1124.         uint8_t rawDir = msg.GetByte();
  1125.         Direction dir = SOUTH;
  1126.         switch(rawDir)
  1127.         {
  1128.             case 1:
  1129.                 dir = EAST;
  1130.                 break;
  1131.             case 2:
  1132.                 dir = NORTHEAST;
  1133.                 break;
  1134.             case 3:
  1135.                 dir = NORTH;
  1136.                 break;
  1137.             case 4:
  1138.                 dir = NORTHWEST;
  1139.                 break;
  1140.             case 5:
  1141.                 dir = WEST;
  1142.                 break;
  1143.             case 6:
  1144.                 dir = SOUTHWEST;
  1145.                 break;
  1146.             case 7:
  1147.                 dir = SOUTH;
  1148.                 break;
  1149.             case 8:
  1150.                 dir = SOUTHEAST;
  1151.                 break;
  1152.             default:
  1153.                 continue;
  1154.         }
  1155.  
  1156.         path.push_back(dir);
  1157.     }
  1158.  
  1159.     addGameTask(&Game::playerAutoWalk, player->getID(), path);
  1160. }
  1161.  
  1162. void ProtocolGame::parseMove(NetworkMessage& msg, Direction dir)
  1163. {
  1164.     addGameTask(&Game::playerMove, player->getID(), dir);
  1165. }
  1166.  
  1167. void ProtocolGame::parseTurn(NetworkMessage& msg, Direction dir)
  1168. {
  1169.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), dir);
  1170. }
  1171.  
  1172. void ProtocolGame::parseRequestOutfit(NetworkMessage& msg)
  1173. {
  1174.     addGameTask(&Game::playerRequestOutfit, player->getID());
  1175. }
  1176.  
  1177. void ProtocolGame::parseSetOutfit(NetworkMessage& msg)
  1178. {
  1179.     Outfit_t newOutfit = player->defaultOutfit;
  1180.     if(g_config.getBool(ConfigManager::ALLOW_CHANGEOUTFIT))
  1181.         newOutfit.lookType = msg.GetU16();
  1182.     else
  1183.         msg.SkipBytes(2);
  1184.  
  1185.     if(g_config.getBool(ConfigManager::ALLOW_CHANGECOLORS))
  1186.     {
  1187.         newOutfit.lookHead = msg.GetByte();
  1188.         newOutfit.lookBody = msg.GetByte();
  1189.         newOutfit.lookLegs = msg.GetByte();
  1190.         newOutfit.lookFeet = msg.GetByte();
  1191.     }
  1192.     else
  1193.         msg.SkipBytes(4);
  1194.  
  1195.     if(g_config.getBool(ConfigManager::ALLOW_CHANGEADDONS))
  1196.         newOutfit.lookAddons = msg.GetByte();
  1197.     else
  1198.         msg.SkipBytes(1);
  1199.  
  1200.     addGameTask(&Game::playerChangeOutfit, player->getID(), newOutfit);
  1201. }
  1202.  
  1203. void ProtocolGame::parseUseItem(NetworkMessage& msg)
  1204. {
  1205.     Position pos = msg.GetPosition();
  1206.     uint16_t spriteId = msg.GetSpriteId();
  1207.     int16_t stackpos = msg.GetByte();
  1208.     uint8_t index = msg.GetByte();
  1209.     bool isHotkey = (pos.x == 0xFFFF && !pos.y && !pos.z);
  1210.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseItem, player->getID(), pos, stackpos, index, spriteId, isHotkey);
  1211. }
  1212.  
  1213. void ProtocolGame::parseUseItemEx(NetworkMessage& msg)
  1214. {
  1215.     Position fromPos = msg.GetPosition();
  1216.     uint16_t fromSpriteId = msg.GetSpriteId();
  1217.     int16_t fromStackpos = msg.GetByte();
  1218.     Position toPos = msg.GetPosition();
  1219.     uint16_t toSpriteId = msg.GetU16();
  1220.     int16_t toStackpos = msg.GetByte();
  1221.     bool isHotkey = (fromPos.x == 0xFFFF && !fromPos.y && !fromPos.z);
  1222.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseItemEx, player->getID(),
  1223.         fromPos, fromStackpos, fromSpriteId, toPos, toStackpos, toSpriteId, isHotkey);
  1224. }
  1225.  
  1226. void ProtocolGame::parseBattleWindow(NetworkMessage& msg)
  1227. {
  1228.     Position fromPos = msg.GetPosition();
  1229.     uint16_t spriteId = msg.GetSpriteId();
  1230.     int16_t fromStackpos = msg.GetByte();
  1231.     uint32_t creatureId = msg.GetU32();
  1232.     bool isHotkey = (fromPos.x == 0xFFFF && !fromPos.y && !fromPos.z);
  1233.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseBattleWindow, player->getID(), fromPos, fromStackpos, creatureId, spriteId, isHotkey);
  1234. }
  1235.  
  1236. void ProtocolGame::parseCloseContainer(NetworkMessage& msg)
  1237. {
  1238.     uint8_t cid = msg.GetByte();
  1239.     addGameTask(&Game::playerCloseContainer, player->getID(), cid);
  1240. }
  1241.  
  1242. void ProtocolGame::parseUpArrowContainer(NetworkMessage& msg)
  1243. {
  1244.     uint8_t cid = msg.GetByte();
  1245.     addGameTask(&Game::playerMoveUpContainer, player->getID(), cid);
  1246. }
  1247.  
  1248. void ProtocolGame::parseUpdateTile(NetworkMessage& msg)
  1249. {
  1250.     Position pos = msg.GetPosition();
  1251.     //addGameTask(&Game::playerUpdateTile, player->getID(), pos);
  1252. }
  1253.  
  1254. void ProtocolGame::parseUpdateContainer(NetworkMessage& msg)
  1255. {
  1256.     uint8_t cid = msg.GetByte();
  1257.     addGameTask(&Game::playerUpdateContainer, player->getID(), cid);
  1258. }
  1259.  
  1260. void ProtocolGame::parseThrow(NetworkMessage& msg)
  1261. {
  1262.     Position fromPos = msg.GetPosition();
  1263.     uint16_t spriteId = msg.GetSpriteId();
  1264.     int16_t fromStackpos = msg.GetByte();
  1265.     Position toPos = msg.GetPosition();
  1266.     uint8_t count = msg.GetByte();
  1267.     if(toPos != fromPos)
  1268.         addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerMoveThing,
  1269.             player->getID(), fromPos, spriteId, fromStackpos, toPos, count);
  1270. }
  1271.  
  1272. void ProtocolGame::parseLookAt(NetworkMessage& msg)
  1273. {
  1274.     Position pos = msg.GetPosition();
  1275.     uint16_t spriteId = msg.GetSpriteId();
  1276.     int16_t stackpos = msg.GetByte();
  1277.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookAt, player->getID(), pos, spriteId, stackpos);
  1278. }
  1279.  
  1280. void ProtocolGame::parseSay(NetworkMessage& msg)
  1281. {
  1282.     std::string receiver;
  1283.     uint16_t channelId = 0;
  1284.  
  1285.     SpeakClasses type = (SpeakClasses)msg.GetByte();
  1286.     switch(type)
  1287.     {
  1288.         case SPEAK_PRIVATE:
  1289.         case SPEAK_PRIVATE_RED:
  1290.         case SPEAK_RVR_ANSWER:
  1291.             receiver = msg.GetString();
  1292.             break;
  1293.  
  1294.         case SPEAK_CHANNEL_Y:
  1295.         case SPEAK_CHANNEL_RN:
  1296.         case SPEAK_CHANNEL_RA:
  1297.             channelId = msg.GetU16();
  1298.             break;
  1299.  
  1300.         default:
  1301.             break;
  1302.     }
  1303.  
  1304.     const std::string text = msg.GetString();
  1305.     if(text.length() > 255) //client limit
  1306.     {
  1307.         std::stringstream s;
  1308.         s << text.length();
  1309.  
  1310.         Logger::getInstance()->eFile("bots/" + player->getName() + ".log", "Attempt to send message with size " + s.str() + " - client is limited to 255 characters.", true);
  1311.         return;
  1312.     }
  1313.  
  1314.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerSay, player->getID(), channelId, type, receiver, text);
  1315. }
  1316.  
  1317. void ProtocolGame::parseFightModes(NetworkMessage& msg)
  1318. {
  1319.     uint8_t rawFightMode = msg.GetByte(); //1 - offensive, 2 - balanced, 3 - defensive
  1320.     uint8_t rawChaseMode = msg.GetByte(); //0 - stand while fightning, 1 - chase opponent
  1321.     uint8_t rawSecureMode = msg.GetByte(); //0 - can't attack unmarked, 1 - can attack unmarked
  1322.  
  1323.     chaseMode_t chaseMode = CHASEMODE_STANDSTILL;
  1324.     if(rawChaseMode == 1)
  1325.         chaseMode = CHASEMODE_FOLLOW;
  1326.  
  1327.     fightMode_t fightMode = FIGHTMODE_ATTACK;
  1328.     if(rawFightMode == 2)
  1329.         fightMode = FIGHTMODE_BALANCED;
  1330.     else if(rawFightMode == 3)
  1331.         fightMode = FIGHTMODE_DEFENSE;
  1332.  
  1333.     secureMode_t secureMode = SECUREMODE_OFF;
  1334.     if(rawSecureMode == 1)
  1335.         secureMode = SECUREMODE_ON;
  1336.  
  1337.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerSetFightModes, player->getID(), fightMode, chaseMode, secureMode);
  1338. }
  1339.  
  1340. void ProtocolGame::parseAttack(NetworkMessage& msg)
  1341. {
  1342.     uint32_t creatureId = msg.GetU32();
  1343.     addGameTask(&Game::playerSetAttackedCreature, player->getID(), creatureId);
  1344. }
  1345.  
  1346. void ProtocolGame::parseFollow(NetworkMessage& msg)
  1347. {
  1348.     uint32_t creatureId = msg.GetU32();
  1349.     addGameTask(&Game::playerFollowCreature, player->getID(), creatureId);
  1350. }
  1351.  
  1352. void ProtocolGame::parseTextWindow(NetworkMessage& msg)
  1353. {
  1354.     uint32_t windowTextId = msg.GetU32();
  1355.     const std::string newText = msg.GetString();
  1356.     addGameTask(&Game::playerWriteItem, player->getID(), windowTextId, newText);
  1357. }
  1358.  
  1359. void ProtocolGame::parseHouseWindow(NetworkMessage &msg)
  1360. {
  1361.     uint8_t doorId = msg.GetByte();
  1362.     uint32_t id = msg.GetU32();
  1363.     const std::string text = msg.GetString();
  1364.     addGameTask(&Game::playerUpdateHouseWindow, player->getID(), doorId, id, text);
  1365. }
  1366.  
  1367. void ProtocolGame::parseLookInShop(NetworkMessage &msg)
  1368. {
  1369.     uint16_t id = msg.GetU16();
  1370.     uint16_t count = msg.GetByte();
  1371.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookInShop, player->getID(), id, count);
  1372. }
  1373.  
  1374. void ProtocolGame::parsePlayerPurchase(NetworkMessage &msg)
  1375. {
  1376.     uint16_t id = msg.GetU16();
  1377.     uint16_t count = msg.GetByte();
  1378.     uint16_t amount = msg.GetByte();
  1379.     bool ignoreCap = msg.GetByte();
  1380.     bool inBackpacks = msg.GetByte();
  1381.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerPurchaseItem, player->getID(), id, count, amount, ignoreCap, inBackpacks);
  1382. }
  1383.  
  1384. void ProtocolGame::parsePlayerSale(NetworkMessage &msg)
  1385. {
  1386.     uint16_t id = msg.GetU16();
  1387.     uint16_t count = msg.GetByte();
  1388.     uint16_t amount = msg.GetByte();
  1389.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerSellItem, player->getID(), id, count, amount);
  1390. }
  1391.  
  1392. void ProtocolGame::parseCloseShop(NetworkMessage &msg)
  1393. {
  1394.     addGameTask(&Game::playerCloseShop, player->getID());
  1395. }
  1396.  
  1397. void ProtocolGame::parseRequestTrade(NetworkMessage& msg)
  1398. {
  1399.     Position pos = msg.GetPosition();
  1400.     uint16_t spriteId = msg.GetSpriteId();
  1401.     int16_t stackpos = msg.GetByte();
  1402.     uint32_t playerId = msg.GetU32();
  1403.     addGameTask(&Game::playerRequestTrade, player->getID(), pos, stackpos, playerId, spriteId);
  1404. }
  1405.  
  1406. void ProtocolGame::parseAcceptTrade(NetworkMessage& msg)
  1407. {
  1408.     addGameTask(&Game::playerAcceptTrade, player->getID());
  1409. }
  1410.  
  1411. void ProtocolGame::parseLookInTrade(NetworkMessage& msg)
  1412. {
  1413.     bool counter = msg.GetByte();
  1414.     int32_t index = msg.GetByte();
  1415.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookInTrade, player->getID(), counter, index);
  1416. }
  1417.  
  1418. void ProtocolGame::parseCloseTrade()
  1419. {
  1420.     addGameTask(&Game::playerCloseTrade, player->getID());
  1421. }
  1422.  
  1423. void ProtocolGame::parseAddVip(NetworkMessage& msg)
  1424. {
  1425.     const std::string name = msg.GetString();
  1426.     if(name.size() > 32)
  1427.         return;
  1428.  
  1429.     addGameTask(&Game::playerRequestAddVip, player->getID(), name);
  1430. }
  1431.  
  1432. void ProtocolGame::parseRemoveVip(NetworkMessage& msg)
  1433. {
  1434.     uint32_t guid = msg.GetU32();
  1435.     addGameTask(&Game::playerRequestRemoveVip, player->getID(), guid);
  1436. }
  1437.  
  1438. void ProtocolGame::parseRotateItem(NetworkMessage& msg)
  1439. {
  1440.     Position pos = msg.GetPosition();
  1441.     uint16_t spriteId = msg.GetSpriteId();
  1442.     int16_t stackpos = msg.GetByte();
  1443.     addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerRotateItem, player->getID(), pos, stackpos, spriteId);
  1444. }
  1445.  
  1446. void ProtocolGame::parseDebugAssert(NetworkMessage& msg)
  1447. {
  1448.     if(m_debugAssertSent)
  1449.         return;
  1450.  
  1451.     std::stringstream s;
  1452.     s << "----- " << formatDate() << " - " << player->getName() << " (" << convertIPAddress(getIP())
  1453.         << ") -----" << std::endl << msg.GetString() << std::endl << msg.GetString()
  1454.         << std::endl << msg.GetString() << std::endl << msg.GetString()
  1455.         << std::endl << std::endl;
  1456.  
  1457.     m_debugAssertSent = true;
  1458.     Logger::getInstance()->iFile(LOGFILE_CLIENT_ASSERTION, s.str(), false);
  1459. }
  1460.  
  1461. void ProtocolGame::parseBugReport(NetworkMessage& msg)
  1462. {
  1463.     std::string comment = msg.GetString();
  1464.     addGameTask(&Game::playerReportBug, player->getID(), comment);
  1465. }
  1466.  
  1467. void ProtocolGame::parseInviteToParty(NetworkMessage& msg)
  1468. {
  1469.     uint32_t targetId = msg.GetU32();
  1470.     addGameTask(&Game::playerInviteToParty, player->getID(), targetId);
  1471. }
  1472.  
  1473. void ProtocolGame::parseJoinParty(NetworkMessage& msg)
  1474. {
  1475.     uint32_t targetId = msg.GetU32();
  1476.     addGameTask(&Game::playerJoinParty, player->getID(), targetId);
  1477. }
  1478.  
  1479. void ProtocolGame::parseRevokePartyInvite(NetworkMessage& msg)
  1480. {
  1481.     uint32_t targetId = msg.GetU32();
  1482.     addGameTask(&Game::playerRevokePartyInvitation, player->getID(), targetId);
  1483. }
  1484.  
  1485. void ProtocolGame::parsePassPartyLeadership(NetworkMessage& msg)
  1486. {
  1487.     uint32_t targetId = msg.GetU32();
  1488.     addGameTask(&Game::playerPassPartyLeadership, player->getID(), targetId);
  1489. }
  1490.  
  1491. void ProtocolGame::parseLeaveParty(NetworkMessage& msg)
  1492. {
  1493.     addGameTask(&Game::playerLeaveParty, player->getID());
  1494. }
  1495.  
  1496. void ProtocolGame::parseSharePartyExperience(NetworkMessage& msg)
  1497. {
  1498.     bool activate = msg.GetByte();
  1499.     uint8_t unknown = msg.GetByte(); //TODO: find out what is this byte
  1500.     addGameTask(&Game::playerSharePartyExperience, player->getID(), activate, unknown);
  1501. }
  1502.  
  1503. void ProtocolGame::parseQuests(NetworkMessage& msg)
  1504. {
  1505.     addGameTask(&Game::playerQuests, player->getID());
  1506. }
  1507.  
  1508. void ProtocolGame::parseQuestInfo(NetworkMessage& msg)
  1509. {
  1510.     uint16_t questId = msg.GetU16();
  1511.     addGameTask(&Game::playerQuestInfo, player->getID(), questId);
  1512. }
  1513.  
  1514. void ProtocolGame::parseViolationWindow(NetworkMessage& msg)
  1515. {
  1516.     std::string target = msg.GetString();
  1517.     uint8_t reason = msg.GetByte();
  1518.     ViolationAction_t action = (ViolationAction_t)msg.GetByte();
  1519.     std::string comment = msg.GetString();
  1520.     std::string statement = msg.GetString();
  1521.     uint32_t statementId = (uint32_t)msg.GetU16();
  1522.     bool ipBanishment = msg.GetByte();
  1523.     addGameTask(&Game::playerViolationWindow, player->getID(), target, reason, action, comment, statement, statementId, ipBanishment);
  1524. }
  1525.  
  1526. //********************** Send methods *******************************//
  1527. /*void ProtocolGame::sendCountdowns(const std::string& name, uint32_t cd)
  1528. {
  1529.     NetworkMessage_ptr msg = getOutputBuffer();
  1530.     if(msg)
  1531.     {
  1532.         TRACK_MESSAGE(msg);
  1533.         msg->AddByte(0xDE);
  1534.         msg->AddString(name);
  1535.         msg->AddU32(cd);
  1536.     }
  1537. }*/
  1538.  
  1539. void ProtocolGame::sendOpenPrivateChannel(const std::string& receiver)
  1540. {
  1541.     NetworkMessage_ptr msg = getOutputBuffer();
  1542.     if(msg)
  1543.     {
  1544.         TRACK_MESSAGE(msg);
  1545.         msg->AddByte(0xAD);
  1546.         msg->AddString(receiver);
  1547.     }
  1548. }
  1549.  
  1550. void ProtocolGame::sendCreatureOutfit(const Creature* creature, const Outfit_t& outfit)
  1551. {
  1552.     if(!canSee(creature))
  1553.         return;
  1554.  
  1555.     NetworkMessage_ptr msg = getOutputBuffer();
  1556.     if(msg)
  1557.     {
  1558.         TRACK_MESSAGE(msg);
  1559.         msg->AddByte(0x8E);
  1560.         msg->AddU32(creature->getID());
  1561.         AddCreatureOutfit(msg, creature, outfit);
  1562.     }
  1563. }
  1564.  
  1565. void ProtocolGame::sendCreatureLight(const Creature* creature)
  1566. {
  1567.     if(!canSee(creature))
  1568.         return;
  1569.  
  1570.     NetworkMessage_ptr msg = getOutputBuffer();
  1571.     if(msg)
  1572.     {
  1573.         TRACK_MESSAGE(msg);
  1574.         AddCreatureLight(msg, creature);
  1575.     }
  1576. }
  1577.  
  1578. void ProtocolGame::sendWorldLight(const LightInfo& lightInfo)
  1579. {
  1580.     NetworkMessage_ptr msg = getOutputBuffer();
  1581.     if(msg)
  1582.     {
  1583.         TRACK_MESSAGE(msg);
  1584.         AddWorldLight(msg, lightInfo);
  1585.     }
  1586. }
  1587.  
  1588. void ProtocolGame::sendCreatureUpdate(const Creature* creature)
  1589. {
  1590.     if(!canSee(creature))
  1591.         return;
  1592.  
  1593.     uint32_t stackpos = creature->getTile()->getClientIndexOfThing(player, creature);
  1594.     if(stackpos >= 10)
  1595.         return;
  1596.  
  1597.     NetworkMessage_ptr msg = getOutputBuffer();
  1598.     if(msg)
  1599.     {
  1600.         TRACK_MESSAGE(msg);
  1601.         std::list<uint32_t>::iterator it = std::find(knownCreatureList.begin(), knownCreatureList.end(), creature->getID());
  1602.         if(it != knownCreatureList.end())
  1603.         {
  1604.             RemoveTileItem(msg, creature->getPosition(), stackpos);
  1605.             msg->AddByte(0x6A);
  1606.             msg->AddPosition(creature->getPosition());
  1607.             msg->AddByte(stackpos);
  1608.             AddCreature(msg, creature, false, creature->getID());
  1609.         }
  1610.         else
  1611.             AddTileCreature(msg, creature->getPosition(), stackpos, creature);
  1612.     }
  1613. }
  1614.  
  1615. void ProtocolGame::sendCreatureShield(const Creature* creature)
  1616. {
  1617.     if(!canSee(creature))
  1618.         return;
  1619.  
  1620.     NetworkMessage_ptr msg = getOutputBuffer();
  1621.     if(msg)
  1622.     {
  1623.         TRACK_MESSAGE(msg);
  1624.         msg->AddByte(0x91);
  1625.         msg->AddU32(creature->getID());
  1626.         msg->AddByte(player->getPartyShield(creature));
  1627.     }
  1628. }
  1629.  
  1630. void ProtocolGame::sendCreatureSkull(const Creature* creature)
  1631. {
  1632.     if(!canSee(creature))
  1633.         return;
  1634.  
  1635.     NetworkMessage_ptr msg = getOutputBuffer();
  1636.     if(msg)
  1637.     {
  1638.         TRACK_MESSAGE(msg);
  1639.         msg->AddByte(0x90);
  1640.         msg->AddU32(creature->getID());
  1641.         msg->AddByte(player->getSkullClient(creature));
  1642.     }
  1643. }
  1644.  
  1645. void ProtocolGame::sendCreatureSquare(const Creature* creature, SquareColor_t color)
  1646. {
  1647.     if(!canSee(creature))
  1648.         return;
  1649.  
  1650.     NetworkMessage_ptr msg = getOutputBuffer();
  1651.     if(msg)
  1652.     {
  1653.         TRACK_MESSAGE(msg);
  1654.         msg->AddByte(0x86);
  1655.         msg->AddU32(creature->getID());
  1656.         msg->AddByte((uint8_t)color);
  1657.     }
  1658. }
  1659.  
  1660. void ProtocolGame::sendTutorial(uint8_t tutorialId)
  1661. {
  1662.     NetworkMessage_ptr msg = getOutputBuffer();
  1663.     if(msg)
  1664.     {
  1665.         TRACK_MESSAGE(msg);
  1666.         msg->AddByte(0xDC);
  1667.         msg->AddByte(tutorialId);
  1668.     }
  1669. }
  1670.  
  1671. void ProtocolGame::sendAddMarker(const Position& pos, MapMarks_t markType, const std::string& desc)
  1672. {
  1673.     NetworkMessage_ptr msg = getOutputBuffer();
  1674.     if(msg)
  1675.     {
  1676.         TRACK_MESSAGE(msg);
  1677.         msg->AddByte(0xDD);
  1678.         msg->AddPosition(pos);
  1679.         msg->AddByte(markType);
  1680.         msg->AddString(desc);
  1681.     }
  1682. }
  1683.  
  1684. void ProtocolGame::sendReLoginWindow()
  1685. {
  1686.     NetworkMessage_ptr msg = getOutputBuffer();
  1687.     if(msg)
  1688.     {
  1689.         TRACK_MESSAGE(msg);
  1690.         msg->AddByte(0x28);
  1691.     }
  1692. }
  1693.  
  1694. void ProtocolGame::sendStats()
  1695. {
  1696.     NetworkMessage_ptr msg = getOutputBuffer();
  1697.     if(msg)
  1698.     {
  1699.         TRACK_MESSAGE(msg);
  1700.         AddPlayerStats(msg);
  1701.     }
  1702. }
  1703.  
  1704. void ProtocolGame::sendTextMessage(MessageClasses mClass, const std::string& message)
  1705. {
  1706.     NetworkMessage_ptr msg = getOutputBuffer();
  1707.     if(msg)
  1708.     {
  1709.         TRACK_MESSAGE(msg);
  1710.         AddTextMessage(msg, mClass, message);
  1711.     }
  1712. }
  1713.  
  1714. void ProtocolGame::sendClosePrivate(uint16_t channelId)
  1715. {
  1716.     NetworkMessage_ptr msg = getOutputBuffer();
  1717.     if(msg)
  1718.     {
  1719.         TRACK_MESSAGE(msg);
  1720.         if(channelId == CHANNEL_GUILD || channelId == CHANNEL_PARTY)
  1721.             g_chat.removeUserFromChannel(player, channelId);
  1722.  
  1723.         msg->AddByte(0xB3);
  1724.         msg->AddU16(channelId);
  1725.     }
  1726. }
  1727.  
  1728. void ProtocolGame::sendCreatePrivateChannel(uint16_t channelId, const std::string& channelName)
  1729. {
  1730.     NetworkMessage_ptr msg = getOutputBuffer();
  1731.     if(msg)
  1732.     {
  1733.         TRACK_MESSAGE(msg);
  1734.         msg->AddByte(0xB2);
  1735.         msg->AddU16(channelId);
  1736.         msg->AddString(channelName);
  1737.     }
  1738. }
  1739.  
  1740. void ProtocolGame::sendChannelsDialog()
  1741. {
  1742.     NetworkMessage_ptr msg = getOutputBuffer();
  1743.     if(msg)
  1744.     {
  1745.         TRACK_MESSAGE(msg);
  1746.         msg->AddByte(0xAB);
  1747.         ChannelList list = g_chat.getChannelList(player);
  1748.         msg->AddByte(list.size());
  1749.         for(ChannelList::iterator it = list.begin(); it != list.end(); ++it)
  1750.         {
  1751.             if(ChatChannel* channel = (*it))
  1752.             {
  1753.                 msg->AddU16(channel->getId());
  1754.                 msg->AddString(channel->getName());
  1755.             }
  1756.         }
  1757.     }
  1758. }
  1759.  
  1760. void ProtocolGame::sendChannel(uint16_t channelId, const std::string& channelName)
  1761. {
  1762.     NetworkMessage_ptr msg = getOutputBuffer();
  1763.     if(msg)
  1764.     {
  1765.         TRACK_MESSAGE(msg);
  1766.         msg->AddByte(0xAC);
  1767.         msg->AddU16(channelId);
  1768.         msg->AddString(channelName);
  1769.     }
  1770. }
  1771.  
  1772. void ProtocolGame::sendRuleViolationsChannel(uint16_t channelId)
  1773. {
  1774.     NetworkMessage_ptr msg = getOutputBuffer();
  1775.     if(msg)
  1776.     {
  1777.         TRACK_MESSAGE(msg);
  1778.         msg->AddByte(0xAE);
  1779.         msg->AddU16(channelId);
  1780.         for(RuleViolationsMap::const_iterator it = g_game.getRuleViolations().begin(); it != g_game.getRuleViolations().end(); ++it)
  1781.         {
  1782.             RuleViolation& rvr = *it->second;
  1783.             if(rvr.isOpen && rvr.reporter)
  1784.                 AddCreatureSpeak(msg, rvr.reporter, SPEAK_RVR_CHANNEL, rvr.text, channelId, rvr.time);
  1785.         }
  1786.     }
  1787. }
  1788.  
  1789. void ProtocolGame::sendRemoveReport(const std::string& name)
  1790. {
  1791.     NetworkMessage_ptr msg = getOutputBuffer();
  1792.     if(msg)
  1793.     {
  1794.         TRACK_MESSAGE(msg);
  1795.         msg->AddByte(0xAF);
  1796.         msg->AddString(name);
  1797.     }
  1798. }
  1799.  
  1800. void ProtocolGame::sendRuleViolationCancel(const std::string& name)
  1801. {
  1802.     NetworkMessage_ptr msg = getOutputBuffer();
  1803.     if(msg)
  1804.     {
  1805.         TRACK_MESSAGE(msg);
  1806.         msg->AddByte(0xB0);
  1807.         msg->AddString(name);
  1808.     }
  1809. }
  1810.  
  1811. void ProtocolGame::sendLockRuleViolation()
  1812. {
  1813.     NetworkMessage_ptr msg = getOutputBuffer();
  1814.     if(msg)
  1815.     {
  1816.         TRACK_MESSAGE(msg);
  1817.         msg->AddByte(0xB1);
  1818.     }
  1819. }
  1820.  
  1821. void ProtocolGame::sendIcons(int32_t icons)
  1822. {
  1823.     NetworkMessage_ptr msg = getOutputBuffer();
  1824.     if(msg)
  1825.     {
  1826.         TRACK_MESSAGE(msg);
  1827.         msg->AddByte(0xA2);
  1828.         msg->AddU16(icons);
  1829.     }
  1830. }
  1831.  
  1832. void ProtocolGame::sendContainer(uint32_t cid, const Container* container, bool hasParent)
  1833. {
  1834.     NetworkMessage_ptr msg = getOutputBuffer();
  1835.     if(msg)
  1836.     {
  1837.         TRACK_MESSAGE(msg);
  1838.         msg->AddByte(0x6E);
  1839.         msg->AddByte(cid);
  1840.  
  1841.         msg->AddItemId(container);
  1842.         msg->AddString(container->getName());
  1843.         msg->AddByte(container->capacity());
  1844.  
  1845.         msg->AddByte(hasParent ? 0x01 : 0x00);
  1846.         msg->AddByte(std::min(container->size(), (uint32_t)255));
  1847.  
  1848.         ItemList::const_iterator cit = container->getItems();
  1849.         for(uint32_t i = 0; cit != container->getEnd() && i < 255; ++cit, ++i)
  1850.             msg->AddItem(*cit);
  1851.     }
  1852. }
  1853.  
  1854. void ProtocolGame::sendShop(const ShopInfoList& shop)
  1855. {
  1856.     NetworkMessage_ptr msg = getOutputBuffer();
  1857.     if(msg)
  1858.     {
  1859.         TRACK_MESSAGE(msg);
  1860.         msg->AddByte(0x7A);
  1861.         msg->AddByte(std::min(shop.size(), (size_t)255));
  1862.  
  1863.         ShopInfoList::const_iterator it = shop.begin();
  1864.         for(uint32_t i = 0; it != shop.end() && i < 255; ++it, ++i)
  1865.             AddShopItem(msg, (*it));
  1866.     }
  1867. }
  1868.  
  1869. void ProtocolGame::sendCloseShop()
  1870. {
  1871.     NetworkMessage_ptr msg = getOutputBuffer();
  1872.     if(msg)
  1873.     {
  1874.         TRACK_MESSAGE(msg);
  1875.         msg->AddByte(0x7C);
  1876.     }
  1877. }
  1878.  
  1879. void ProtocolGame::sendGoods(const ShopInfoList& shop)
  1880. {
  1881.     NetworkMessage_ptr msg = getOutputBuffer();
  1882.     if(msg)
  1883.     {
  1884.         TRACK_MESSAGE(msg);
  1885.         msg->AddByte(0x7B);
  1886.         msg->AddU32(g_game.getMoney(player));
  1887.  
  1888.         std::map<uint32_t, uint32_t> goodsMap;
  1889.         if(shop.size() >= 5)
  1890.         {
  1891.             for(ShopInfoList::const_iterator sit = shop.begin(); sit != shop.end(); ++sit)
  1892.             {
  1893.                 if(sit->sellPrice < 0)
  1894.                     continue;
  1895.  
  1896.                 int8_t subType = -1;
  1897.                 if(sit->subType)
  1898.                 {
  1899.                     const ItemType& it = Item::items[sit->itemId];
  1900.                     if(it.hasSubType() && !it.stackable)
  1901.                         subType = sit->subType;
  1902.                 }
  1903.  
  1904.                 uint32_t count = player->__getItemTypeCount(sit->itemId, subType);
  1905.                 if(count > 0)
  1906.                     goodsMap[sit->itemId] = count;
  1907.             }
  1908.         }
  1909.         else
  1910.         {
  1911.             std::map<uint32_t, uint32_t> tmpMap;
  1912.             player->__getAllItemTypeCount(tmpMap);
  1913.             for(ShopInfoList::const_iterator sit = shop.begin(); sit != shop.end(); ++sit)
  1914.             {
  1915.                 if(sit->sellPrice < 0)
  1916.                     continue;
  1917.  
  1918.                 int8_t subType = -1;
  1919.                 if(sit->subType)
  1920.                 {
  1921.                     const ItemType& it = Item::items[sit->itemId];
  1922.                     if(it.hasSubType() && !it.stackable)
  1923.                         subType = sit->subType;
  1924.                 }
  1925.  
  1926.                 if(subType != -1)
  1927.                 {
  1928.                     uint32_t count = player->__getItemTypeCount(sit->itemId, subType);
  1929.                     if(count > 0)
  1930.                         goodsMap[sit->itemId] = count;
  1931.                 }
  1932.                 else
  1933.                     goodsMap[sit->itemId] = tmpMap[sit->itemId];
  1934.             }
  1935.         }
  1936.  
  1937.         msg->AddByte(std::min(goodsMap.size(), (size_t)255));
  1938.         std::map<uint32_t, uint32_t>::const_iterator it = goodsMap.begin();
  1939.         for(uint32_t i = 0; it != goodsMap.end() && i < 255; ++it, ++i)
  1940.         {
  1941.             msg->AddItemId(it->first);
  1942.             msg->AddByte(std::min(it->second, (uint32_t)255));
  1943.         }
  1944.     }
  1945. }
  1946.  
  1947. void ProtocolGame::sendTradeItemRequest(const Player* player, const Item* item, bool ack)
  1948. {
  1949.     NetworkMessage_ptr msg = getOutputBuffer();
  1950.     if(msg)
  1951.     {
  1952.         TRACK_MESSAGE(msg);
  1953.         if(ack)
  1954.             msg->AddByte(0x7D);
  1955.         else
  1956.             msg->AddByte(0x7E);
  1957.  
  1958.         msg->AddString(player->getName());
  1959.         if(const Container* container = item->getContainer())
  1960.         {
  1961.             msg->AddByte(container->getItemHoldingCount() + 1);
  1962.             msg->AddItem(item);
  1963.             for(ContainerIterator it = container->begin(); it != container->end(); ++it)
  1964.                 msg->AddItem(*it);
  1965.         }
  1966.         else
  1967.         {
  1968.             msg->AddByte(1);
  1969.             msg->AddItem(item);
  1970.         }
  1971.     }
  1972. }
  1973.  
  1974. void ProtocolGame::sendCloseTrade()
  1975. {
  1976.     NetworkMessage_ptr msg = getOutputBuffer();
  1977.     if(msg)
  1978.     {
  1979.         TRACK_MESSAGE(msg);
  1980.         msg->AddByte(0x7F);
  1981.     }
  1982. }
  1983.  
  1984. void ProtocolGame::sendCloseContainer(uint32_t cid)
  1985. {
  1986.     NetworkMessage_ptr msg = getOutputBuffer();
  1987.     if(msg)
  1988.     {
  1989.         TRACK_MESSAGE(msg);
  1990.         msg->AddByte(0x6F);
  1991.         msg->AddByte(cid);
  1992.     }
  1993. }
  1994.  
  1995. void ProtocolGame::sendCreatureTurn(const Creature* creature, int16_t stackpos)
  1996. {
  1997.     if(stackpos >= 10 || !canSee(creature))
  1998.         return;
  1999.  
  2000.     NetworkMessage_ptr msg = getOutputBuffer();
  2001.     if(msg)
  2002.     {
  2003.         TRACK_MESSAGE(msg);
  2004.         msg->AddByte(0x6B);
  2005.         msg->AddPosition(creature->getPosition());
  2006.         msg->AddByte(stackpos);
  2007.         msg->AddU16(0x63); /*99*/
  2008.         msg->AddU32(creature->getID());
  2009.         msg->AddByte(creature->getDirection());
  2010.     }
  2011. }
  2012.  
  2013. void ProtocolGame::sendCreatureSay(const Creature* creature, SpeakClasses type, const std::string& text, Position* pos/* = NULL*/)
  2014. {
  2015.     NetworkMessage_ptr msg = getOutputBuffer();
  2016.     if(msg)
  2017.     {
  2018.         TRACK_MESSAGE(msg);
  2019.         AddCreatureSpeak(msg, creature, type, text, 0, 0, pos);
  2020.     }
  2021. }
  2022.  
  2023. void ProtocolGame::sendToChannel(const Creature* creature, SpeakClasses type, const std::string& text, uint16_t channelId, uint32_t time /*= 0*/)
  2024. {
  2025.     NetworkMessage_ptr msg = getOutputBuffer();
  2026.     if(msg)
  2027.     {
  2028.         TRACK_MESSAGE(msg);
  2029.         AddCreatureSpeak(msg, creature, type, text, channelId, time);
  2030.     }
  2031. }
  2032.  
  2033. void ProtocolGame::sendCancel(const std::string& message)
  2034. {
  2035.     NetworkMessage_ptr msg = getOutputBuffer();
  2036.     if(msg)
  2037.     {
  2038.         TRACK_MESSAGE(msg);
  2039.         AddTextMessage(msg, MSG_STATUS_SMALL, message);
  2040.     }
  2041. }
  2042.  
  2043. void ProtocolGame::sendCancelTarget()
  2044. {
  2045.     NetworkMessage_ptr msg = getOutputBuffer();
  2046.     if(msg)
  2047.     {
  2048.         TRACK_MESSAGE(msg);
  2049.         msg->AddByte(0xA3);
  2050.     }
  2051. }
  2052.  
  2053. void ProtocolGame::sendChangeSpeed(const Creature* creature, uint32_t speed)
  2054. {
  2055.     if(!canSee(creature))
  2056.         return;
  2057.  
  2058.     NetworkMessage_ptr msg = getOutputBuffer();
  2059.     if(msg)
  2060.     {
  2061.         TRACK_MESSAGE(msg);
  2062.         msg->AddByte(0x8F);
  2063.         msg->AddU32(creature->getID());
  2064.         msg->AddU16(speed);
  2065.     }
  2066. }
  2067.  
  2068. void ProtocolGame::sendCancelWalk()
  2069. {
  2070.     NetworkMessage_ptr msg = getOutputBuffer();
  2071.     if(msg)
  2072.     {
  2073.         TRACK_MESSAGE(msg);
  2074.         msg->AddByte(0xB5);
  2075.         msg->AddByte(player->getDirection());
  2076.     }
  2077. }
  2078.  
  2079. void ProtocolGame::sendSkills()
  2080. {
  2081.     NetworkMessage_ptr msg = getOutputBuffer();
  2082.     if(msg)
  2083.     {
  2084.         TRACK_MESSAGE(msg);
  2085.         AddPlayerSkills(msg);
  2086.     }
  2087. }
  2088.  
  2089. void ProtocolGame::sendPing()
  2090. {
  2091.     NetworkMessage_ptr msg = getOutputBuffer();
  2092.     if(msg)
  2093.     {
  2094.         TRACK_MESSAGE(msg);
  2095.         msg->AddByte(0x1E);
  2096.     }
  2097. }
  2098.  
  2099. void ProtocolGame::sendDistanceShoot(const Position& from, const Position& to, uint8_t type)
  2100. {
  2101.     if(type > SHOOT_EFFECT_LAST || (!canSee(from) && !canSee(to)))
  2102.         return;
  2103.  
  2104.     NetworkMessage_ptr msg = getOutputBuffer();
  2105.     if(msg)
  2106.     {
  2107.         TRACK_MESSAGE(msg);
  2108.         AddDistanceShoot(msg, from, to, type);
  2109.     }
  2110. }
  2111.  
  2112. void ProtocolGame::sendMagicEffect(const Position& pos, uint8_t type)
  2113. {
  2114.     if(type > MAGIC_EFFECT_LAST || !canSee(pos))
  2115.         return;
  2116.  
  2117.     NetworkMessage_ptr msg = getOutputBuffer();
  2118.     if(msg)
  2119.     {
  2120.         TRACK_MESSAGE(msg);
  2121.         AddMagicEffect(msg, pos, type);
  2122.     }
  2123. }
  2124.  
  2125. void ProtocolGame::sendAnimatedText(const Position& pos, uint8_t color, std::string text)
  2126. {
  2127.     if(!canSee(pos))
  2128.         return;
  2129.  
  2130.     NetworkMessage_ptr msg = getOutputBuffer();
  2131.     if(msg)
  2132.     {
  2133.         TRACK_MESSAGE(msg);
  2134.         AddAnimatedText(msg, pos, color, text);
  2135.     }
  2136. }
  2137.  
  2138. void ProtocolGame::sendCreatureHealth(const Creature* creature)
  2139. {
  2140.     if(!canSee(creature))
  2141.         return;
  2142.  
  2143.     NetworkMessage_ptr msg = getOutputBuffer();
  2144.     if(msg)
  2145.     {
  2146.         TRACK_MESSAGE(msg);
  2147.         AddCreatureHealth(msg, creature);
  2148.     }
  2149. }
  2150.  
  2151. void ProtocolGame::sendFYIBox(const std::string& message)
  2152. {
  2153.     if(message.empty() || message.length() > 1018) //Prevent client debug when message is empty or length is > 1018 (not confirmed)
  2154.     {
  2155.         std::cout << "[Warning - ProtocolGame::sendFYIBox] Trying to send an empty or too huge message." << std::endl;
  2156.         return;
  2157.     }
  2158.  
  2159.     NetworkMessage_ptr msg = getOutputBuffer();
  2160.     if(msg)
  2161.     {
  2162.         TRACK_MESSAGE(msg);
  2163.         msg->AddByte(0x15);
  2164.         msg->AddString(message);
  2165.     }
  2166. }
  2167.  
  2168. //tile
  2169. void ProtocolGame::sendAddTileItem(const Tile* tile, const Position& pos, uint32_t stackpos, const Item* item)
  2170. {
  2171.     if(!canSee(pos))
  2172.         return;
  2173.  
  2174.     NetworkMessage_ptr msg = getOutputBuffer();
  2175.     if(msg)
  2176.     {
  2177.         TRACK_MESSAGE(msg);
  2178.         AddTileItem(msg, pos, stackpos, item);
  2179.     }
  2180. }
  2181.  
  2182. void ProtocolGame::sendUpdateTileItem(const Tile* tile, const Position& pos, uint32_t stackpos, const Item* item)
  2183. {
  2184.     if(!canSee(pos))
  2185.         return;
  2186.  
  2187.     NetworkMessage_ptr msg = getOutputBuffer();
  2188.     if(msg)
  2189.     {
  2190.         TRACK_MESSAGE(msg);
  2191.         UpdateTileItem(msg, pos, stackpos, item);
  2192.     }
  2193. }
  2194.  
  2195. void ProtocolGame::sendRemoveTileItem(const Tile* tile, const Position& pos, uint32_t stackpos)
  2196. {
  2197.     if(!canSee(pos))
  2198.         return;
  2199.  
  2200.     NetworkMessage_ptr msg = getOutputBuffer();
  2201.     if(msg)
  2202.     {
  2203.         TRACK_MESSAGE(msg);
  2204.         RemoveTileItem(msg, pos, stackpos);
  2205.     }
  2206. }
  2207.  
  2208. void ProtocolGame::sendUpdateTile(const Tile* tile, const Position& pos)
  2209. {
  2210.     if(!canSee(pos))
  2211.         return;
  2212.  
  2213.     NetworkMessage_ptr msg = getOutputBuffer();
  2214.     if(msg)
  2215.     {
  2216.         TRACK_MESSAGE(msg);
  2217.         msg->AddByte(0x69);
  2218.         msg->AddPosition(pos);
  2219.         if(tile)
  2220.         {
  2221.             GetTileDescription(tile, msg);
  2222.             msg->AddByte(0x00);
  2223.             msg->AddByte(0xFF);
  2224.         }
  2225.         else
  2226.         {
  2227.             msg->AddByte(0x01);
  2228.             msg->AddByte(0xFF);
  2229.         }
  2230.     }
  2231. }
  2232.  
  2233. void ProtocolGame::sendAddCreature(const Creature* creature, const Position& pos, uint32_t stackpos)
  2234. {
  2235.     if(!canSee(creature))
  2236.         return;
  2237.  
  2238.     NetworkMessage_ptr msg = getOutputBuffer();
  2239.     if(!msg)
  2240.         return;
  2241.  
  2242.     TRACK_MESSAGE(msg);
  2243.     if(creature != player)
  2244.     {
  2245.         AddTileCreature(msg, pos, stackpos, creature);
  2246.         return;
  2247.     }
  2248.  
  2249.     msg->AddByte(0x0A);
  2250.     msg->AddU32(player->getID());
  2251.     msg->AddU16(0x32);
  2252.  
  2253.     msg->AddByte(player->hasFlag(PlayerFlag_CanReportBugs));
  2254.     if(Group* group = player->getGroup())
  2255.     {
  2256.         int32_t reasons = group->getViolationReasons();
  2257.         if(reasons > 1)
  2258.         {
  2259.             msg->AddByte(0x0B);
  2260.             for(int32_t i = 0; i < 20; ++i)
  2261.             {
  2262.                 if(i < 4)
  2263.                     msg->AddByte(group->getNameViolationFlags());
  2264.                 else if(i < reasons)
  2265.                     msg->AddByte(group->getStatementViolationFlags());
  2266.                 else
  2267.                     msg->AddByte(0x00);
  2268.             }
  2269.         }
  2270.     }
  2271.  
  2272.     AddMapDescription(msg, pos);
  2273.     for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i)
  2274.         AddInventoryItem(msg, (slots_t)i, player->getInventoryItem((slots_t)i));
  2275.  
  2276.     AddPlayerStats(msg);
  2277.     AddPlayerSkills(msg);
  2278.  
  2279.     //gameworld light-settings
  2280.     LightInfo lightInfo;
  2281.     g_game.getWorldLightInfo(lightInfo);
  2282.     AddWorldLight(msg, lightInfo);
  2283.  
  2284.     //player light level
  2285.     AddCreatureLight(msg, creature);
  2286.     player->sendIcons();
  2287.     for(VIPListSet::iterator it = player->VIPList.begin(); it != player->VIPList.end(); it++)
  2288.     {
  2289.         std::string vipName;
  2290.         if(IOLoginData::getInstance()->getNameByGuid((*it), vipName))
  2291.         {
  2292.             Player* tmpPlayer = g_game.getPlayerByName(vipName);
  2293.             sendVIP((*it), vipName, (tmpPlayer && player->canSeeCreature(tmpPlayer)));
  2294.         }
  2295.     }
  2296. }
  2297.  
  2298. void ProtocolGame::sendRemoveCreature(const Creature* creature, const Position& pos, uint32_t stackpos)
  2299. {
  2300.     if(!canSee(pos))
  2301.         return;
  2302.  
  2303.     NetworkMessage_ptr msg = getOutputBuffer();
  2304.     if(msg)
  2305.     {
  2306.         TRACK_MESSAGE(msg);
  2307.         RemoveTileItem(msg, pos, stackpos);
  2308.     }
  2309. }
  2310.  
  2311. void ProtocolGame::sendMoveCreature(const Creature* creature, const Tile* newTile, const Position& newPos,
  2312.     uint32_t newStackpos, const Tile* oldTile, const Position& oldPos, uint32_t oldStackpos, bool teleport)
  2313. {
  2314.     if(creature == player)
  2315.     {
  2316.         NetworkMessage_ptr msg = getOutputBuffer();
  2317.         if(msg)
  2318.         {
  2319.             TRACK_MESSAGE(msg);
  2320.             if(teleport || oldStackpos >= 10)
  2321.             {
  2322.                 RemoveTileItem(msg, oldPos, oldStackpos);
  2323.                 AddMapDescription(msg, newPos);
  2324.             }
  2325.             else
  2326.             {
  2327.                 if(oldPos.z != 7 || newPos.z < 8)
  2328.                 {
  2329.                     msg->AddByte(0x6D);
  2330.                     msg->AddPosition(oldPos);
  2331.                     msg->AddByte(oldStackpos);
  2332.                     msg->AddPosition(newPos);
  2333.                 }
  2334.                 else
  2335.                     RemoveTileItem(msg, oldPos, oldStackpos);
  2336.  
  2337.                 if(newPos.z > oldPos.z)
  2338.                     MoveDownCreature(msg, creature, newPos, oldPos, oldStackpos);
  2339.                 else if(newPos.z < oldPos.z)
  2340.                     MoveUpCreature(msg, creature, newPos, oldPos, oldStackpos);
  2341.  
  2342.                 if(oldPos.y > newPos.y) // north, for old x
  2343.                 {
  2344.                     msg->AddByte(0x65);
  2345.                     GetMapDescription(oldPos.x - 8, newPos.y - 6, newPos.z, 18, 1, msg);
  2346.                 }
  2347.                 else if(oldPos.y < newPos.y) // south, for old x
  2348.                 {
  2349.                     msg->AddByte(0x67);
  2350.                     GetMapDescription(oldPos.x - 8, newPos.y + 7, newPos.z, 18, 1, msg);
  2351.                 }
  2352.  
  2353.                 if(oldPos.x < newPos.x) // east, [with new y]
  2354.                 {
  2355.                     msg->AddByte(0x66);
  2356.                     GetMapDescription(newPos.x + 9, newPos.y - 6, newPos.z, 1, 14, msg);
  2357.                 }
  2358.                 else if(oldPos.x > newPos.x) // west, [with new y]
  2359.                 {
  2360.                     msg->AddByte(0x68);
  2361.                     GetMapDescription(newPos.x - 8, newPos.y - 6, newPos.z, 1, 14, msg);
  2362.                 }
  2363.             }
  2364.         }
  2365.     }
  2366.     else if(canSee(oldPos) && canSee(newPos))
  2367.     {
  2368.         if(!player->canSeeCreature(creature))
  2369.             return;
  2370.  
  2371.         NetworkMessage_ptr msg = getOutputBuffer();
  2372.         if(msg)
  2373.         {
  2374.             TRACK_MESSAGE(msg);
  2375.             if(!teleport && (oldPos.z != 7 || newPos.z < 8) && oldStackpos < 10)
  2376.             {
  2377.                 msg->AddByte(0x6D);
  2378.                 msg->AddPosition(oldPos);
  2379.                 msg->AddByte(oldStackpos);
  2380.                 msg->AddPosition(newPos);
  2381.             }
  2382.             else
  2383.             {
  2384.                 RemoveTileItem(msg, oldPos, oldStackpos);
  2385.                 AddTileCreature(msg, newPos, newStackpos, creature);
  2386.             }
  2387.         }
  2388.     }
  2389.     else if(canSee(oldPos))
  2390.     {
  2391.         if(!player->canSeeCreature(creature))
  2392.             return;
  2393.  
  2394.         NetworkMessage_ptr msg = getOutputBuffer();
  2395.         if(msg)
  2396.         {
  2397.             TRACK_MESSAGE(msg);
  2398.             RemoveTileItem(msg, oldPos, oldStackpos);
  2399.         }
  2400.     }
  2401.     else if(canSee(newPos) && player->canSeeCreature(creature))
  2402.     {
  2403.         NetworkMessage_ptr msg = getOutputBuffer();
  2404.         if(msg)
  2405.         {
  2406.             TRACK_MESSAGE(msg);
  2407.             AddTileCreature(msg, newPos, newStackpos, creature);
  2408.         }
  2409.     }
  2410. }
  2411.  
  2412. //inventory
  2413. void ProtocolGame::sendAddInventoryItem(slots_t slot, const Item* item)
  2414. {
  2415.     NetworkMessage_ptr msg = getOutputBuffer();
  2416.     if(msg)
  2417.     {
  2418.         TRACK_MESSAGE(msg);
  2419.         AddInventoryItem(msg, slot, item);
  2420.     }
  2421. }
  2422.  
  2423. void ProtocolGame::sendUpdateInventoryItem(slots_t slot, const Item* item)
  2424. {
  2425.     NetworkMessage_ptr msg = getOutputBuffer();
  2426.     if(msg)
  2427.     {
  2428.         TRACK_MESSAGE(msg);
  2429.         UpdateInventoryItem(msg, slot, item);
  2430.     }
  2431. }
  2432.  
  2433. void ProtocolGame::sendRemoveInventoryItem(slots_t slot)
  2434. {
  2435.     NetworkMessage_ptr msg = getOutputBuffer();
  2436.     if(msg)
  2437.     {
  2438.         TRACK_MESSAGE(msg);
  2439.         RemoveInventoryItem(msg, slot);
  2440.     }
  2441. }
  2442.  
  2443. //containers
  2444. void ProtocolGame::sendAddContainerItem(uint8_t cid, const Item* item)
  2445. {
  2446.     NetworkMessage_ptr msg = getOutputBuffer();
  2447.     if(msg)
  2448.     {
  2449.         TRACK_MESSAGE(msg);
  2450.         AddContainerItem(msg, cid, item);
  2451.     }
  2452. }
  2453.  
  2454. void ProtocolGame::sendUpdateContainerItem(uint8_t cid, uint8_t slot, const Item* item)
  2455. {
  2456.     NetworkMessage_ptr msg = getOutputBuffer();
  2457.     if(msg)
  2458.     {
  2459.         TRACK_MESSAGE(msg);
  2460.         UpdateContainerItem(msg, cid, slot, item);
  2461.     }
  2462. }
  2463.  
  2464. void ProtocolGame::sendRemoveContainerItem(uint8_t cid, uint8_t slot)
  2465. {
  2466.     NetworkMessage_ptr msg = getOutputBuffer();
  2467.     if(msg)
  2468.     {
  2469.         TRACK_MESSAGE(msg);
  2470.         RemoveContainerItem(msg, cid, slot);
  2471.     }
  2472. }
  2473.  
  2474. void ProtocolGame::sendTextWindow(uint32_t windowTextId, Item* item, uint16_t maxLen, bool canWrite)
  2475. {
  2476.     NetworkMessage_ptr msg = getOutputBuffer();
  2477.     if(msg)
  2478.     {
  2479.         TRACK_MESSAGE(msg);
  2480.         msg->AddByte(0x96);
  2481.         msg->AddU32(windowTextId);
  2482.         msg->AddItemId(item);
  2483.         if(canWrite)
  2484.         {
  2485.             msg->AddU16(maxLen);
  2486.             msg->AddString(item->getText());
  2487.         }
  2488.         else
  2489.         {
  2490.             msg->AddU16(item->getText().size());
  2491.             msg->AddString(item->getText());
  2492.         }
  2493.  
  2494.         const std::string& writer = item->getWriter();
  2495.         if(writer.size())
  2496.             msg->AddString(writer);
  2497.         else
  2498.             msg->AddString("");
  2499.  
  2500.         time_t writtenDate = item->getDate();
  2501.         if(writtenDate > 0)
  2502.             msg->AddString(formatDate(writtenDate));
  2503.         else
  2504.             msg->AddString("");
  2505.     }
  2506. }
  2507.  
  2508. void ProtocolGame::sendTextWindow(uint32_t windowTextId, uint32_t itemId, const std::string& text)
  2509. {
  2510.     NetworkMessage_ptr msg = getOutputBuffer();
  2511.     if(msg)
  2512.     {
  2513.         TRACK_MESSAGE(msg);
  2514.         msg->AddByte(0x96);
  2515.         msg->AddU32(windowTextId);
  2516.         msg->AddItemId(itemId);
  2517.  
  2518.         msg->AddU16(text.size());
  2519.         msg->AddString(text);
  2520.  
  2521.         msg->AddString("");
  2522.         msg->AddString("");
  2523.     }
  2524. }
  2525.  
  2526. void ProtocolGame::sendHouseWindow(uint32_t windowTextId, House* _house,
  2527.     uint32_t listId, const std::string& text)
  2528. {
  2529.     NetworkMessage_ptr msg = getOutputBuffer();
  2530.     if(msg)
  2531.     {
  2532.         TRACK_MESSAGE(msg);
  2533.         msg->AddByte(0x97);
  2534.         msg->AddByte(0x00);
  2535.         msg->AddU32(windowTextId);
  2536.         msg->AddString(text);
  2537.     }
  2538. }
  2539.  
  2540. void ProtocolGame::sendOutfitWindow()
  2541. {
  2542.     NetworkMessage_ptr msg = getOutputBuffer();
  2543.     if(msg)
  2544.     {
  2545.         TRACK_MESSAGE(msg);
  2546.         msg->AddByte(0xC8);
  2547.         AddCreatureOutfit(msg, player, player->getDefaultOutfit(), true);
  2548.  
  2549.         std::list<Outfit> outfitList;
  2550.         for(OutfitMap::iterator it = player->outfits.begin(); it != player->outfits.end(); ++it)
  2551.         {
  2552.             if(player->canWearOutfit(it->first, it->second.addons))
  2553.                 outfitList.push_back(it->second);
  2554.         }
  2555.  
  2556.         if(outfitList.size())
  2557.         {
  2558.             msg->AddByte((size_t)std::min((size_t)OUTFITS_MAX_NUMBER, outfitList.size()));
  2559.             std::list<Outfit>::iterator it = outfitList.begin();
  2560.             for(int32_t i = 0; it != outfitList.end() && i < OUTFITS_MAX_NUMBER; ++it, ++i)
  2561.             {
  2562.                 msg->AddU16(it->lookType);
  2563.                 msg->AddString(it->name);
  2564.                 if(player->hasCustomFlag(PlayerCustomFlag_CanWearAllAddons))
  2565.                     msg->AddByte(0x03);
  2566.                 else if(!g_config.getBool(ConfigManager::ADDONS_PREMIUM) || player->isPremium())
  2567.                     msg->AddByte(it->addons);
  2568.                 else
  2569.                     msg->AddByte(0x00);
  2570.             }
  2571.         }
  2572.         else
  2573.         {
  2574.             msg->AddByte(1);
  2575.             msg->AddU16(player->getDefaultOutfit().lookType);
  2576.             msg->AddString("Outfit");
  2577.             msg->AddByte(player->getDefaultOutfit().lookAddons);
  2578.         }
  2579.  
  2580.         player->hasRequestedOutfit(true);
  2581.     }
  2582. }
  2583.  
  2584. void ProtocolGame::sendQuests()
  2585. {
  2586.     NetworkMessage_ptr msg = getOutputBuffer();
  2587.     if(msg)
  2588.     {
  2589.         TRACK_MESSAGE(msg);
  2590.         msg->AddByte(0xF0);
  2591.  
  2592.         msg->AddU16(Quests::getInstance()->getQuestCount(player));
  2593.         for(QuestList::const_iterator it = Quests::getInstance()->getFirstQuest(); it != Quests::getInstance()->getLastQuest(); ++it)
  2594.         {
  2595.             if(!(*it)->isStarted(player))
  2596.                 continue;
  2597.  
  2598.             msg->AddU16((*it)->getId());
  2599.             msg->AddString((*it)->getName());
  2600.             msg->AddByte((*it)->isCompleted(player));
  2601.         }
  2602.     }
  2603. }
  2604.  
  2605. void ProtocolGame::sendQuestInfo(Quest* quest)
  2606. {
  2607.     NetworkMessage_ptr msg = getOutputBuffer();
  2608.     if(msg)
  2609.     {
  2610.         TRACK_MESSAGE(msg);
  2611.         msg->AddByte(0xF1);
  2612.         msg->AddU16(quest->getId());
  2613.  
  2614.         msg->AddByte(quest->getMissionCount(player));
  2615.         for(MissionList::const_iterator it = quest->getFirstMission(); it != quest->getLastMission(); ++it)
  2616.         {
  2617.             if(!(*it)->isStarted(player))
  2618.                 continue;
  2619.  
  2620.             msg->AddString((*it)->getName(player));
  2621.             msg->AddString((*it)->getDescription(player));
  2622.         }
  2623.     }
  2624. }
  2625.  
  2626. void ProtocolGame::sendVIPLogIn(uint32_t guid)
  2627. {
  2628.     NetworkMessage_ptr msg = getOutputBuffer();
  2629.     if(msg)
  2630.     {
  2631.         TRACK_MESSAGE(msg);
  2632.         msg->AddByte(0xD3);
  2633.         msg->AddU32(guid);
  2634.     }
  2635. }
  2636.  
  2637. void ProtocolGame::sendVIPLogOut(uint32_t guid)
  2638. {
  2639.     NetworkMessage_ptr msg = getOutputBuffer();
  2640.     if(msg)
  2641.     {
  2642.         TRACK_MESSAGE(msg);
  2643.         msg->AddByte(0xD4);
  2644.         msg->AddU32(guid);
  2645.     }
  2646. }
  2647.  
  2648. void ProtocolGame::sendVIP(uint32_t guid, const std::string& name, bool isOnline)
  2649. {
  2650.     NetworkMessage_ptr msg = getOutputBuffer();
  2651.     if(msg)
  2652.     {
  2653.         TRACK_MESSAGE(msg);
  2654.         msg->AddByte(0xD2);
  2655.         msg->AddU32(guid);
  2656.         msg->AddString(name);
  2657.         msg->AddByte(isOnline ? 1 : 0);
  2658.     }
  2659. }
  2660.  
  2661. ////////////// Add common messages
  2662. void ProtocolGame::AddMapDescription(NetworkMessage_ptr msg, const Position& pos)
  2663. {
  2664.     msg->AddByte(0x64);
  2665.     msg->AddPosition(player->getPosition());
  2666.     GetMapDescription(pos.x - 8, pos.y - 6, pos.z, 18, 14, msg);
  2667. }
  2668.  
  2669. void ProtocolGame::AddTextMessage(NetworkMessage_ptr msg, MessageClasses mclass, const std::string& message)
  2670. {
  2671.     msg->AddByte(0xB4);
  2672.     msg->AddByte(mclass);
  2673.     msg->AddString(message);
  2674. }
  2675.  
  2676. void ProtocolGame::AddAnimatedText(NetworkMessage_ptr msg, const Position& pos,
  2677.     uint8_t color, const std::string& text)
  2678. {
  2679.     msg->AddByte(0x84);
  2680.     msg->AddPosition(pos);
  2681.     msg->AddByte(color);
  2682.     msg->AddString(text);
  2683. }
  2684.  
  2685. void ProtocolGame::AddMagicEffect(NetworkMessage_ptr msg,const Position& pos, uint8_t type)
  2686. {
  2687.     msg->AddByte(0x83);
  2688.     msg->AddPosition(pos);
  2689.     msg->AddByte(type + 1);
  2690. }
  2691.  
  2692. void ProtocolGame::AddDistanceShoot(NetworkMessage_ptr msg, const Position& from, const Position& to,
  2693.     uint8_t type)
  2694. {
  2695.     msg->AddByte(0x85);
  2696.     msg->AddPosition(from);
  2697.     msg->AddPosition(to);
  2698.     msg->AddByte(type + 1);
  2699. }
  2700.  
  2701. void ProtocolGame::AddCreature(NetworkMessage_ptr msg, const Creature* creature, bool known, uint32_t remove)
  2702. {
  2703.     if(!known)
  2704.     {
  2705.         msg->AddU16(0x61);
  2706.         msg->AddU32(remove);
  2707.         msg->AddU32(creature->getID());
  2708.         msg->AddString(creature->getHideName() ? "" : (creature->getNick().empty() ? creature->getName() : creature->getNick()));
  2709.     }
  2710.     else
  2711.     {
  2712.         msg->AddU16(0x62);
  2713.         msg->AddU32(creature->getID());
  2714.     }
  2715.  
  2716.     if(!creature->getHideHealth())
  2717.         msg->AddByte((int32_t)std::ceil(((float)creature->getHealth()) * 100 / std::max(creature->getMaxHealth(), (int32_t)1)));
  2718.     else
  2719.         msg->AddByte(0x00);
  2720.  
  2721.     msg->AddByte((uint8_t)creature->getDirection());
  2722.     AddCreatureOutfit(msg, creature, creature->getCurrentOutfit());
  2723.  
  2724.     LightInfo lightInfo;
  2725.     creature->getCreatureLight(lightInfo);
  2726.     msg->AddByte(player->hasCustomFlag(PlayerCustomFlag_HasFullLight) ? 0xFF : lightInfo.level);
  2727.     msg->AddByte(lightInfo.color);
  2728.  
  2729.     msg->AddU16(creature->getStepSpeed());
  2730.     msg->AddByte(player->getSkullClient(creature));
  2731.     msg->AddByte(player->getPartyShield(creature));
  2732.     if(!known)
  2733.         msg->AddByte(0x00); // war emblem
  2734.  
  2735.     msg->AddByte(!player->canWalkthrough(creature));
  2736. }
  2737.  
  2738. void ProtocolGame::AddPlayerStats(NetworkMessage_ptr msg)
  2739. {
  2740.     msg->AddByte(0xA0);
  2741.     msg->AddU16(player->getHealth());
  2742.     msg->AddU16(player->getPlayerInfo(PLAYERINFO_MAXHEALTH));
  2743.     msg->AddU32(uint32_t(player->getFreeCapacity() * 100));
  2744.     uint64_t experience = player->getExperience();
  2745.     if(experience > 0x7FFFFFFF) // client debugs after 2,147,483,647 exp
  2746.         msg->AddU32(0x7FFFFFFF);
  2747.     else
  2748.         msg->AddU32(experience);
  2749.  
  2750.     msg->AddU16(player->getPlayerInfo(PLAYERINFO_LEVEL));
  2751.     msg->AddByte(player->getPlayerInfo(PLAYERINFO_LEVELPERCENT));
  2752.     msg->AddU16(player->getPlayerInfo(PLAYERINFO_MANA));
  2753.     msg->AddU16(player->getPlayerInfo(PLAYERINFO_MAXMANA));
  2754.     msg->AddByte(player->getPlayerInfo(PLAYERINFO_MAGICLEVEL));
  2755.     msg->AddByte(player->getPlayerInfo(PLAYERINFO_MAGICLEVELPERCENT));
  2756.     msg->AddByte(player->getPlayerInfo(PLAYERINFO_SOUL));
  2757.     msg->AddU16(player->getStaminaMinutes());
  2758. }
  2759.  
  2760. void ProtocolGame::AddPlayerSkills(NetworkMessage_ptr msg)
  2761. {
  2762.     msg->AddByte(0xA1);
  2763.     msg->AddByte(player->getSkill(SKILL_FIST, SKILL_LEVEL));
  2764.     msg->AddByte(player->getSkill(SKILL_FIST, SKILL_PERCENT));
  2765.     msg->AddByte(player->getSkill(SKILL_CLUB, SKILL_LEVEL));
  2766.     msg->AddByte(player->getSkill(SKILL_CLUB, SKILL_PERCENT));
  2767.     msg->AddByte(player->getSkill(SKILL_SWORD, SKILL_LEVEL));
  2768.     msg->AddByte(player->getSkill(SKILL_SWORD, SKILL_PERCENT));
  2769.     msg->AddByte(player->getSkill(SKILL_AXE, SKILL_LEVEL));
  2770.     msg->AddByte(player->getSkill(SKILL_AXE, SKILL_PERCENT));
  2771.     msg->AddByte(player->getSkill(SKILL_DIST, SKILL_LEVEL));
  2772.     msg->AddByte(player->getSkill(SKILL_DIST, SKILL_PERCENT));
  2773.     msg->AddByte(player->getSkill(SKILL_SHIELD, SKILL_LEVEL));
  2774.     msg->AddByte(player->getSkill(SKILL_SHIELD, SKILL_PERCENT));
  2775.     msg->AddByte(player->getSkill(SKILL_FISH, SKILL_LEVEL));
  2776.     msg->AddByte(player->getSkill(SKILL_FISH, SKILL_PERCENT));
  2777. }
  2778.  
  2779. void ProtocolGame::AddCreatureSpeak(NetworkMessage_ptr msg, const Creature* creature, SpeakClasses type,
  2780.     std::string text, uint16_t channelId, uint32_t time/*= 0*/, Position* pos/* = NULL*/)
  2781. {
  2782.     msg->AddByte(0xAA);
  2783.     if(creature)
  2784.     {
  2785.         const Player* speaker = creature->getPlayer();
  2786.         if(speaker)
  2787.         {
  2788.             msg->AddU32(++g_chat.statement);
  2789.             g_chat.statementMap[g_chat.statement] = text;
  2790.         }
  2791.         else
  2792.             msg->AddU32(0x00);
  2793.  
  2794.         if(creature->getSpeakType() != SPEAK_CLASS_NONE)
  2795.             type = creature->getSpeakType();
  2796.  
  2797.         switch(type)
  2798.         {
  2799.             case SPEAK_CHANNEL_RA:
  2800.                 msg->AddString("");
  2801.                 break;
  2802.             case SPEAK_RVR_ANSWER:
  2803.                 msg->AddString("Gamemaster");
  2804.                 break;
  2805.             default:
  2806.                 msg->AddString(!creature->getHideName() ? (creature->getNick().empty() ? creature->getName() : creature->getNick()) : "");
  2807.                 break;
  2808.         }
  2809.  
  2810.         if(speaker && type != SPEAK_RVR_ANSWER && !speaker->isAccountManager()
  2811.             && !speaker->hasCustomFlag(PlayerCustomFlag_HideLevel))
  2812.             msg->AddU16(speaker->getPlayerInfo(PLAYERINFO_LEVEL));
  2813.         else
  2814.             msg->AddU16(0x00);
  2815.  
  2816.     }
  2817.     else
  2818.     {
  2819.         msg->AddU32(0x00);
  2820.         msg->AddString("");
  2821.         msg->AddU16(0x00);
  2822.     }
  2823.  
  2824.     msg->AddByte(type);
  2825.     switch(type)
  2826.     {
  2827.         case SPEAK_SAY:
  2828.         case SPEAK_WHISPER:
  2829.         case SPEAK_YELL:
  2830.         case SPEAK_MONSTER_SAY:
  2831.         case SPEAK_MONSTER_YELL:
  2832.         case SPEAK_PRIVATE_NP:
  2833.         {
  2834.             if(pos)
  2835.                 msg->AddPosition(*pos);
  2836.             else if(creature)
  2837.                 msg->AddPosition(creature->getPosition());
  2838.             else
  2839.                 msg->AddPosition(Position(0,0,7));
  2840.  
  2841.             break;
  2842.         }
  2843.  
  2844.         case SPEAK_CHANNEL_Y:
  2845.         case SPEAK_CHANNEL_RN:
  2846.         case SPEAK_CHANNEL_RA:
  2847.         case SPEAK_CHANNEL_O:
  2848.         case SPEAK_CHANNEL_W:
  2849.             msg->AddU16(channelId);
  2850.             break;
  2851.  
  2852.         case SPEAK_RVR_CHANNEL:
  2853.         {
  2854.             msg->AddU32(uint32_t(OTSYS_TIME() / 1000 & 0xFFFFFFFF) - time);
  2855.             break;
  2856.         }
  2857.  
  2858.         default:
  2859.             break;
  2860.     }
  2861.  
  2862.     msg->AddString(text);
  2863. }
  2864.  
  2865. void ProtocolGame::AddCreatureHealth(NetworkMessage_ptr msg,const Creature* creature)
  2866. {
  2867.     msg->AddByte(0x8C);
  2868.     msg->AddU32(creature->getID());
  2869.     if(!creature->getHideHealth())
  2870.         msg->AddByte((int32_t)std::ceil(((float)creature->getHealth()) * 100 / std::max(creature->getMaxHealth(), (int32_t)1)));
  2871.     else
  2872.         msg->AddByte(0x00);
  2873. }
  2874.  
  2875. void ProtocolGame::AddCreatureOutfit(NetworkMessage_ptr msg, const Creature* creature, const Outfit_t& outfit, bool outfitWindow/* = false*/)
  2876. {
  2877.     if(outfitWindow || !creature->getPlayer() || (!creature->isInvisible() && (!creature->isGhost()
  2878.         || !g_config.getBool(ConfigManager::GHOST_INVISIBLE_EFFECT))))
  2879.     {
  2880.         msg->AddU16(outfit.lookType);
  2881.         if(outfit.lookType)
  2882.         {
  2883.             msg->AddByte(outfit.lookHead);
  2884.             msg->AddByte(outfit.lookBody);
  2885.             msg->AddByte(outfit.lookLegs);
  2886.             msg->AddByte(outfit.lookFeet);
  2887.             msg->AddByte(outfit.lookAddons);
  2888.         }
  2889.         else if(outfit.lookTypeEx)
  2890.             msg->AddItemId(outfit.lookTypeEx);
  2891.         else
  2892.             msg->AddU16(outfit.lookTypeEx);
  2893.     }
  2894.     else
  2895.         msg->AddU32(0x00);
  2896. }
  2897.  
  2898. void ProtocolGame::AddWorldLight(NetworkMessage_ptr msg, const LightInfo& lightInfo)
  2899. {
  2900.     msg->AddByte(0x82);
  2901.     msg->AddByte((player->hasCustomFlag(PlayerCustomFlag_HasFullLight) ? 0xFF : lightInfo.level));
  2902.     msg->AddByte(lightInfo.color);
  2903. }
  2904.  
  2905. void ProtocolGame::AddCreatureLight(NetworkMessage_ptr msg, const Creature* creature)
  2906. {
  2907.     LightInfo lightInfo;
  2908.     creature->getCreatureLight(lightInfo);
  2909.     msg->AddByte(0x8D);
  2910.     msg->AddU32(creature->getID());
  2911.     msg->AddByte((player->hasCustomFlag(PlayerCustomFlag_HasFullLight) ? 0xFF : lightInfo.level));
  2912.     msg->AddByte(lightInfo.color);
  2913. }
  2914.  
  2915. //tile
  2916. void ProtocolGame::AddTileItem(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos, const Item* item)
  2917. {
  2918.     if(stackpos >= 10)
  2919.         return;
  2920.  
  2921.     msg->AddByte(0x6A);
  2922.     msg->AddPosition(pos);
  2923.     msg->AddByte(stackpos);
  2924.     msg->AddItem(item);
  2925. }
  2926.  
  2927. void ProtocolGame::AddTileCreature(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos, const Creature* creature)
  2928. {
  2929.     if(stackpos >= 10)
  2930.         return;
  2931.  
  2932.     msg->AddByte(0x6A);
  2933.     msg->AddPosition(pos);
  2934.     msg->AddByte(stackpos);
  2935.  
  2936.     bool known;
  2937.     uint32_t removedKnown;
  2938.     checkCreatureAsKnown(creature->getID(), known, removedKnown);
  2939.     AddCreature(msg, creature, known, removedKnown);
  2940. }
  2941.  
  2942. void ProtocolGame::UpdateTileItem(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos, const Item* item)
  2943. {
  2944.     if(stackpos >= 10)
  2945.         return;
  2946.  
  2947.     msg->AddByte(0x6B);
  2948.     msg->AddPosition(pos);
  2949.     msg->AddByte(stackpos);
  2950.     msg->AddItem(item);
  2951. }
  2952.  
  2953. void ProtocolGame::RemoveTileItem(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos)
  2954. {
  2955.     if(stackpos >= 10)
  2956.         return;
  2957.  
  2958.     msg->AddByte(0x6C);
  2959.     msg->AddPosition(pos);
  2960.     msg->AddByte(stackpos);
  2961. }
  2962.  
  2963. void ProtocolGame::MoveUpCreature(NetworkMessage_ptr msg, const Creature* creature,
  2964.     const Position& newPos, const Position& oldPos, uint32_t oldStackpos)
  2965. {
  2966.     if(creature != player)
  2967.         return;
  2968.  
  2969.     msg->AddByte(0xBE); //floor change up
  2970.     if(newPos.z == 7) //going to surface
  2971.     {
  2972.         int32_t skip = -1;
  2973.         GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 5, 18, 14, 3, skip); //(floor 7 and 6 already set)
  2974.         GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 4, 18, 14, 4, skip);
  2975.         GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 3, 18, 14, 5, skip);
  2976.         GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 2, 18, 14, 6, skip);
  2977.         GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 1, 18, 14, 7, skip);
  2978.         GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 0, 18, 14, 8, skip);
  2979.         if(skip >= 0)
  2980.         {
  2981.             msg->AddByte(skip);
  2982.             msg->AddByte(0xFF);
  2983.         }
  2984.     }
  2985.     else if(newPos.z > 7) //underground, going one floor up (still underground)
  2986.     {
  2987.         int32_t skip = -1;
  2988.         GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, oldPos.z - 3, 18, 14, 3, skip);
  2989.         if(skip >= 0)
  2990.         {
  2991.             msg->AddByte(skip);
  2992.             msg->AddByte(0xFF);
  2993.         }
  2994.     }
  2995.  
  2996.     //moving up a floor up makes us out of sync
  2997.     //west
  2998.     msg->AddByte(0x68);
  2999.     GetMapDescription(oldPos.x - 8, oldPos.y + 1 - 6, newPos.z, 1, 14, msg);
  3000.  
  3001.     //north
  3002.     msg->AddByte(0x65);
  3003.     GetMapDescription(oldPos.x - 8, oldPos.y - 6, newPos.z, 18, 1, msg);
  3004. }
  3005.  
  3006. void ProtocolGame::MoveDownCreature(NetworkMessage_ptr msg, const Creature* creature,
  3007.     const Position& newPos, const Position& oldPos, uint32_t oldStackpos)
  3008. {
  3009.     if(creature != player)
  3010.         return;
  3011.  
  3012.     msg->AddByte(0xBF); //floor change down
  3013.     if(newPos.z == 8) //going from surface to underground
  3014.     {
  3015.         int32_t skip = -1;
  3016.         GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, newPos.z, 18, 14, -1, skip);
  3017.         GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, newPos.z + 1, 18, 14, -2, skip);
  3018.         GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, newPos.z + 2, 18, 14, -3, skip);
  3019.         if(skip >= 0)
  3020.         {
  3021.             msg->AddByte(skip);
  3022.             msg->AddByte(0xFF);
  3023.         }
  3024.     }
  3025.     else if(newPos.z > oldPos.z && newPos.z > 8 && newPos.z < 14) //going further down
  3026.     {
  3027.         int32_t skip = -1;
  3028.         GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, newPos.z + 2, 18, 14, -3, skip);
  3029.         if(skip >= 0)
  3030.         {
  3031.             msg->AddByte(skip);
  3032.             msg->AddByte(0xFF);
  3033.         }
  3034.     }
  3035.  
  3036.     //moving down a floor makes us out of sync
  3037.     //east
  3038.     msg->AddByte(0x66);
  3039.     GetMapDescription(oldPos.x + 9, oldPos.y - 1 - 6, newPos.z, 1, 14, msg);
  3040.  
  3041.     //south
  3042.     msg->AddByte(0x67);
  3043.     GetMapDescription(oldPos.x - 8, oldPos.y + 7, newPos.z, 18, 1, msg);
  3044. }
  3045.  
  3046. //inventory
  3047. void ProtocolGame::AddInventoryItem(NetworkMessage_ptr msg, slots_t slot, const Item* item)
  3048. {
  3049.     if(item)
  3050.     {
  3051.         msg->AddByte(0x78);
  3052.         msg->AddByte(slot);
  3053.         msg->AddItem(item);
  3054.     }
  3055.     else
  3056.         RemoveInventoryItem(msg, slot);
  3057. }
  3058.  
  3059. void ProtocolGame::RemoveInventoryItem(NetworkMessage_ptr msg, slots_t slot)
  3060. {
  3061.     msg->AddByte(0x79);
  3062.     msg->AddByte(slot);
  3063. }
  3064.  
  3065. void ProtocolGame::UpdateInventoryItem(NetworkMessage_ptr msg, slots_t slot, const Item* item)
  3066. {
  3067.     AddInventoryItem(msg, slot, item);
  3068. }
  3069.  
  3070. //containers
  3071. void ProtocolGame::AddContainerItem(NetworkMessage_ptr msg, uint8_t cid, const Item* item)
  3072. {
  3073.     msg->AddByte(0x70);
  3074.     msg->AddByte(cid);
  3075.     msg->AddItem(item);
  3076. }
  3077.  
  3078. void ProtocolGame::UpdateContainerItem(NetworkMessage_ptr msg, uint8_t cid, uint8_t slot, const Item* item)
  3079. {
  3080.     msg->AddByte(0x71);
  3081.     msg->AddByte(cid);
  3082.     msg->AddByte(slot);
  3083.     msg->AddItem(item);
  3084. }
  3085.  
  3086. void ProtocolGame::RemoveContainerItem(NetworkMessage_ptr msg, uint8_t cid, uint8_t slot)
  3087. {
  3088.     msg->AddByte(0x72);
  3089.     msg->AddByte(cid);
  3090.     msg->AddByte(slot);
  3091. }
  3092.  
  3093. void ProtocolGame::sendChannelMessage(std::string author, std::string text, SpeakClasses type, uint8_t channel)
  3094. {
  3095.     NetworkMessage_ptr msg = getOutputBuffer();
  3096.     if(msg)
  3097.     {
  3098.         TRACK_MESSAGE(msg);
  3099.         msg->AddByte(0xAA);
  3100.         msg->AddU32(0x00);
  3101.         msg->AddString(author);
  3102.         msg->AddU16(0x00);
  3103.         msg->AddByte(type);
  3104.         msg->AddU16(channel);
  3105.         msg->AddString(text);
  3106.     }
  3107. }
  3108.  
  3109. void ProtocolGame::AddShopItem(NetworkMessage_ptr msg, const ShopInfo item)
  3110. {
  3111.     const ItemType& it = Item::items[item.itemId];
  3112.     msg->AddU16(it.clientId);
  3113.     if(it.isSplash() || it.isFluidContainer())
  3114.         msg->AddByte(fluidMap[item.subType % 8]);
  3115.     else if(it.stackable || it.charges)
  3116.         msg->AddByte(item.subType);
  3117.     else
  3118.         msg->AddByte(0x01);
  3119.  
  3120.     msg->AddString(item.itemName);
  3121.     msg->AddU32(uint32_t(it.weight * 100));
  3122.     msg->AddU32(item.buyPrice);
  3123.     msg->AddU32(item.sellPrice);
  3124. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement