Advertisement
Guest User

protocolgame.cpp

a guest
Oct 1st, 2017
852
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 62.06 KB | None | 0 0
  1. /**
  2. * The Forgotten Server - a free and open-source MMORPG server emulator
  3. * Copyright (C) 2017 Mark Samman <mark.samman@gmail.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program; if not, write to the Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. */
  19.  
  20. #include "otpch.h"
  21.  
  22. #include <boost/range/adaptor/reversed.hpp>
  23.  
  24. #include "protocolgame.h"
  25.  
  26. #include "outputmessage.h"
  27.  
  28. #include "player.h"
  29.  
  30. #include "configmanager.h"
  31. #include "actions.h"
  32. #include "game.h"
  33. #include "iologindata.h"
  34. #include "waitlist.h"
  35. #include "ban.h"
  36. #include "scheduler.h"
  37. #include "databasetasks.h"
  38.  
  39. extern Game g_game;
  40. extern ConfigManager g_config;
  41. extern Actions actions;
  42. extern CreatureEvents* g_creatureEvents;
  43. extern Chat* g_chat;
  44.  
  45. void ProtocolGame::release()
  46. {
  47. //dispatcher thread
  48. if (player && player->client == shared_from_this()) {
  49. player->client.reset();
  50. player->decrementReferenceCounter();
  51. player = nullptr;
  52. }
  53.  
  54. OutputMessagePool::getInstance().removeProtocolFromAutosend(shared_from_this());
  55. Protocol::release();
  56. }
  57.  
  58. void ProtocolGame::login(const std::string& name, uint32_t accountId, OperatingSystem_t operatingSystem)
  59. {
  60. //dispatcher thread
  61. Player* foundPlayer = g_game.getPlayerByName(name);
  62. if (!foundPlayer || g_config.getBoolean(ConfigManager::ALLOW_CLONES)) {
  63. player = new Player(getThis());
  64. player->setName(name);
  65.  
  66. player->incrementReferenceCounter();
  67. player->setID();
  68.  
  69. if (!IOLoginData::preloadPlayer(player, name)) {
  70. disconnectClient("Your character could not be loaded.");
  71. return;
  72. }
  73.  
  74. if (IOBan::isPlayerNamelocked(player->getGUID())) {
  75. disconnectClient("Your character has been namelocked.");
  76. return;
  77. }
  78.  
  79. if (g_game.getGameState() == GAME_STATE_CLOSING && !player->hasFlag(PlayerFlag_CanAlwaysLogin)) {
  80. disconnectClient("The game is just going down.\nPlease try again later.");
  81. return;
  82. }
  83.  
  84. if (g_game.getGameState() == GAME_STATE_CLOSED && !player->hasFlag(PlayerFlag_CanAlwaysLogin)) {
  85. disconnectClient("Server is currently closed.\nPlease try again later.");
  86. return;
  87. }
  88.  
  89. if (g_config.getBoolean(ConfigManager::ONE_PLAYER_ON_ACCOUNT) && player->getAccountType() < ACCOUNT_TYPE_GAMEMASTER && g_game.getPlayerByAccount(player->getAccount())) {
  90. disconnectClient("You may only login with one character\nof your account at the same time.");
  91. return;
  92. }
  93.  
  94. if (!player->hasFlag(PlayerFlag_CannotBeBanned)) {
  95. BanInfo banInfo;
  96. if (IOBan::isAccountBanned(accountId, banInfo)) {
  97. if (banInfo.reason.empty()) {
  98. banInfo.reason = "(none)";
  99. }
  100.  
  101. std::ostringstream ss;
  102. if (banInfo.expiresAt > 0) {
  103. ss << "Your account has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason;
  104. } else {
  105. ss << "Your account has been permanently banned by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason;
  106. }
  107. disconnectClient(ss.str());
  108. return;
  109. }
  110. }
  111.  
  112. WaitingList& waitingList = WaitingList::getInstance();
  113. if (!waitingList.clientLogin(player)) {
  114. uint32_t currentSlot = waitingList.getClientSlot(player);
  115. uint32_t retryTime = WaitingList::getTime(currentSlot);
  116. std::ostringstream ss;
  117.  
  118. ss << "Too many players online.\nYou are at place "
  119. << currentSlot << " on the waiting list.";
  120.  
  121. auto output = OutputMessagePool::getOutputMessage();
  122. output->addByte(0x16);
  123. output->addString(ss.str());
  124. output->addByte(retryTime);
  125. send(output);
  126. disconnect();
  127. return;
  128. }
  129.  
  130. if (!IOLoginData::loadPlayerByName(player, name)) {
  131. disconnectClient("Your character could not be loaded.");
  132. return;
  133. }
  134.  
  135. player->setOperatingSystem(operatingSystem);
  136.  
  137. if (!g_game.placeCreature(player, player->getLoginPosition())) {
  138. if (!g_game.placeCreature(player, player->getTemplePosition(), false, true)) {
  139. disconnectClient("Temple position is wrong. Contact the administrator.");
  140. return;
  141. }
  142. }
  143.  
  144. if (operatingSystem >= CLIENTOS_OTCLIENT_LINUX) {
  145. player->registerCreatureEvent("ExtendedOpcode");
  146. }
  147.  
  148. player->lastIP = player->getIP();
  149. player->lastLoginSaved = std::max<time_t>(time(nullptr), player->lastLoginSaved + 1);
  150. acceptPackets = true;
  151. } else {
  152. if (eventConnect != 0 || !g_config.getBoolean(ConfigManager::REPLACE_KICK_ON_LOGIN)) {
  153. //Already trying to connect
  154. disconnectClient("You are already logged in.");
  155. return;
  156. }
  157.  
  158. if (foundPlayer->client) {
  159. foundPlayer->disconnect();
  160. foundPlayer->isConnecting = true;
  161.  
  162. eventConnect = g_scheduler.addEvent(createSchedulerTask(1000, std::bind(&ProtocolGame::connect, getThis(), foundPlayer->getID(), operatingSystem)));
  163. } else {
  164. connect(foundPlayer->getID(), operatingSystem);
  165. }
  166. }
  167. OutputMessagePool::getInstance().addProtocolToAutosend(shared_from_this());
  168. }
  169.  
  170. void ProtocolGame::connect(uint32_t playerId, OperatingSystem_t operatingSystem)
  171. {
  172. eventConnect = 0;
  173.  
  174. Player* foundPlayer = g_game.getPlayerByID(playerId);
  175. if (!foundPlayer || foundPlayer->client) {
  176. disconnectClient("You are already logged in.");
  177. return;
  178. }
  179.  
  180. if (isConnectionExpired()) {
  181. //ProtocolGame::release() has been called at this point and the Connection object
  182. //no longer exists, so we return to prevent leakage of the Player.
  183. return;
  184. }
  185.  
  186. player = foundPlayer;
  187. player->incrementReferenceCounter();
  188.  
  189. g_chat->removeUserFromAllChannels(*player);
  190. player->setOperatingSystem(operatingSystem);
  191. player->isConnecting = false;
  192.  
  193. player->client = getThis();
  194. sendAddCreature(player, player->getPosition(), 0, false);
  195. player->lastIP = player->getIP();
  196. player->lastLoginSaved = std::max<time_t>(time(nullptr), player->lastLoginSaved + 1);
  197. acceptPackets = true;
  198. }
  199.  
  200. void ProtocolGame::logout(bool displayEffect, bool forced)
  201. {
  202. //dispatcher thread
  203. if (!player) {
  204. return;
  205. }
  206.  
  207. if (!player->isRemoved()) {
  208. if (!forced) {
  209. if (!player->isAccessPlayer()) {
  210. if (player->getTile()->hasFlag(TILESTATE_NOLOGOUT)) {
  211. player->sendCancelMessage(RETURNVALUE_YOUCANNOTLOGOUTHERE);
  212. return;
  213. }
  214.  
  215. if (!player->getTile()->hasFlag(TILESTATE_PROTECTIONZONE) && player->hasCondition(CONDITION_INFIGHT)) {
  216. player->sendCancelMessage(RETURNVALUE_YOUMAYNOTLOGOUTDURINGAFIGHT);
  217. return;
  218. }
  219. }
  220.  
  221. //scripting event - onLogout
  222. if (!g_creatureEvents->playerLogout(player)) {
  223. //Let the script handle the error message
  224. return;
  225. }
  226. }
  227.  
  228. if (displayEffect && player->getHealth() > 0) {
  229. g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
  230. }
  231. }
  232.  
  233. disconnect();
  234.  
  235. g_game.removeCreature(player);
  236. }
  237.  
  238. void ProtocolGame::onRecvFirstMessage(NetworkMessage& msg)
  239. {
  240. if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
  241. disconnect();
  242. return;
  243. }
  244.  
  245. OperatingSystem_t operatingSystem = static_cast<OperatingSystem_t>(msg.get<uint16_t>());
  246. version = msg.get<uint16_t>();
  247.  
  248. if (!Protocol::RSA_decrypt(msg)) {
  249. disconnect();
  250. return;
  251. }
  252.  
  253. uint32_t key[4];
  254. key[0] = msg.get<uint32_t>();
  255. key[1] = msg.get<uint32_t>();
  256. key[2] = msg.get<uint32_t>();
  257. key[3] = msg.get<uint32_t>();
  258. enableXTEAEncryption();
  259. setXTEAKey(key);
  260.  
  261. if (operatingSystem >= CLIENTOS_OTCLIENT_LINUX) {
  262. NetworkMessage opcodeMessage;
  263. opcodeMessage.addByte(0x32);
  264. opcodeMessage.addByte(0x00);
  265. opcodeMessage.add<uint16_t>(0x00);
  266. writeToOutputBuffer(opcodeMessage);
  267. }
  268.  
  269. msg.skipBytes(1); // gamemaster flag
  270.  
  271. std::string accountName = msg.getString();
  272. std::string characterName = msg.getString();
  273. std::string password = msg.getString();
  274.  
  275. uint32_t timeStamp = msg.get<uint32_t>();
  276. uint8_t randNumber = msg.getByte();
  277. if (challengeTimestamp != timeStamp || challengeRandom != randNumber) {
  278. disconnect();
  279. return;
  280. }
  281.  
  282. if (version < g_config.getNumber(ConfigManager::VERSION_MIN) || version > g_config.getNumber(ConfigManager::VERSION_MAX)) {
  283. std::ostringstream ss;
  284. ss << "Only clients with protocol " << g_config.getString(ConfigManager::VERSION_STR) << " allowed!";
  285. disconnectClient(ss.str());
  286. return;
  287. }
  288.  
  289. if (accountName.empty()) {
  290. disconnectClient("You must enter your account name.");
  291. return;
  292. }
  293.  
  294. if (g_game.getGameState() == GAME_STATE_STARTUP) {
  295. disconnectClient("Gameworld is starting up. Please wait.");
  296. return;
  297. }
  298.  
  299. if (g_game.getGameState() == GAME_STATE_MAINTAIN) {
  300. disconnectClient("Gameworld is under maintenance. Please re-connect in a while.");
  301. return;
  302. }
  303.  
  304. BanInfo banInfo;
  305. if (IOBan::isIpBanned(getIP(), banInfo)) {
  306. if (banInfo.reason.empty()) {
  307. banInfo.reason = "(none)";
  308. }
  309.  
  310. std::ostringstream ss;
  311. ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason;
  312. disconnectClient(ss.str());
  313. return;
  314. }
  315.  
  316. uint32_t accountId = IOLoginData::gameworldAuthentication(accountName, password, characterName);
  317. if (accountId == 0) {
  318. disconnectClient("Account name or password is not correct.");
  319. return;
  320. }
  321.  
  322. g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::login, getThis(), characterName, accountId, operatingSystem)));
  323. }
  324.  
  325. void ProtocolGame::onConnect()
  326. {
  327. auto output = OutputMessagePool::getOutputMessage();
  328. static std::random_device rd;
  329. static std::ranlux24 generator(rd());
  330. static std::uniform_int_distribution<uint16_t> randNumber(0x00, 0xFF);
  331.  
  332. // Skip checksum
  333. output->skipBytes(sizeof(uint32_t));
  334.  
  335. // Packet length & type
  336. output->add<uint16_t>(0x0006);
  337. output->addByte(0x1F);
  338.  
  339. // Add timestamp & random number
  340. challengeTimestamp = static_cast<uint32_t>(time(nullptr));
  341. output->add<uint32_t>(challengeTimestamp);
  342.  
  343. challengeRandom = randNumber(generator);
  344. output->addByte(challengeRandom);
  345.  
  346. // Go back and write checksum
  347. output->skipBytes(-12);
  348. output->add<uint32_t>(adlerChecksum(output->getOutputBuffer() + sizeof(uint32_t), 8));
  349.  
  350. send(std::move(output));
  351. }
  352.  
  353. void ProtocolGame::disconnectClient(const std::string& message) const
  354. {
  355. auto output = OutputMessagePool::getOutputMessage();
  356. output->addByte(0x14);
  357. output->addString(message);
  358. send(output);
  359. disconnect();
  360. }
  361.  
  362. void ProtocolGame::writeToOutputBuffer(const NetworkMessage& msg)
  363. {
  364. auto out = getOutputBuffer(msg.getLength());
  365. out->append(msg);
  366. }
  367.  
  368. void ProtocolGame::parsePacket(NetworkMessage& msg)
  369. {
  370. if (!acceptPackets || g_game.getGameState() == GAME_STATE_SHUTDOWN || msg.getLength() <= 0) {
  371. return;
  372. }
  373.  
  374. uint8_t recvbyte = msg.getByte();
  375.  
  376. //a dead player can not perform actions
  377. if (!player || player->isRemoved() || player->getHealth() <= 0) {
  378. if (recvbyte == 0x0F) {
  379. disconnect();
  380. return;
  381. }
  382.  
  383. if (recvbyte != 0x14) {
  384. return;
  385. }
  386. }
  387.  
  388. switch (recvbyte) {
  389. case 0x14: g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::logout, getThis(), true, false))); break;
  390. case 0x1E: addGameTask(&Game::playerReceivePing, player->getID()); break;
  391. case 0x32: parseExtendedOpcode(msg); break; //otclient extended opcode
  392. case 0x64: parseAutoWalk(msg); break;
  393. case 0x65: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTH); break;
  394. case 0x66: addGameTask(&Game::playerMove, player->getID(), DIRECTION_EAST); break;
  395. case 0x67: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTH); break;
  396. case 0x68: addGameTask(&Game::playerMove, player->getID(), DIRECTION_WEST); break;
  397. case 0x69: addGameTask(&Game::playerStopAutoWalk, player->getID()); break;
  398. case 0x6A: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTHEAST); break;
  399. case 0x6B: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTHEAST); break;
  400. case 0x6C: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTHWEST); break;
  401. case 0x6D: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTHWEST); break;
  402. case 0x6F: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_NORTH); break;
  403. case 0x70: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_EAST); break;
  404. case 0x71: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_SOUTH); break;
  405. case 0x72: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_WEST); break;
  406. case 0x78: parseThrow(msg); break;
  407. case 0x79: parseLookInShop(msg); break;
  408. case 0x7A: parsePlayerPurchase(msg); break;
  409. case 0x7B: parsePlayerSale(msg); break;
  410. case 0x7C: addGameTask(&Game::playerCloseShop, player->getID()); break;
  411. case 0x7D: parseRequestTrade(msg); break;
  412. case 0x7E: parseLookInTrade(msg); break;
  413. case 0x7F: addGameTask(&Game::playerAcceptTrade, player->getID()); break;
  414. case 0x80: addGameTask(&Game::playerCloseTrade, player->getID()); break;
  415. case 0x82: parseUseItem(msg); break;
  416. case 0x83: parseUseItemEx(msg); break;
  417. case 0x84: parseUseWithCreature(msg); break;
  418. case 0x85: parseRotateItem(msg); break;
  419. case 0x87: parseCloseContainer(msg); break;
  420. case 0x88: parseUpArrowContainer(msg); break;
  421. case 0x89: parseTextWindow(msg); break;
  422. case 0x8A: parseHouseWindow(msg); break;
  423. case 0x8C: parseLookAt(msg); break;
  424. case 0x8D: parseLookInBattleList(msg); break;
  425. case 0x8E: /* join aggression */ break;
  426. case 0x96: parseSay(msg); break;
  427. case 0x97: addGameTask(&Game::playerRequestChannels, player->getID()); break;
  428. case 0x98: parseOpenChannel(msg); break;
  429. case 0x99: parseCloseChannel(msg); break;
  430. case 0x9A: parseOpenPrivateChannel(msg); break;
  431. case 0x9E: addGameTask(&Game::playerCloseNpcChannel, player->getID()); break;
  432. case 0xA0: parseFightModes(msg); break;
  433. case 0xA1: parseAttack(msg); break;
  434. case 0xA2: parseFollow(msg); break;
  435. case 0xA3: parseInviteToParty(msg); break;
  436. case 0xA4: parseJoinParty(msg); break;
  437. case 0xA5: parseRevokePartyInvite(msg); break;
  438. case 0xA6: parsePassPartyLeadership(msg); break;
  439. case 0xA7: addGameTask(&Game::playerLeaveParty, player->getID()); break;
  440. case 0xA8: parseEnableSharedPartyExperience(msg); break;
  441. case 0xAA: addGameTask(&Game::playerCreatePrivateChannel, player->getID()); break;
  442. case 0xAB: parseChannelInvite(msg); break;
  443. case 0xAC: parseChannelExclude(msg); break;
  444. case 0xBE: addGameTask(&Game::playerCancelAttackAndFollow, player->getID()); break;
  445. case 0xC9: /* update tile */ break;
  446. case 0xCA: parseUpdateContainer(msg); break;
  447. case 0xD2: addGameTask(&Game::playerRequestOutfit, player->getID()); break;
  448. case 0xD3: parseSetOutfit(msg); break;
  449. case 0xDC: parseAddVip(msg); break;
  450. case 0xDD: parseRemoveVip(msg); break;
  451. case 0xE6: parseBugReport(msg); break;
  452. case 0xE7: /* thank you */ break;
  453. case 0xE8: parseDebugAssert(msg); break;
  454. case 0xF0: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerShowQuestLog, player->getID()); break;
  455. case 0xF1: parseQuestLine(msg); break;
  456. case 0xF2: /* rule violation report */ break;
  457. case 0xF3: /* get object info */ break;
  458.  
  459. default:
  460. // std::cout << "Player: " << player->getName() << " sent an unknown packet header: 0x" << std::hex << static_cast<uint16_t>(recvbyte) << std::dec << "!" << std::endl;
  461. break;
  462. }
  463.  
  464. if (msg.isOverrun()) {
  465. disconnect();
  466. }
  467. }
  468.  
  469. void ProtocolGame::GetTileDescription(const Tile* tile, NetworkMessage& msg)
  470. {
  471. int32_t count;
  472. Item* ground = tile->getGround();
  473. if (ground) {
  474. msg.addItem(ground);
  475. count = 1;
  476. } else {
  477. count = 0;
  478. }
  479.  
  480. const TileItemVector* items = tile->getItemList();
  481. if (items) {
  482. for (auto it = items->getBeginTopItem(), end = items->getEndTopItem(); it != end; ++it) {
  483. msg.addItem(*it);
  484.  
  485. if (++count == 10) {
  486. return;
  487. }
  488. }
  489. }
  490.  
  491. if (!loggedIn && tile->getPosition() == player->getPosition()) {
  492. bool playerSpawned = false;
  493. const CreatureVector *creatures = tile->getCreatures();
  494. if (creatures) {
  495. for (const Creature *creature : boost::adaptors::reverse(*creatures)) {
  496. if (!player->canSeeCreature(creature)) {
  497. continue;
  498. }
  499.  
  500. if (creature == player) {
  501. playerSpawned = true;
  502. }
  503.  
  504. bool known;
  505. uint32_t removedKnown;
  506. checkCreatureAsKnown(creature->getID(), known, removedKnown);
  507. AddCreature(msg, creature, known, removedKnown);
  508.  
  509. if (count == 8 && playerSpawned == false) { // player still not spawned and we need to send him too
  510. checkCreatureAsKnown(player->getID(), known, removedKnown);
  511. AddCreature(msg, player, known, removedKnown);
  512. ++count;
  513. }
  514.  
  515. if (++count == 10) {
  516. return;
  517. }
  518. }
  519. }
  520. } else {
  521. const CreatureVector *creatures = tile->getCreatures();
  522. if (creatures) {
  523. for (const Creature *creature : boost::adaptors::reverse(*creatures)) {
  524. if (!player->canSeeCreature(creature)) {
  525. continue;
  526. }
  527.  
  528. bool known;
  529. uint32_t removedKnown;
  530. checkCreatureAsKnown(creature->getID(), known, removedKnown);
  531. AddCreature(msg, creature, known, removedKnown);
  532.  
  533. if (++count == 10) {
  534. return;
  535. }
  536. }
  537. }
  538. }
  539.  
  540. if (items) {
  541. for (auto it = items->getBeginDownItem(), end = items->getEndDownItem(); it != end; ++it) {
  542. msg.addItem(*it);
  543.  
  544. if (++count == 10) {
  545. return;
  546. }
  547. }
  548. }
  549. }
  550.  
  551. void ProtocolGame::GetMapDescription(int32_t x, int32_t y, int32_t z, int32_t width, int32_t height, NetworkMessage& msg)
  552. {
  553. int32_t skip = -1;
  554. int32_t startz, endz, zstep;
  555.  
  556. if (z > 7) {
  557. startz = z - 2;
  558. endz = std::min<int32_t>(MAP_MAX_LAYERS - 1, z + 2);
  559. zstep = 1;
  560. } else {
  561. startz = 7;
  562. endz = 0;
  563. zstep = -1;
  564. }
  565.  
  566. for (int32_t nz = startz; nz != endz + zstep; nz += zstep) {
  567. GetFloorDescription(msg, x, y, nz, width, height, z - nz, skip);
  568. }
  569.  
  570. if (skip >= 0) {
  571. msg.addByte(skip);
  572. msg.addByte(0xFF);
  573. }
  574. }
  575.  
  576. void ProtocolGame::GetFloorDescription(NetworkMessage& msg, int32_t x, int32_t y, int32_t z, int32_t width, int32_t height, int32_t offset, int32_t& skip)
  577. {
  578. for (int32_t nx = 0; nx < width; nx++) {
  579. for (int32_t ny = 0; ny < height; ny++) {
  580. Tile* tile = g_game.map.getTile(x + nx + offset, y + ny + offset, z);
  581. if (tile) {
  582. if (skip >= 0) {
  583. msg.addByte(skip);
  584. msg.addByte(0xFF);
  585. }
  586.  
  587. skip = 0;
  588. GetTileDescription(tile, msg);
  589. } else if (skip == 0xFE) {
  590. msg.addByte(0xFF);
  591. msg.addByte(0xFF);
  592. skip = -1;
  593. } else {
  594. ++skip;
  595. }
  596. }
  597. }
  598. }
  599.  
  600. void ProtocolGame::checkCreatureAsKnown(uint32_t id, bool& known, uint32_t& removedKnown)
  601. {
  602. auto result = knownCreatureSet.insert(id);
  603. if (!result.second) {
  604. known = true;
  605. return;
  606. }
  607.  
  608. known = false;
  609.  
  610. if (knownCreatureSet.size() > 250) {
  611. // Look for a creature to remove
  612. for (auto it = knownCreatureSet.begin(), end = knownCreatureSet.end(); it != end; ++it) {
  613. Creature* creature = g_game.getCreatureByID(*it);
  614. if (!canSee(creature)) {
  615. removedKnown = *it;
  616. knownCreatureSet.erase(it);
  617. return;
  618. }
  619. }
  620.  
  621. // Bad situation. Let's just remove anyone.
  622. auto it = knownCreatureSet.begin();
  623. if (*it == id) {
  624. ++it;
  625. }
  626.  
  627. removedKnown = *it;
  628. knownCreatureSet.erase(it);
  629. } else {
  630. removedKnown = 0;
  631. }
  632. }
  633.  
  634. bool ProtocolGame::canSee(const Creature* c) const
  635. {
  636. if (!c || !player || c->isRemoved()) {
  637. return false;
  638. }
  639.  
  640. if (!player->canSeeCreature(c)) {
  641. return false;
  642. }
  643.  
  644. return canSee(c->getPosition());
  645. }
  646.  
  647. bool ProtocolGame::canSee(const Position& pos) const
  648. {
  649. return canSee(pos.x, pos.y, pos.z);
  650. }
  651.  
  652. bool ProtocolGame::canSee(int32_t x, int32_t y, int32_t z) const
  653. {
  654. if (!player) {
  655. return false;
  656. }
  657.  
  658. const Position& myPos = player->getPosition();
  659. if (myPos.z <= 7) {
  660. //we are on ground level or above (7 -> 0)
  661. //view is from 7 -> 0
  662. if (z > 7) {
  663. return false;
  664. }
  665. } else if (myPos.z >= 8) {
  666. //we are underground (8 -> 15)
  667. //view is +/- 2 from the floor we stand on
  668. if (std::abs(myPos.getZ() - z) > 2) {
  669. return false;
  670. }
  671. }
  672.  
  673. //negative offset means that the action taken place is on a lower floor than ourself
  674. int32_t offsetz = myPos.getZ() - z;
  675. if ((x >= myPos.getX() - 8 + offsetz) && (x <= myPos.getX() + 9 + offsetz) &&
  676. (y >= myPos.getY() - 6 + offsetz) && (y <= myPos.getY() + 7 + offsetz)) {
  677. return true;
  678. }
  679. return false;
  680. }
  681.  
  682. // Parse methods
  683. void ProtocolGame::parseChannelInvite(NetworkMessage& msg)
  684. {
  685. const std::string name = msg.getString();
  686. addGameTask(&Game::playerChannelInvite, player->getID(), name);
  687. }
  688.  
  689. void ProtocolGame::parseChannelExclude(NetworkMessage& msg)
  690. {
  691. const std::string name = msg.getString();
  692. addGameTask(&Game::playerChannelExclude, player->getID(), name);
  693. }
  694.  
  695. void ProtocolGame::parseOpenChannel(NetworkMessage& msg)
  696. {
  697. uint16_t channelId = msg.get<uint16_t>();
  698. addGameTask(&Game::playerOpenChannel, player->getID(), channelId);
  699. }
  700.  
  701. void ProtocolGame::parseCloseChannel(NetworkMessage& msg)
  702. {
  703. uint16_t channelId = msg.get<uint16_t>();
  704. addGameTask(&Game::playerCloseChannel, player->getID(), channelId);
  705. }
  706.  
  707. void ProtocolGame::parseOpenPrivateChannel(NetworkMessage& msg)
  708. {
  709. const std::string receiver = msg.getString();
  710. addGameTask(&Game::playerOpenPrivateChannel, player->getID(), receiver);
  711. }
  712.  
  713. void ProtocolGame::parseAutoWalk(NetworkMessage& msg)
  714. {
  715. uint8_t numdirs = msg.getByte();
  716. if (numdirs == 0 || (msg.getBufferPosition() + numdirs) != (msg.getLength() + 8)) {
  717. return;
  718. }
  719.  
  720. msg.skipBytes(numdirs);
  721.  
  722. std::forward_list<Direction> path;
  723. for (uint8_t i = 0; i < numdirs; ++i) {
  724. uint8_t rawdir = msg.getPreviousByte();
  725. switch (rawdir) {
  726. case 1: path.push_front(DIRECTION_EAST); break;
  727. case 2: path.push_front(DIRECTION_NORTHEAST); break;
  728. case 3: path.push_front(DIRECTION_NORTH); break;
  729. case 4: path.push_front(DIRECTION_NORTHWEST); break;
  730. case 5: path.push_front(DIRECTION_WEST); break;
  731. case 6: path.push_front(DIRECTION_SOUTHWEST); break;
  732. case 7: path.push_front(DIRECTION_SOUTH); break;
  733. case 8: path.push_front(DIRECTION_SOUTHEAST); break;
  734. default: break;
  735. }
  736. }
  737.  
  738. if (path.empty()) {
  739. return;
  740. }
  741.  
  742. addGameTask(&Game::playerAutoWalk, player->getID(), path);
  743. }
  744.  
  745. void ProtocolGame::parseSetOutfit(NetworkMessage& msg)
  746. {
  747. Outfit_t newOutfit;
  748. newOutfit.lookType = msg.get<uint16_t>();
  749. newOutfit.lookHead = msg.getByte();
  750. newOutfit.lookBody = msg.getByte();
  751. newOutfit.lookLegs = msg.getByte();
  752. newOutfit.lookFeet = msg.getByte();
  753. newOutfit.lookAddons = msg.getByte();
  754. addGameTask(&Game::playerChangeOutfit, player->getID(), newOutfit);
  755. }
  756.  
  757. void ProtocolGame::parseUseItem(NetworkMessage& msg)
  758. {
  759. Position pos = msg.getPosition();
  760. uint16_t spriteId = msg.get<uint16_t>();
  761. uint8_t stackpos = msg.getByte();
  762. uint8_t index = msg.getByte();
  763. addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseItem, player->getID(), pos, stackpos, index, spriteId);
  764. }
  765.  
  766. void ProtocolGame::parseUseItemEx(NetworkMessage& msg)
  767. {
  768. Position fromPos = msg.getPosition();
  769. uint16_t fromSpriteId = msg.get<uint16_t>();
  770. uint8_t fromStackPos = msg.getByte();
  771. Position toPos = msg.getPosition();
  772. uint16_t toSpriteId = msg.get<uint16_t>();
  773. uint8_t toStackPos = msg.getByte();
  774. addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseItemEx, player->getID(), fromPos, fromStackPos, fromSpriteId, toPos, toStackPos, toSpriteId);
  775. }
  776.  
  777. void ProtocolGame::parseUseWithCreature(NetworkMessage& msg)
  778. {
  779. Position fromPos = msg.getPosition();
  780. uint16_t spriteId = msg.get<uint16_t>();
  781. uint8_t fromStackPos = msg.getByte();
  782. uint32_t creatureId = msg.get<uint32_t>();
  783. addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseWithCreature, player->getID(), fromPos, fromStackPos, creatureId, spriteId);
  784. }
  785.  
  786. void ProtocolGame::parseCloseContainer(NetworkMessage& msg)
  787. {
  788. uint8_t cid = msg.getByte();
  789. addGameTask(&Game::playerCloseContainer, player->getID(), cid);
  790. }
  791.  
  792. void ProtocolGame::parseUpArrowContainer(NetworkMessage& msg)
  793. {
  794. uint8_t cid = msg.getByte();
  795. addGameTask(&Game::playerMoveUpContainer, player->getID(), cid);
  796. }
  797.  
  798. void ProtocolGame::parseUpdateContainer(NetworkMessage& msg)
  799. {
  800. uint8_t cid = msg.getByte();
  801. addGameTask(&Game::playerUpdateContainer, player->getID(), cid);
  802. }
  803.  
  804. void ProtocolGame::parseThrow(NetworkMessage& msg)
  805. {
  806. Position fromPos = msg.getPosition();
  807. uint16_t spriteId = msg.get<uint16_t>();
  808. uint8_t fromStackpos = msg.getByte();
  809. Position toPos = msg.getPosition();
  810. uint8_t count = msg.getByte();
  811.  
  812. if (toPos != fromPos) {
  813. addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerMoveThing, player->getID(), fromPos, spriteId, fromStackpos, toPos, count);
  814. }
  815. }
  816.  
  817. void ProtocolGame::parseLookAt(NetworkMessage& msg)
  818. {
  819. Position pos = msg.getPosition();
  820. msg.skipBytes(2); // spriteId
  821. uint8_t stackpos = msg.getByte();
  822. addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookAt, player->getID(), pos, stackpos);
  823. }
  824.  
  825. void ProtocolGame::parseLookInBattleList(NetworkMessage& msg)
  826. {
  827. uint32_t creatureId = msg.get<uint32_t>();
  828. addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookInBattleList, player->getID(), creatureId);
  829. }
  830.  
  831. void ProtocolGame::parseSay(NetworkMessage& msg)
  832. {
  833. std::string receiver;
  834. uint16_t channelId;
  835.  
  836. SpeakClasses type = static_cast<SpeakClasses>(msg.getByte());
  837. switch (type) {
  838. case TALKTYPE_PRIVATE:
  839. case TALKTYPE_PRIVATE_RED:
  840. receiver = msg.getString();
  841. channelId = 0;
  842. break;
  843.  
  844. case TALKTYPE_CHANNEL_Y:
  845. case TALKTYPE_CHANNEL_R1:
  846. case TALKTYPE_CHANNEL_R2:
  847. channelId = msg.get<uint16_t>();
  848. break;
  849.  
  850. default:
  851. channelId = 0;
  852. break;
  853. }
  854.  
  855. const std::string text = msg.getString();
  856. if (text.length() > 255) {
  857. return;
  858. }
  859.  
  860. addGameTask(&Game::playerSay, player->getID(), channelId, type, receiver, text);
  861. }
  862.  
  863. void ProtocolGame::parseFightModes(NetworkMessage& msg)
  864. {
  865. uint8_t rawFightMode = msg.getByte(); // 1 - offensive, 2 - balanced, 3 - defensive
  866. uint8_t rawChaseMode = msg.getByte(); // 0 - stand while fightning, 1 - chase opponent
  867. uint8_t rawSecureMode = msg.getByte(); // 0 - can't attack unmarked, 1 - can attack unmarked
  868.  
  869. fightMode_t fightMode;
  870. if (rawFightMode == 1) {
  871. fightMode = FIGHTMODE_ATTACK;
  872. } else if (rawFightMode == 2) {
  873. fightMode = FIGHTMODE_BALANCED;
  874. } else {
  875. fightMode = FIGHTMODE_DEFENSE;
  876. }
  877.  
  878. addGameTask(&Game::playerSetFightModes, player->getID(), fightMode, rawChaseMode != 0, rawSecureMode != 0);
  879. }
  880.  
  881. void ProtocolGame::parseAttack(NetworkMessage& msg)
  882. {
  883. uint32_t creatureId = msg.get<uint32_t>();
  884. // msg.get<uint32_t>(); creatureId (same as above)
  885. addGameTask(&Game::playerSetAttackedCreature, player->getID(), creatureId);
  886. }
  887.  
  888. void ProtocolGame::parseFollow(NetworkMessage& msg)
  889. {
  890. uint32_t creatureId = msg.get<uint32_t>();
  891. // msg.get<uint32_t>(); creatureId (same as above)
  892. addGameTask(&Game::playerFollowCreature, player->getID(), creatureId);
  893. }
  894.  
  895. void ProtocolGame::parseTextWindow(NetworkMessage& msg)
  896. {
  897. uint32_t windowTextId = msg.get<uint32_t>();
  898. const std::string newText = msg.getString();
  899. addGameTask(&Game::playerWriteItem, player->getID(), windowTextId, newText);
  900. }
  901.  
  902. void ProtocolGame::parseHouseWindow(NetworkMessage& msg)
  903. {
  904. uint8_t doorId = msg.getByte();
  905. uint32_t id = msg.get<uint32_t>();
  906. const std::string text = msg.getString();
  907. addGameTask(&Game::playerUpdateHouseWindow, player->getID(), doorId, id, text);
  908. }
  909.  
  910. void ProtocolGame::parseLookInShop(NetworkMessage& msg)
  911. {
  912. uint16_t id = msg.get<uint16_t>();
  913. uint8_t count = msg.getByte();
  914. addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookInShop, player->getID(), id, count);
  915. }
  916.  
  917. void ProtocolGame::parsePlayerPurchase(NetworkMessage& msg)
  918. {
  919. uint16_t id = msg.get<uint16_t>();
  920. uint8_t count = msg.getByte();
  921. uint8_t amount = msg.getByte();
  922. bool ignoreCap = msg.getByte() != 0;
  923. bool inBackpacks = msg.getByte() != 0;
  924. addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerPurchaseItem, player->getID(), id, count, amount, ignoreCap, inBackpacks);
  925. }
  926.  
  927. void ProtocolGame::parsePlayerSale(NetworkMessage& msg)
  928. {
  929. uint16_t id = msg.get<uint16_t>();
  930. uint8_t count = msg.getByte();
  931. uint8_t amount = msg.getByte();
  932. bool ignoreEquipped = msg.getByte() != 0;
  933. addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerSellItem, player->getID(), id, count, amount, ignoreEquipped);
  934. }
  935.  
  936. void ProtocolGame::parseRequestTrade(NetworkMessage& msg)
  937. {
  938. Position pos = msg.getPosition();
  939. uint16_t spriteId = msg.get<uint16_t>();
  940. uint8_t stackpos = msg.getByte();
  941. uint32_t playerId = msg.get<uint32_t>();
  942. addGameTask(&Game::playerRequestTrade, player->getID(), pos, stackpos, playerId, spriteId);
  943. }
  944.  
  945. void ProtocolGame::parseLookInTrade(NetworkMessage& msg)
  946. {
  947. bool counterOffer = (msg.getByte() == 0x01);
  948. uint8_t index = msg.getByte();
  949. addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookInTrade, player->getID(), counterOffer, index);
  950. }
  951.  
  952. void ProtocolGame::parseAddVip(NetworkMessage& msg)
  953. {
  954. const std::string name = msg.getString();
  955. addGameTask(&Game::playerRequestAddVip, player->getID(), name);
  956. }
  957.  
  958. void ProtocolGame::parseRemoveVip(NetworkMessage& msg)
  959. {
  960. uint32_t guid = msg.get<uint32_t>();
  961. addGameTask(&Game::playerRequestRemoveVip, player->getID(), guid);
  962. }
  963.  
  964. void ProtocolGame::parseRotateItem(NetworkMessage& msg)
  965. {
  966. Position pos = msg.getPosition();
  967. uint16_t spriteId = msg.get<uint16_t>();
  968. uint8_t stackpos = msg.getByte();
  969. addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerRotateItem, player->getID(), pos, stackpos, spriteId);
  970. }
  971.  
  972. void ProtocolGame::parseBugReport(NetworkMessage& msg)
  973. {
  974. uint8_t category = msg.getByte();
  975. std::string message = msg.getString();
  976.  
  977. Position position;
  978. if (category == BUG_CATEGORY_MAP) {
  979. position = msg.getPosition();
  980. }
  981.  
  982. addGameTask(&Game::playerReportBug, player->getID(), message, position, category);
  983. }
  984.  
  985. void ProtocolGame::parseDebugAssert(NetworkMessage& msg)
  986. {
  987. if (debugAssertSent) {
  988. return;
  989. }
  990.  
  991. debugAssertSent = true;
  992.  
  993. std::string assertLine = msg.getString();
  994. std::string date = msg.getString();
  995. std::string description = msg.getString();
  996. std::string comment = msg.getString();
  997. addGameTask(&Game::playerDebugAssert, player->getID(), assertLine, date, description, comment);
  998. }
  999.  
  1000. void ProtocolGame::parseInviteToParty(NetworkMessage& msg)
  1001. {
  1002. uint32_t targetId = msg.get<uint32_t>();
  1003. addGameTask(&Game::playerInviteToParty, player->getID(), targetId);
  1004. }
  1005.  
  1006. void ProtocolGame::parseJoinParty(NetworkMessage& msg)
  1007. {
  1008. uint32_t targetId = msg.get<uint32_t>();
  1009. addGameTask(&Game::playerJoinParty, player->getID(), targetId);
  1010. }
  1011.  
  1012. void ProtocolGame::parseRevokePartyInvite(NetworkMessage& msg)
  1013. {
  1014. uint32_t targetId = msg.get<uint32_t>();
  1015. addGameTask(&Game::playerRevokePartyInvitation, player->getID(), targetId);
  1016. }
  1017.  
  1018. void ProtocolGame::parsePassPartyLeadership(NetworkMessage& msg)
  1019. {
  1020. uint32_t targetId = msg.get<uint32_t>();
  1021. addGameTask(&Game::playerPassPartyLeadership, player->getID(), targetId);
  1022. }
  1023.  
  1024. void ProtocolGame::parseEnableSharedPartyExperience(NetworkMessage& msg)
  1025. {
  1026. bool sharedExpActive = msg.getByte() == 1;
  1027. addGameTask(&Game::playerEnableSharedPartyExperience, player->getID(), sharedExpActive);
  1028. }
  1029.  
  1030. void ProtocolGame::parseQuestLine(NetworkMessage& msg)
  1031. {
  1032. uint16_t questId = msg.get<uint16_t>();
  1033. addGameTask(&Game::playerShowQuestLine, player->getID(), questId);
  1034. }
  1035.  
  1036. // Send methods
  1037. void ProtocolGame::sendOpenPrivateChannel(const std::string& receiver)
  1038. {
  1039. NetworkMessage msg;
  1040. msg.addByte(0xAD);
  1041. msg.addString(receiver);
  1042. writeToOutputBuffer(msg);
  1043. }
  1044.  
  1045. void ProtocolGame::sendCreatureOutfit(const Creature* creature, const Outfit_t& outfit)
  1046. {
  1047. if (!canSee(creature)) {
  1048. return;
  1049. }
  1050.  
  1051. NetworkMessage msg;
  1052. msg.addByte(0x8E);
  1053. msg.add<uint32_t>(creature->getID());
  1054. AddOutfit(msg, outfit);
  1055. writeToOutputBuffer(msg);
  1056. }
  1057.  
  1058. void ProtocolGame::sendCreatureLight(const Creature* creature)
  1059. {
  1060. if (!canSee(creature)) {
  1061. return;
  1062. }
  1063.  
  1064. NetworkMessage msg;
  1065. AddCreatureLight(msg, creature);
  1066. writeToOutputBuffer(msg);
  1067. }
  1068.  
  1069. void ProtocolGame::sendWorldLight(const LightInfo& lightInfo)
  1070. {
  1071. NetworkMessage msg;
  1072. AddWorldLight(msg, lightInfo);
  1073. writeToOutputBuffer(msg);
  1074. }
  1075.  
  1076. void ProtocolGame::sendCreatureWalkthrough(const Creature* creature, bool walkthrough)
  1077. {
  1078. if (!canSee(creature)) {
  1079. return;
  1080. }
  1081.  
  1082. NetworkMessage msg;
  1083. msg.addByte(0x92);
  1084. msg.add<uint32_t>(creature->getID());
  1085. msg.addByte(walkthrough ? 0x00 : 0x01);
  1086. writeToOutputBuffer(msg);
  1087. }
  1088.  
  1089. void ProtocolGame::sendCreatureShield(const Creature* creature)
  1090. {
  1091. if (!canSee(creature)) {
  1092. return;
  1093. }
  1094.  
  1095. NetworkMessage msg;
  1096. msg.addByte(0x91);
  1097. msg.add<uint32_t>(creature->getID());
  1098. msg.addByte(player->getPartyShield(creature->getPlayer()));
  1099. writeToOutputBuffer(msg);
  1100. }
  1101.  
  1102. void ProtocolGame::sendCreatureSkull(const Creature* creature)
  1103. {
  1104. if (g_game.getWorldType() != WORLD_TYPE_PVP) {
  1105. return;
  1106. }
  1107.  
  1108. if (!canSee(creature)) {
  1109. return;
  1110. }
  1111.  
  1112. NetworkMessage msg;
  1113. msg.addByte(0x90);
  1114. msg.add<uint32_t>(creature->getID());
  1115. msg.addByte(player->getSkullClient(creature));
  1116. writeToOutputBuffer(msg);
  1117. }
  1118.  
  1119. void ProtocolGame::sendCreatureSquare(const Creature* creature, SquareColor_t color)
  1120. {
  1121. if (!canSee(creature)) {
  1122. return;
  1123. }
  1124.  
  1125. NetworkMessage msg;
  1126. msg.addByte(0x86);
  1127. msg.add<uint32_t>(creature->getID());
  1128. msg.addByte(color);
  1129. writeToOutputBuffer(msg);
  1130. }
  1131.  
  1132. void ProtocolGame::sendTutorial(uint8_t tutorialId)
  1133. {
  1134. NetworkMessage msg;
  1135. msg.addByte(0xDC);
  1136. msg.addByte(tutorialId);
  1137. writeToOutputBuffer(msg);
  1138. }
  1139.  
  1140. void ProtocolGame::sendAddMarker(const Position& pos, uint8_t markType, const std::string& desc)
  1141. {
  1142. NetworkMessage msg;
  1143. msg.addByte(0xDD);
  1144. msg.addPosition(pos);
  1145. msg.addByte(markType);
  1146. msg.addString(desc);
  1147. writeToOutputBuffer(msg);
  1148. }
  1149.  
  1150. void ProtocolGame::sendReLoginWindow()
  1151. {
  1152. NetworkMessage msg;
  1153. msg.addByte(0x28);
  1154. writeToOutputBuffer(msg);
  1155. }
  1156.  
  1157. void ProtocolGame::sendStats()
  1158. {
  1159. NetworkMessage msg;
  1160. AddPlayerStats(msg);
  1161. writeToOutputBuffer(msg);
  1162. }
  1163.  
  1164. void ProtocolGame::sendTextMessage(const TextMessage& message)
  1165. {
  1166. NetworkMessage msg;
  1167. msg.addByte(0xB4);
  1168. msg.addByte(message.type);
  1169. msg.addString(message.text);
  1170. writeToOutputBuffer(msg);
  1171. }
  1172.  
  1173. void ProtocolGame::sendClosePrivate(uint16_t channelId)
  1174. {
  1175. NetworkMessage msg;
  1176. msg.addByte(0xB3);
  1177. msg.add<uint16_t>(channelId);
  1178. writeToOutputBuffer(msg);
  1179. }
  1180.  
  1181. void ProtocolGame::sendCreatePrivateChannel(uint16_t channelId, const std::string& channelName)
  1182. {
  1183. NetworkMessage msg;
  1184. msg.addByte(0xB2);
  1185. msg.add<uint16_t>(channelId);
  1186. msg.addString(channelName);
  1187. writeToOutputBuffer(msg);
  1188. }
  1189.  
  1190. void ProtocolGame::sendChannelsDialog()
  1191. {
  1192. NetworkMessage msg;
  1193. msg.addByte(0xAB);
  1194.  
  1195. const ChannelList& list = g_chat->getChannelList(*player);
  1196. msg.addByte(list.size());
  1197. for (ChatChannel* channel : list) {
  1198. msg.add<uint16_t>(channel->getId());
  1199. msg.addString(channel->getName());
  1200. }
  1201.  
  1202. writeToOutputBuffer(msg);
  1203. }
  1204.  
  1205. void ProtocolGame::sendChannel(uint16_t channelId, const std::string& channelName)
  1206. {
  1207. NetworkMessage msg;
  1208. msg.addByte(0xAC);
  1209.  
  1210. msg.add<uint16_t>(channelId);
  1211. msg.addString(channelName);
  1212. writeToOutputBuffer(msg);
  1213. }
  1214.  
  1215. void ProtocolGame::sendChannelMessage(const std::string& author, const std::string& text, SpeakClasses type, uint16_t channel)
  1216. {
  1217. NetworkMessage msg;
  1218. msg.addByte(0xAA);
  1219. msg.add<uint32_t>(0x00);
  1220. msg.addString(author);
  1221. msg.add<uint16_t>(0x00);
  1222. msg.addByte(type);
  1223. msg.add<uint16_t>(channel);
  1224. msg.addString(text);
  1225. writeToOutputBuffer(msg);
  1226. }
  1227.  
  1228. void ProtocolGame::sendIcons(uint16_t icons)
  1229. {
  1230. NetworkMessage msg;
  1231. msg.addByte(0xA2);
  1232. msg.add<uint16_t>(icons);
  1233. writeToOutputBuffer(msg);
  1234. }
  1235.  
  1236. void ProtocolGame::sendContainer(uint8_t cid, const Container* container, bool hasParent, uint16_t firstIndex)
  1237. {
  1238. NetworkMessage msg;
  1239. msg.addByte(0x6E);
  1240.  
  1241. msg.addByte(cid);
  1242.  
  1243. msg.addItem(container);
  1244. msg.addString(container->getName());
  1245.  
  1246. msg.addByte(container->capacity());
  1247.  
  1248. msg.addByte(hasParent ? 0x01 : 0x00);
  1249.  
  1250. msg.addByte(std::min<uint32_t>(0xFF, container->size()));
  1251.  
  1252. uint32_t i = 0;
  1253. const ItemDeque& itemList = container->getItemList();
  1254. for (ItemDeque::const_iterator cit = itemList.begin() + firstIndex, end = itemList.end(); i < 0xFF && cit != end; ++cit, ++i) {
  1255. msg.addItem(*cit);
  1256. }
  1257. writeToOutputBuffer(msg);
  1258. }
  1259.  
  1260. void ProtocolGame::sendShop(Npc*, const ShopInfoList& itemList)
  1261. {
  1262. NetworkMessage msg;
  1263. msg.addByte(0x7A);
  1264.  
  1265. uint16_t itemsToSend = std::min<size_t>(itemList.size(), std::numeric_limits<uint16_t>::max());
  1266. msg.addByte(itemsToSend);
  1267.  
  1268. uint16_t i = 0;
  1269. for (auto it = itemList.begin(); i < itemsToSend; ++it, ++i) {
  1270. AddShopItem(msg, *it);
  1271. }
  1272.  
  1273. writeToOutputBuffer(msg);
  1274. }
  1275.  
  1276. void ProtocolGame::sendCloseShop()
  1277. {
  1278. NetworkMessage msg;
  1279. msg.addByte(0x7C);
  1280. writeToOutputBuffer(msg);
  1281. }
  1282.  
  1283. void ProtocolGame::sendSaleItemList(const std::list<ShopInfo>& shop)
  1284. {
  1285. NetworkMessage msg;
  1286. msg.addByte(0x7B);
  1287. msg.add<uint32_t>(player->getMoney());
  1288.  
  1289. std::map<uint16_t, uint32_t> saleMap;
  1290.  
  1291. if (shop.size() <= 5) {
  1292. // For very small shops it's not worth it to create the complete map
  1293. for (const ShopInfo& shopInfo : shop) {
  1294. if (shopInfo.sellPrice == 0) {
  1295. continue;
  1296. }
  1297.  
  1298. int8_t subtype = -1;
  1299.  
  1300. const ItemType& itemType = Item::items[shopInfo.itemId];
  1301. if (itemType.hasSubType() && !itemType.stackable) {
  1302. subtype = (shopInfo.subType == 0 ? -1 : shopInfo.subType);
  1303. }
  1304.  
  1305. uint32_t count = player->getItemTypeCount(shopInfo.itemId, subtype);
  1306. if (count > 0) {
  1307. saleMap[shopInfo.itemId] = count;
  1308. }
  1309. }
  1310. } else {
  1311. // Large shop, it's better to get a cached map of all item counts and use it
  1312. // We need a temporary map since the finished map should only contain items
  1313. // available in the shop
  1314. std::map<uint32_t, uint32_t> tempSaleMap;
  1315. player->getAllItemTypeCount(tempSaleMap);
  1316.  
  1317. // We must still check manually for the special items that require subtype matches
  1318. // (That is, fluids such as potions etc., actually these items are very few since
  1319. // health potions now use their own ID)
  1320. for (const ShopInfo& shopInfo : shop) {
  1321. if (shopInfo.sellPrice == 0) {
  1322. continue;
  1323. }
  1324.  
  1325. int8_t subtype = -1;
  1326.  
  1327. const ItemType& itemType = Item::items[shopInfo.itemId];
  1328. if (itemType.hasSubType() && !itemType.stackable) {
  1329. subtype = (shopInfo.subType == 0 ? -1 : shopInfo.subType);
  1330. }
  1331.  
  1332. if (subtype != -1) {
  1333. uint32_t count;
  1334. if (!itemType.isFluidContainer() && !itemType.isSplash()) {
  1335. count = player->getItemTypeCount(shopInfo.itemId, subtype); // This shop item requires extra checks
  1336. } else {
  1337. count = subtype;
  1338. }
  1339.  
  1340. if (count > 0) {
  1341. saleMap[shopInfo.itemId] = count;
  1342. }
  1343. } else {
  1344. std::map<uint32_t, uint32_t>::const_iterator findIt = tempSaleMap.find(shopInfo.itemId);
  1345. if (findIt != tempSaleMap.end() && findIt->second > 0) {
  1346. saleMap[shopInfo.itemId] = findIt->second;
  1347. }
  1348. }
  1349. }
  1350. }
  1351.  
  1352. uint8_t itemsToSend = std::min<size_t>(saleMap.size(), std::numeric_limits<uint8_t>::max());
  1353. msg.addByte(itemsToSend);
  1354.  
  1355. uint8_t i = 0;
  1356. for (std::map<uint16_t, uint32_t>::const_iterator it = saleMap.begin(); i < itemsToSend; ++it, ++i) {
  1357. msg.addItemId(it->first);
  1358. msg.addByte(std::min<uint32_t>(it->second, std::numeric_limits<uint8_t>::max()));
  1359. }
  1360.  
  1361. writeToOutputBuffer(msg);
  1362. }
  1363.  
  1364. void ProtocolGame::sendQuestLog()
  1365. {
  1366. NetworkMessage msg;
  1367. msg.addByte(0xF0);
  1368. msg.add<uint16_t>(g_game.quests.getQuestsCount(player));
  1369.  
  1370. for (const Quest& quest : g_game.quests.getQuests()) {
  1371. if (quest.isStarted(player)) {
  1372. msg.add<uint16_t>(quest.getID());
  1373. msg.addString(quest.getName());
  1374. msg.addByte(quest.isCompleted(player));
  1375. }
  1376. }
  1377.  
  1378. writeToOutputBuffer(msg);
  1379. }
  1380.  
  1381. void ProtocolGame::sendQuestLine(const Quest* quest)
  1382. {
  1383. NetworkMessage msg;
  1384. msg.addByte(0xF1);
  1385. msg.add<uint16_t>(quest->getID());
  1386. msg.addByte(quest->getMissionsCount(player));
  1387.  
  1388. for (const Mission& mission : quest->getMissions()) {
  1389. if (mission.isStarted(player)) {
  1390. msg.addString(mission.getName(player));
  1391. msg.addString(mission.getDescription(player));
  1392. }
  1393. }
  1394.  
  1395. writeToOutputBuffer(msg);
  1396. }
  1397.  
  1398. void ProtocolGame::sendTradeItemRequest(const std::string& traderName, const Item* item, bool ack)
  1399. {
  1400. NetworkMessage msg;
  1401.  
  1402. if (ack) {
  1403. msg.addByte(0x7D);
  1404. } else {
  1405. msg.addByte(0x7E);
  1406. }
  1407.  
  1408. msg.addString(traderName);
  1409.  
  1410. if (const Container* tradeContainer = item->getContainer()) {
  1411. std::list<const Container*> listContainer {tradeContainer};
  1412. std::list<const Item*> itemList {tradeContainer};
  1413. while (!listContainer.empty()) {
  1414. const Container* container = listContainer.front();
  1415. listContainer.pop_front();
  1416.  
  1417. for (Item* containerItem : container->getItemList()) {
  1418. Container* tmpContainer = containerItem->getContainer();
  1419. if (tmpContainer) {
  1420. listContainer.push_back(tmpContainer);
  1421. }
  1422. itemList.push_back(containerItem);
  1423. }
  1424. }
  1425.  
  1426. msg.addByte(itemList.size());
  1427. for (const Item* listItem : itemList) {
  1428. msg.addItem(listItem);
  1429. }
  1430. } else {
  1431. msg.addByte(0x01);
  1432. msg.addItem(item);
  1433. }
  1434. writeToOutputBuffer(msg);
  1435. }
  1436.  
  1437. void ProtocolGame::sendCloseTrade()
  1438. {
  1439. NetworkMessage msg;
  1440. msg.addByte(0x7F);
  1441. writeToOutputBuffer(msg);
  1442. }
  1443.  
  1444. void ProtocolGame::sendCloseContainer(uint8_t cid)
  1445. {
  1446. NetworkMessage msg;
  1447. msg.addByte(0x6F);
  1448. msg.addByte(cid);
  1449. writeToOutputBuffer(msg);
  1450. }
  1451.  
  1452. void ProtocolGame::sendCreatureTurn(const Creature* creature, uint32_t stackPos)
  1453. {
  1454. if (!canSee(creature)) {
  1455. return;
  1456. }
  1457.  
  1458. NetworkMessage msg;
  1459. msg.addByte(0x6B);
  1460. msg.addPosition(creature->getPosition());
  1461. msg.addByte(stackPos);
  1462. msg.add<uint16_t>(0x63);
  1463. msg.add<uint32_t>(creature->getID());
  1464. msg.addByte(creature->getDirection());
  1465. writeToOutputBuffer(msg);
  1466. }
  1467.  
  1468. void ProtocolGame::sendCreatureSay(const Creature* creature, SpeakClasses type, const std::string& text, const Position* pos/* = nullptr*/)
  1469. {
  1470. if (!creature) {
  1471. return;
  1472. }
  1473.  
  1474. NetworkMessage msg;
  1475. msg.addByte(0xAA);
  1476. msg.add<uint32_t>(0x00);
  1477.  
  1478. msg.addString(creature->getName());
  1479.  
  1480. //Add level only for players
  1481. if (const Player* speaker = creature->getPlayer()) {
  1482. msg.add<uint16_t>(speaker->getLevel());
  1483. } else {
  1484. msg.add<uint16_t>(0x00);
  1485. }
  1486.  
  1487. msg.addByte(type);
  1488. if (pos) {
  1489. msg.addPosition(*pos);
  1490. } else {
  1491. msg.addPosition(creature->getPosition());
  1492. }
  1493.  
  1494. msg.addString(text);
  1495. writeToOutputBuffer(msg);
  1496. }
  1497.  
  1498. void ProtocolGame::sendToChannel(const Creature* creature, SpeakClasses type, const std::string& text, uint16_t channelId)
  1499. {
  1500. if (!creature) {
  1501. return;
  1502. }
  1503.  
  1504. NetworkMessage msg;
  1505. msg.addByte(0xAA);
  1506. msg.add<uint32_t>(0x00);
  1507.  
  1508. if (type == TALKTYPE_CHANNEL_R2) {
  1509. msg.addString("");
  1510. type = TALKTYPE_CHANNEL_R1;
  1511. } else {
  1512. msg.addString(creature->getName());
  1513. //Add level only for players
  1514. if (const Player* speaker = creature->getPlayer()) {
  1515. msg.add<uint16_t>(speaker->getLevel());
  1516. } else {
  1517. msg.add<uint16_t>(0x00);
  1518. }
  1519. }
  1520.  
  1521. msg.addByte(type);
  1522. msg.add<uint16_t>(channelId);
  1523. msg.addString(text);
  1524. writeToOutputBuffer(msg);
  1525. }
  1526.  
  1527. void ProtocolGame::sendPrivateMessage(const Player* speaker, SpeakClasses type, const std::string& text)
  1528. {
  1529. NetworkMessage msg;
  1530. msg.addByte(0xAA);
  1531. static uint32_t statementId = 0;
  1532. msg.add<uint32_t>(++statementId);
  1533. if (speaker) {
  1534. msg.addString(speaker->getName());
  1535. msg.add<uint16_t>(speaker->getLevel());
  1536. } else {
  1537. msg.add<uint32_t>(0x00);
  1538. }
  1539. msg.addByte(type);
  1540. msg.addString(text);
  1541. writeToOutputBuffer(msg);
  1542. }
  1543.  
  1544. void ProtocolGame::sendCancelTarget()
  1545. {
  1546. NetworkMessage msg;
  1547. msg.addByte(0xA3);
  1548. writeToOutputBuffer(msg);
  1549. }
  1550.  
  1551. void ProtocolGame::sendChangeSpeed(const Creature* creature, uint32_t speed)
  1552. {
  1553. NetworkMessage msg;
  1554. msg.addByte(0x8F);
  1555. msg.add<uint32_t>(creature->getID());
  1556. msg.add<uint16_t>(speed);
  1557. writeToOutputBuffer(msg);
  1558. }
  1559.  
  1560. void ProtocolGame::sendCancelWalk()
  1561. {
  1562. NetworkMessage msg;
  1563. msg.addByte(0xB5);
  1564. msg.addByte(player->getDirection());
  1565. writeToOutputBuffer(msg);
  1566. }
  1567.  
  1568. void ProtocolGame::sendSkills()
  1569. {
  1570. NetworkMessage msg;
  1571. AddPlayerSkills(msg);
  1572. writeToOutputBuffer(msg);
  1573. }
  1574.  
  1575. void ProtocolGame::sendPing()
  1576. {
  1577. NetworkMessage msg;
  1578. msg.addByte(0x1E);
  1579. writeToOutputBuffer(msg);
  1580. }
  1581.  
  1582. void ProtocolGame::sendDistanceShoot(const Position& from, const Position& to, uint8_t type)
  1583. {
  1584. NetworkMessage msg;
  1585. msg.addByte(0x85);
  1586. msg.addPosition(from);
  1587. msg.addPosition(to);
  1588. msg.addByte(type);
  1589. writeToOutputBuffer(msg);
  1590. }
  1591.  
  1592. void ProtocolGame::sendMagicEffect(const Position& pos, uint8_t type)
  1593. {
  1594. if (!canSee(pos)) {
  1595. return;
  1596. }
  1597.  
  1598. NetworkMessage msg;
  1599. msg.addByte(0x83);
  1600. msg.addPosition(pos);
  1601. msg.addByte(type);
  1602. writeToOutputBuffer(msg);
  1603. }
  1604.  
  1605. void ProtocolGame::sendCreatureHealth(const Creature* creature)
  1606. {
  1607. NetworkMessage msg;
  1608. msg.addByte(0x8C);
  1609. msg.add<uint32_t>(creature->getID());
  1610.  
  1611. if (creature->isHealthHidden()) {
  1612. msg.addByte(0x00);
  1613. } else {
  1614. msg.addByte(std::ceil((static_cast<double>(creature->getHealth()) / std::max<int32_t>(creature->getMaxHealth(), 1)) * 100));
  1615. }
  1616. writeToOutputBuffer(msg);
  1617. }
  1618.  
  1619. void ProtocolGame::sendFYIBox(const std::string& message)
  1620. {
  1621. NetworkMessage msg;
  1622. msg.addByte(0x15);
  1623. msg.addString(message);
  1624. writeToOutputBuffer(msg);
  1625. }
  1626.  
  1627. //tile
  1628. void ProtocolGame::sendMapDescription(const Position& pos)
  1629. {
  1630. NetworkMessage msg;
  1631. msg.addByte(0x64);
  1632. msg.addPosition(player->getPosition());
  1633. GetMapDescription(pos.x - 8, pos.y - 6, pos.z, 18, 14, msg);
  1634. writeToOutputBuffer(msg);
  1635. }
  1636.  
  1637. void ProtocolGame::sendAddTileItem(const Position& pos, uint32_t stackpos, const Item* item)
  1638. {
  1639. if (!canSee(pos)) {
  1640. return;
  1641. }
  1642.  
  1643. NetworkMessage msg;
  1644. msg.addByte(0x6A);
  1645. msg.addPosition(pos);
  1646. msg.addByte(stackpos);
  1647. msg.addItem(item);
  1648. writeToOutputBuffer(msg);
  1649. }
  1650.  
  1651. void ProtocolGame::sendUpdateTileItem(const Position& pos, uint32_t stackpos, const Item* item)
  1652. {
  1653. if (!canSee(pos)) {
  1654. return;
  1655. }
  1656.  
  1657. NetworkMessage msg;
  1658. msg.addByte(0x6B);
  1659. msg.addPosition(pos);
  1660. msg.addByte(stackpos);
  1661. msg.addItem(item);
  1662. writeToOutputBuffer(msg);
  1663. }
  1664.  
  1665. void ProtocolGame::sendRemoveTileThing(const Position& pos, uint32_t stackpos)
  1666. {
  1667. if (!canSee(pos)) {
  1668. return;
  1669. }
  1670.  
  1671. NetworkMessage msg;
  1672. RemoveTileThing(msg, pos, stackpos);
  1673. writeToOutputBuffer(msg);
  1674. }
  1675.  
  1676. void ProtocolGame::sendUpdateTile(const Tile* tile, const Position& pos)
  1677. {
  1678. if (!canSee(pos)) {
  1679. return;
  1680. }
  1681.  
  1682. NetworkMessage msg;
  1683. msg.addByte(0x69);
  1684. msg.addPosition(pos);
  1685.  
  1686. if (tile) {
  1687. GetTileDescription(tile, msg);
  1688. msg.addByte(0x00);
  1689. msg.addByte(0xFF);
  1690. } else {
  1691. msg.addByte(0x01);
  1692. msg.addByte(0xFF);
  1693. }
  1694.  
  1695. writeToOutputBuffer(msg);
  1696. }
  1697.  
  1698. void ProtocolGame::sendFightModes()
  1699. {
  1700. NetworkMessage msg;
  1701. msg.addByte(0xA7);
  1702. msg.addByte(player->fightMode);
  1703. msg.addByte(player->chaseMode);
  1704. msg.addByte(player->secureMode);
  1705. writeToOutputBuffer(msg);
  1706. }
  1707.  
  1708. void ProtocolGame::sendAddCreature(const Creature* creature, const Position& pos, int32_t stackpos, bool isLogin)
  1709. {
  1710. if (!canSee(pos)) {
  1711. return;
  1712. }
  1713.  
  1714. if (creature != player) {
  1715. if (stackpos != -1) {
  1716. NetworkMessage msg;
  1717. msg.addByte(0x6A);
  1718. msg.addPosition(pos);
  1719. msg.addByte(stackpos);
  1720.  
  1721. bool known;
  1722. uint32_t removedKnown;
  1723. checkCreatureAsKnown(creature->getID(), known, removedKnown);
  1724. AddCreature(msg, creature, known, removedKnown);
  1725. writeToOutputBuffer(msg);
  1726. }
  1727.  
  1728. if (isLogin) {
  1729. sendMagicEffect(pos, CONST_ME_TELEPORT);
  1730. }
  1731. return;
  1732. }
  1733.  
  1734. NetworkMessage msg;
  1735. msg.addByte(0x0A);
  1736.  
  1737. msg.add<uint32_t>(player->getID());
  1738. msg.add<uint16_t>(0x32); // beat duration (50)
  1739.  
  1740. // can report bugs?
  1741. if (player->getAccountType() >= ACCOUNT_TYPE_TUTOR) {
  1742. msg.addByte(0x01);
  1743. } else {
  1744. msg.addByte(0x00);
  1745. }
  1746.  
  1747. writeToOutputBuffer(msg);
  1748.  
  1749. sendMapDescription(pos);
  1750. loggedIn = true;
  1751.  
  1752. if (isLogin) {
  1753. sendMagicEffect(pos, CONST_ME_TELEPORT);
  1754. }
  1755.  
  1756. sendInventoryItem(CONST_SLOT_HEAD, player->getInventoryItem(CONST_SLOT_HEAD));
  1757. sendInventoryItem(CONST_SLOT_NECKLACE, player->getInventoryItem(CONST_SLOT_NECKLACE));
  1758. sendInventoryItem(CONST_SLOT_BACKPACK, player->getInventoryItem(CONST_SLOT_BACKPACK));
  1759. sendInventoryItem(CONST_SLOT_ARMOR, player->getInventoryItem(CONST_SLOT_ARMOR));
  1760. sendInventoryItem(CONST_SLOT_RIGHT, player->getInventoryItem(CONST_SLOT_RIGHT));
  1761. sendInventoryItem(CONST_SLOT_LEFT, player->getInventoryItem(CONST_SLOT_LEFT));
  1762. sendInventoryItem(CONST_SLOT_LEGS, player->getInventoryItem(CONST_SLOT_LEGS));
  1763. sendInventoryItem(CONST_SLOT_FEET, player->getInventoryItem(CONST_SLOT_FEET));
  1764. sendInventoryItem(CONST_SLOT_RING, player->getInventoryItem(CONST_SLOT_RING));
  1765. sendInventoryItem(CONST_SLOT_AMMO, player->getInventoryItem(CONST_SLOT_AMMO));
  1766.  
  1767. sendStats();
  1768. sendSkills();
  1769.  
  1770. //gameworld light-settings
  1771. LightInfo lightInfo;
  1772. g_game.getWorldLightInfo(lightInfo);
  1773. sendWorldLight(lightInfo);
  1774.  
  1775. //player light level
  1776. sendCreatureLight(creature);
  1777.  
  1778. const std::forward_list<VIPEntry>& vipEntries = IOLoginData::getVIPEntries(player->getAccount());
  1779. for (const VIPEntry& entry : vipEntries) {
  1780. Player* vipPlayer = g_game.getPlayerByGUID(entry.guid);
  1781.  
  1782. sendVIP(entry.guid, entry.name, (vipPlayer && (!vipPlayer->isInGhostMode() || player->isAccessPlayer())));
  1783. }
  1784.  
  1785. player->sendIcons();
  1786. }
  1787.  
  1788. void ProtocolGame::sendMoveCreature(const Creature* creature, const Position& newPos, int32_t newStackPos, const Position& oldPos, int32_t oldStackPos, bool teleport)
  1789. {
  1790. if (creature == player) {
  1791. if (oldStackPos >= 10) {
  1792. sendMapDescription(newPos);
  1793. } else if (teleport) {
  1794. NetworkMessage msg;
  1795. RemoveTileThing(msg, oldPos, oldStackPos);
  1796. writeToOutputBuffer(msg);
  1797. sendMapDescription(newPos);
  1798. } else {
  1799. NetworkMessage msg;
  1800. if (oldPos.z == 7 && newPos.z >= 8) {
  1801. RemoveTileThing(msg, oldPos, oldStackPos);
  1802. } else {
  1803. msg.addByte(0x6D);
  1804. msg.addPosition(oldPos);
  1805. msg.addByte(oldStackPos);
  1806. msg.addPosition(newPos);
  1807. }
  1808.  
  1809. if (newPos.z > oldPos.z) {
  1810. MoveDownCreature(msg, creature, newPos, oldPos);
  1811. } else if (newPos.z < oldPos.z) {
  1812. MoveUpCreature(msg, creature, newPos, oldPos);
  1813. }
  1814.  
  1815. if (oldPos.y > newPos.y) { // north, for old x
  1816. msg.addByte(0x65);
  1817. GetMapDescription(oldPos.x - 8, newPos.y - 6, newPos.z, 18, 1, msg);
  1818. } else if (oldPos.y < newPos.y) { // south, for old x
  1819. msg.addByte(0x67);
  1820. GetMapDescription(oldPos.x - 8, newPos.y + 7, newPos.z, 18, 1, msg);
  1821. }
  1822.  
  1823. if (oldPos.x < newPos.x) { // east, [with new y]
  1824. msg.addByte(0x66);
  1825. GetMapDescription(newPos.x + 9, newPos.y - 6, newPos.z, 1, 14, msg);
  1826. } else if (oldPos.x > newPos.x) { // west, [with new y]
  1827. msg.addByte(0x68);
  1828. GetMapDescription(newPos.x - 8, newPos.y - 6, newPos.z, 1, 14, msg);
  1829. }
  1830. writeToOutputBuffer(msg);
  1831. }
  1832. } else if (canSee(oldPos) && canSee(creature->getPosition())) {
  1833. if (teleport || (oldPos.z == 7 && newPos.z >= 8) || oldStackPos >= 10) {
  1834. sendRemoveTileThing(oldPos, oldStackPos);
  1835. sendAddCreature(creature, newPos, newStackPos, false);
  1836. } else {
  1837. NetworkMessage msg;
  1838. msg.addByte(0x6D);
  1839. msg.addPosition(oldPos);
  1840. msg.addByte(oldStackPos);
  1841. msg.addPosition(creature->getPosition());
  1842. writeToOutputBuffer(msg);
  1843. }
  1844. } else if (canSee(oldPos)) {
  1845. sendRemoveTileThing(oldPos, oldStackPos);
  1846. } else if (canSee(creature->getPosition())) {
  1847. sendAddCreature(creature, newPos, newStackPos, false);
  1848. }
  1849. }
  1850.  
  1851. void ProtocolGame::sendInventoryItem(slots_t slot, const Item* item)
  1852. {
  1853. NetworkMessage msg;
  1854. if (item) {
  1855. msg.addByte(0x78);
  1856. msg.addByte(slot);
  1857. msg.addItem(item);
  1858. } else {
  1859. msg.addByte(0x79);
  1860. msg.addByte(slot);
  1861. }
  1862. writeToOutputBuffer(msg);
  1863. }
  1864.  
  1865. void ProtocolGame::sendAddContainerItem(uint8_t cid, const Item* item)
  1866. {
  1867. NetworkMessage msg;
  1868. msg.addByte(0x70);
  1869. msg.addByte(cid);
  1870. msg.addItem(item);
  1871. writeToOutputBuffer(msg);
  1872. }
  1873.  
  1874. void ProtocolGame::sendUpdateContainerItem(uint8_t cid, uint16_t slot, const Item* item)
  1875. {
  1876. NetworkMessage msg;
  1877. msg.addByte(0x71);
  1878. msg.addByte(cid);
  1879. msg.addByte(slot);
  1880. msg.addItem(item);
  1881. writeToOutputBuffer(msg);
  1882. }
  1883.  
  1884. void ProtocolGame::sendRemoveContainerItem(uint8_t cid, uint16_t slot)
  1885. {
  1886. NetworkMessage msg;
  1887. msg.addByte(0x72);
  1888. msg.addByte(cid);
  1889. msg.addByte(slot);
  1890. writeToOutputBuffer(msg);
  1891. }
  1892.  
  1893. void ProtocolGame::sendTextWindow(uint32_t windowTextId, Item* item, uint16_t maxlen, bool canWrite)
  1894. {
  1895. NetworkMessage msg;
  1896. msg.addByte(0x96);
  1897. msg.add<uint32_t>(windowTextId);
  1898. msg.addItem(item);
  1899.  
  1900. if (canWrite) {
  1901. msg.add<uint16_t>(maxlen);
  1902. msg.addString(item->getText());
  1903. } else {
  1904. const std::string& text = item->getText();
  1905. msg.add<uint16_t>(text.size());
  1906. msg.addString(text);
  1907. }
  1908.  
  1909. const std::string& writer = item->getWriter();
  1910. if (!writer.empty()) {
  1911. msg.addString(writer);
  1912. } else {
  1913. msg.add<uint16_t>(0x00);
  1914. }
  1915.  
  1916. time_t writtenDate = item->getDate();
  1917. if (writtenDate != 0) {
  1918. msg.addString(formatDateShort(writtenDate));
  1919. } else {
  1920. msg.add<uint16_t>(0x00);
  1921. }
  1922.  
  1923. writeToOutputBuffer(msg);
  1924. }
  1925.  
  1926. void ProtocolGame::sendTextWindow(uint32_t windowTextId, uint32_t itemId, const std::string& text)
  1927. {
  1928. NetworkMessage msg;
  1929. msg.addByte(0x96);
  1930. msg.add<uint32_t>(windowTextId);
  1931. msg.addItem(itemId, 1);
  1932. msg.add<uint16_t>(text.size());
  1933. msg.addString(text);
  1934. msg.add<uint16_t>(0x00);
  1935. msg.add<uint16_t>(0x00);
  1936. writeToOutputBuffer(msg);
  1937. }
  1938.  
  1939. void ProtocolGame::sendHouseWindow(uint32_t windowTextId, const std::string& text)
  1940. {
  1941. NetworkMessage msg;
  1942. msg.addByte(0x97);
  1943. msg.addByte(0x00);
  1944. msg.add<uint32_t>(windowTextId);
  1945. msg.addString(text);
  1946. writeToOutputBuffer(msg);
  1947. }
  1948.  
  1949. void ProtocolGame::sendOutfitWindow()
  1950. {
  1951. NetworkMessage msg;
  1952. msg.addByte(0xC8);
  1953.  
  1954. Outfit_t currentOutfit = player->getDefaultOutfit();
  1955. AddOutfit(msg, currentOutfit);
  1956.  
  1957. std::vector<ProtocolOutfit> protocolOutfits;
  1958. if (player->isAccessPlayer()) {
  1959. static const std::string gamemasterOutfitName = "Gamemaster";
  1960. protocolOutfits.emplace_back(gamemasterOutfitName, 75, 0);
  1961. }
  1962.  
  1963. const auto& outfits = Outfits::getInstance().getOutfits(player->getSex());
  1964. protocolOutfits.reserve(outfits.size());
  1965. for (const Outfit& outfit : outfits) {
  1966. uint8_t addons;
  1967. if (!player->getOutfitAddons(outfit, addons)) {
  1968. continue;
  1969. }
  1970.  
  1971. protocolOutfits.emplace_back(outfit.name, outfit.lookType, addons);
  1972. if (protocolOutfits.size() == 26) { // Game client doesn't allow more than 26 outfits
  1973. break;
  1974. }
  1975. }
  1976.  
  1977. msg.addByte(protocolOutfits.size());
  1978. for (const ProtocolOutfit& outfit : protocolOutfits) {
  1979. msg.add<uint16_t>(outfit.lookType);
  1980. msg.addString(outfit.name);
  1981. msg.addByte(outfit.addons);
  1982. }
  1983.  
  1984. writeToOutputBuffer(msg);
  1985. }
  1986.  
  1987. void ProtocolGame::sendUpdatedVIPStatus(uint32_t guid, bool online)
  1988. {
  1989. NetworkMessage msg;
  1990. msg.addByte(online ? 0xD3 : 0xD4);
  1991. msg.add<uint32_t>(guid);
  1992. writeToOutputBuffer(msg);
  1993. }
  1994.  
  1995. void ProtocolGame::sendVIP(uint32_t guid, const std::string& name, bool isOnline)
  1996. {
  1997. NetworkMessage msg;
  1998. msg.addByte(0xD2);
  1999. msg.add<uint32_t>(guid);
  2000. msg.addString(name);
  2001. msg.addByte(isOnline ? 0x01 : 0x00);
  2002. writeToOutputBuffer(msg);
  2003. }
  2004.  
  2005. void ProtocolGame::sendAnimatedText(const std::string& message, const Position& pos, TextColor_t color)
  2006. {
  2007. if (!canSee(pos)) {
  2008. return;
  2009. }
  2010.  
  2011. NetworkMessage msg;
  2012. msg.addByte(0x84);
  2013. msg.addPosition(pos);
  2014. msg.addByte(color);
  2015. msg.addString(message);
  2016. writeToOutputBuffer(msg);
  2017. }
  2018.  
  2019. ////////////// Add common messages
  2020. void ProtocolGame::AddCreature(NetworkMessage& msg, const Creature* creature, bool known, uint32_t remove)
  2021. {
  2022. const Player* otherPlayer = creature->getPlayer();
  2023.  
  2024. if (known) {
  2025. msg.add<uint16_t>(0x62);
  2026. msg.add<uint32_t>(creature->getID());
  2027. } else {
  2028. msg.add<uint16_t>(0x61);
  2029. msg.add<uint32_t>(remove);
  2030. msg.add<uint32_t>(creature->getID());
  2031. msg.addString(creature->getName());
  2032. }
  2033.  
  2034. if (creature->isHealthHidden()) {
  2035. msg.addByte(0x00);
  2036. } else {
  2037. msg.addByte(std::ceil((static_cast<double>(creature->getHealth()) / std::max<int32_t>(creature->getMaxHealth(), 1)) * 100));
  2038. }
  2039.  
  2040. msg.addByte(creature->getDirection());
  2041.  
  2042. if (!creature->isInGhostMode() && !creature->isInvisible()) {
  2043. AddOutfit(msg, creature->getCurrentOutfit());
  2044. } else {
  2045. static Outfit_t outfit;
  2046. AddOutfit(msg, outfit);
  2047. }
  2048.  
  2049. LightInfo lightInfo;
  2050. creature->getCreatureLight(lightInfo);
  2051. msg.addByte(player->isAccessPlayer() ? 0xFF : lightInfo.level);
  2052. msg.addByte(lightInfo.color);
  2053.  
  2054. msg.add<uint16_t>(creature->getStepSpeed());
  2055.  
  2056. msg.addByte(player->getSkullClient(otherPlayer));
  2057. msg.addByte(player->getPartyShield(otherPlayer));
  2058.  
  2059. if (!known) {
  2060. msg.addByte(player->getGuildEmblem(otherPlayer));
  2061. }
  2062.  
  2063. msg.addByte(player->canWalkthroughEx(creature) ? 0x00 : 0x01);
  2064. }
  2065.  
  2066. void ProtocolGame::AddPlayerStats(NetworkMessage& msg)
  2067. {
  2068. msg.addByte(0xA0);
  2069.  
  2070. if (player->getPlayerInfo(PLAYERINFO_MAXHEALTH) > 0) {
  2071. msg.add<uint16_t>(player->getHealth() * 100 / player->getPlayerInfo(PLAYERINFO_MAXHEALTH));
  2072. msg.add<uint16_t>(100);
  2073. } else {
  2074. msg.add<uint16_t>(0);
  2075. msg.add<uint16_t>(0);
  2076. }
  2077.  
  2078. msg.add<uint32_t>(player->getFreeCapacity());
  2079.  
  2080. msg.add<uint32_t>(std::min<uint32_t>(player->getExperience(), 0x7FFFFFFF));
  2081.  
  2082. msg.add<uint16_t>(player->getLevel());
  2083. msg.addByte(player->getLevelPercent());
  2084.  
  2085. if (player->getPlayerInfo(PLAYERINFO_MAXMANA) > 0) {
  2086. msg.add<uint16_t>(player->getMana() * 100 / player->getPlayerInfo(PLAYERINFO_MAXMANA));
  2087. msg.add<uint16_t>(100);
  2088. } else {
  2089. msg.add<uint16_t>(0);
  2090. msg.add<uint16_t>(0);
  2091. }
  2092.  
  2093. msg.addByte(std::min<uint32_t>(player->getMagicLevel(), std::numeric_limits<uint8_t>::max()));
  2094. msg.addByte(player->getMagicLevelPercent());
  2095.  
  2096. msg.addByte(player->getSoul());
  2097.  
  2098. msg.add<uint16_t>(player->getStaminaMinutes());
  2099. }
  2100.  
  2101. void ProtocolGame::AddPlayerSkills(NetworkMessage& msg)
  2102. {
  2103. msg.addByte(0xA1);
  2104.  
  2105. for (uint8_t i = SKILL_FIRST; i <= SKILL_LAST; ++i) {
  2106. msg.addByte(std::min<int32_t>(player->getSkillLevel(i), std::numeric_limits<uint16_t>::max()));
  2107. msg.addByte(player->getSkillPercent(i));
  2108. }
  2109. }
  2110.  
  2111. void ProtocolGame::AddOutfit(NetworkMessage& msg, const Outfit_t& outfit)
  2112. {
  2113. msg.add<uint16_t>(outfit.lookType);
  2114.  
  2115. if (outfit.lookType != 0) {
  2116. msg.addByte(outfit.lookHead);
  2117. msg.addByte(outfit.lookBody);
  2118. msg.addByte(outfit.lookLegs);
  2119. msg.addByte(outfit.lookFeet);
  2120. msg.addByte(outfit.lookAddons);
  2121. } else {
  2122. msg.addItemId(outfit.lookTypeEx);
  2123. }
  2124. }
  2125.  
  2126. void ProtocolGame::AddWorldLight(NetworkMessage& msg, const LightInfo& lightInfo)
  2127. {
  2128. msg.addByte(0x82);
  2129. msg.addByte((player->isAccessPlayer() ? 0xFF : lightInfo.level));
  2130. msg.addByte(lightInfo.color);
  2131. }
  2132.  
  2133. void ProtocolGame::AddCreatureLight(NetworkMessage& msg, const Creature* creature)
  2134. {
  2135. LightInfo lightInfo;
  2136. creature->getCreatureLight(lightInfo);
  2137.  
  2138. msg.addByte(0x8D);
  2139. msg.add<uint32_t>(creature->getID());
  2140. msg.addByte((player->isAccessPlayer() ? 0xFF : lightInfo.level));
  2141. msg.addByte(lightInfo.color);
  2142. }
  2143.  
  2144. //tile
  2145. void ProtocolGame::RemoveTileThing(NetworkMessage& msg, const Position& pos, uint32_t stackpos)
  2146. {
  2147. if (stackpos >= 10) {
  2148. return;
  2149. }
  2150.  
  2151. msg.addByte(0x6C);
  2152. msg.addPosition(pos);
  2153. msg.addByte(stackpos);
  2154. }
  2155.  
  2156. void ProtocolGame::MoveUpCreature(NetworkMessage& msg, const Creature* creature, const Position& newPos, const Position& oldPos)
  2157. {
  2158. if (creature != player) {
  2159. return;
  2160. }
  2161.  
  2162. //floor change up
  2163. msg.addByte(0xBE);
  2164.  
  2165. //going to surface
  2166. if (newPos.z == 7) {
  2167. int32_t skip = -1;
  2168. GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 5, 18, 14, 3, skip); //(floor 7 and 6 already set)
  2169. GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 4, 18, 14, 4, skip);
  2170. GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 3, 18, 14, 5, skip);
  2171. GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 2, 18, 14, 6, skip);
  2172. GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 1, 18, 14, 7, skip);
  2173. GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 0, 18, 14, 8, skip);
  2174.  
  2175. if (skip >= 0) {
  2176. msg.addByte(skip);
  2177. msg.addByte(0xFF);
  2178. }
  2179. }
  2180. //underground, going one floor up (still underground)
  2181. else if (newPos.z > 7) {
  2182. int32_t skip = -1;
  2183. GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, oldPos.getZ() - 3, 18, 14, 3, skip);
  2184.  
  2185. if (skip >= 0) {
  2186. msg.addByte(skip);
  2187. msg.addByte(0xFF);
  2188. }
  2189. }
  2190.  
  2191. //moving up a floor up makes us out of sync
  2192. //west
  2193. msg.addByte(0x68);
  2194. GetMapDescription(oldPos.x - 8, oldPos.y - 5, newPos.z, 1, 14, msg);
  2195.  
  2196. //north
  2197. msg.addByte(0x65);
  2198. GetMapDescription(oldPos.x - 8, oldPos.y - 6, newPos.z, 18, 1, msg);
  2199. }
  2200.  
  2201. void ProtocolGame::MoveDownCreature(NetworkMessage& msg, const Creature* creature, const Position& newPos, const Position& oldPos)
  2202. {
  2203. if (creature != player) {
  2204. return;
  2205. }
  2206.  
  2207. //floor change down
  2208. msg.addByte(0xBF);
  2209.  
  2210. //going from surface to underground
  2211. if (newPos.z == 8) {
  2212. int32_t skip = -1;
  2213.  
  2214. GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, newPos.z, 18, 14, -1, skip);
  2215. GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, newPos.z + 1, 18, 14, -2, skip);
  2216. GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, newPos.z + 2, 18, 14, -3, skip);
  2217.  
  2218. if (skip >= 0) {
  2219. msg.addByte(skip);
  2220. msg.addByte(0xFF);
  2221. }
  2222. }
  2223. //going further down
  2224. else if (newPos.z > oldPos.z && newPos.z > 8 && newPos.z < 14) {
  2225. int32_t skip = -1;
  2226. GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, newPos.z + 2, 18, 14, -3, skip);
  2227.  
  2228. if (skip >= 0) {
  2229. msg.addByte(skip);
  2230. msg.addByte(0xFF);
  2231. }
  2232. }
  2233.  
  2234. //moving down a floor makes us out of sync
  2235. //east
  2236. msg.addByte(0x66);
  2237. GetMapDescription(oldPos.x + 9, oldPos.y - 7, newPos.z, 1, 14, msg);
  2238.  
  2239. //south
  2240. msg.addByte(0x67);
  2241. GetMapDescription(oldPos.x - 8, oldPos.y + 7, newPos.z, 18, 1, msg);
  2242. }
  2243.  
  2244. void ProtocolGame::AddShopItem(NetworkMessage& msg, const ShopInfo& item)
  2245. {
  2246. const ItemType& it = Item::items[item.itemId];
  2247. msg.add<uint16_t>(it.clientId);
  2248.  
  2249. if (it.isSplash() || it.isFluidContainer()) {
  2250. msg.addByte(serverFluidToClient(item.subType));
  2251. } else {
  2252. msg.addByte(0x00);
  2253. }
  2254.  
  2255. msg.addString(item.realName);
  2256. msg.add<uint32_t>(it.weight);
  2257. msg.add<uint32_t>(item.buyPrice);
  2258. msg.add<uint32_t>(item.sellPrice);
  2259. }
  2260.  
  2261. void ProtocolGame::parseExtendedOpcode(NetworkMessage& msg)
  2262. {
  2263. uint8_t opcode = msg.getByte();
  2264. const std::string& buffer = msg.getString();
  2265.  
  2266. // process additional opcodes via lua script event
  2267. addGameTask(&Game::parsePlayerExtendedOpcode, player->getID(), opcode, buffer);
  2268. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement