Advertisement
Kevick

Untitled

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