Advertisement
Guest User

Untitled

a guest
Aug 18th, 2019
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 73.54 KB | None | 0 0
  1. /*
  2. * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. * THE SOFTWARE.
  21. */
  22.  
  23. #include "protocolgame.h"
  24.  
  25. #include "localplayer.h"
  26. #include "thingtypemanager.h"
  27. #include "game.h"
  28. #include "map.h"
  29. #include "item.h"
  30. #include "effect.h"
  31. #include "missile.h"
  32. #include "tile.h"
  33. #include "luavaluecasts.h"
  34. #include <framework/core/eventdispatcher.h>
  35.  
  36. void ProtocolGame::parseMessage(const InputMessagePtr& msg)
  37. {
  38. int opcode = -1;
  39. int prevOpcode = -1;
  40.  
  41. try {
  42. while(!msg->eof()) {
  43. opcode = msg->getU8();
  44.  
  45. // must be > so extended will be enabled before GameStart.
  46. if(!g_game.getFeature(Otc::GameLoginPending)) {
  47. if(!m_gameInitialized && opcode > Proto::GameServerFirstGameOpcode) {
  48. g_game.processGameStart();
  49. m_gameInitialized = true;
  50. }
  51. }
  52.  
  53. // try to parse in lua first
  54. int readPos = msg->getReadPos();
  55. if(callLuaField<bool>("onOpcode", opcode, msg))
  56. continue;
  57. else
  58. msg->setReadPos(readPos); // restore read pos
  59.  
  60. switch(opcode) {
  61. case Proto::GameServerLoginOrPendingState:
  62. if(g_game.getFeature(Otc::GameLoginPending))
  63. parsePendingGame(msg);
  64. else
  65. parseLogin(msg);
  66. break;
  67. case Proto::GameServerGMActions:
  68. parseGMActions(msg);
  69. break;
  70. case Proto::GameServerUpdateNeeded:
  71. parseUpdateNeeded(msg);
  72. break;
  73. case Proto::GameServerLoginError:
  74. parseLoginError(msg);
  75. break;
  76. case Proto::GameServerLoginAdvice:
  77. parseLoginAdvice(msg);
  78. break;
  79. case Proto::GameServerLoginWait:
  80. parseLoginWait(msg);
  81. break;
  82. case Proto::GameServerLoginToken:
  83. parseLoginToken(msg);
  84. break;
  85. case Proto::GameServerPing:
  86. case Proto::GameServerPingBack:
  87. if((opcode == Proto::GameServerPing && g_game.getFeature(Otc::GameClientPing)) ||
  88. (opcode == Proto::GameServerPingBack && !g_game.getFeature(Otc::GameClientPing)))
  89. parsePingBack(msg);
  90. else
  91. parsePing(msg);
  92. break;
  93. case Proto::GameServerChallenge:
  94. parseChallenge(msg);
  95. break;
  96. case Proto::GameServerDeath:
  97. parseDeath(msg);
  98. break;
  99. case Proto::GameServerFullMap:
  100. parseMapDescription(msg);
  101. break;
  102. case Proto::GameServerMapTopRow:
  103. parseMapMoveNorth(msg);
  104. break;
  105. case Proto::GameServerMapRightRow:
  106. parseMapMoveEast(msg);
  107. break;
  108. case Proto::GameServerMapBottomRow:
  109. parseMapMoveSouth(msg);
  110. break;
  111. case Proto::GameServerMapLeftRow:
  112. parseMapMoveWest(msg);
  113. break;
  114. case Proto::GameServerUpdateTile:
  115. parseUpdateTile(msg);
  116. break;
  117. case Proto::GameServerCreateOnMap:
  118. parseTileAddThing(msg);
  119. break;
  120. case Proto::GameServerChangeOnMap:
  121. parseTileTransformThing(msg);
  122. break;
  123. case Proto::GameServerDeleteOnMap:
  124. parseTileRemoveThing(msg);
  125. break;
  126. case Proto::GameServerMoveCreature:
  127. parseCreatureMove(msg);
  128. break;
  129. case Proto::GameServerOpenContainer:
  130. parseOpenContainer(msg);
  131. break;
  132. case Proto::GameServerCloseContainer:
  133. parseCloseContainer(msg);
  134. break;
  135. case Proto::GameServerCreateContainer:
  136. parseContainerAddItem(msg);
  137. break;
  138. case Proto::GameServerChangeInContainer:
  139. parseContainerUpdateItem(msg);
  140. break;
  141. case Proto::GameServerDeleteInContainer:
  142. parseContainerRemoveItem(msg);
  143. break;
  144. case Proto::GameServerSetInventory:
  145. parseAddInventoryItem(msg);
  146. break;
  147. case Proto::GameServerDeleteInventory:
  148. parseRemoveInventoryItem(msg);
  149. break;
  150. case Proto::GameServerOpenNpcTrade:
  151. parseOpenNpcTrade(msg);
  152. break;
  153. case Proto::GameServerPlayerGoods:
  154. parsePlayerGoods(msg);
  155. break;
  156. case Proto::GameServerCloseNpcTrade:
  157. parseCloseNpcTrade(msg);
  158. break;
  159. case Proto::GameServerOwnTrade:
  160. parseOwnTrade(msg);
  161. break;
  162. case Proto::GameServerCounterTrade:
  163. parseCounterTrade(msg);
  164. break;
  165. case Proto::GameServerCloseTrade:
  166. parseCloseTrade(msg);
  167. break;
  168. case Proto::GameServerAmbient:
  169. parseWorldLight(msg);
  170. break;
  171. case Proto::GameServerGraphicalEffect:
  172. parseMagicEffect(msg);
  173. break;
  174. case Proto::GameServerTextEffect:
  175. parseAnimatedText(msg);
  176. break;
  177. case Proto::GameServerMissleEffect:
  178. parseDistanceMissile(msg);
  179. break;
  180. case Proto::GameServerMarkCreature:
  181. parseCreatureMark(msg);
  182. break;
  183. case Proto::GameServerTrappers:
  184. parseTrappers(msg);
  185. break;
  186. case Proto::GameServerCreatureHealth:
  187. parseCreatureHealth(msg);
  188. break;
  189. case Proto::GameServerCreatureLight:
  190. parseCreatureLight(msg);
  191. break;
  192. case Proto::GameServerCreatureOutfit:
  193. parseCreatureOutfit(msg);
  194. break;
  195. case Proto::GameServerCreatureSpeed:
  196. parseCreatureSpeed(msg);
  197. break;
  198. case Proto::GameServerCreatureSkull:
  199. parseCreatureSkulls(msg);
  200. break;
  201. case Proto::GameServerCreatureParty:
  202. parseCreatureShields(msg);
  203. break;
  204. case Proto::GameServerCreatureUnpass:
  205. parseCreatureUnpass(msg);
  206. break;
  207. case Proto::GameServerEditText:
  208. parseEditText(msg);
  209. break;
  210. case Proto::GameServerEditList:
  211. parseEditList(msg);
  212. break;
  213. // PROTOCOL>=1038
  214. case Proto::GameServerPremiumTrigger:
  215. parsePremiumTrigger(msg);
  216. break;
  217. case Proto::GameServerPlayerData:
  218. parsePlayerStats(msg);
  219. break;
  220. case Proto::GameServerPlayerSkills:
  221. parsePlayerSkills(msg);
  222. break;
  223. case Proto::GameServerPlayerState:
  224. parsePlayerState(msg);
  225. break;
  226. case Proto::GameServerClearTarget:
  227. parsePlayerCancelAttack(msg);
  228. break;
  229. case Proto::GameServerPlayerModes:
  230. parsePlayerModes(msg);
  231. break;
  232. case Proto::GameServerTalk:
  233. parseTalk(msg);
  234. break;
  235. case Proto::GameServerChannels:
  236. parseChannelList(msg);
  237. break;
  238. case Proto::GameServerOpenChannel:
  239. parseOpenChannel(msg);
  240. break;
  241. case Proto::GameServerOpenPrivateChannel:
  242. parseOpenPrivateChannel(msg);
  243. break;
  244. case Proto::GameServerRuleViolationChannel:
  245. parseRuleViolationChannel(msg);
  246. break;
  247. case Proto::GameServerRuleViolationRemove:
  248. parseRuleViolationRemove(msg);
  249. break;
  250. case Proto::GameServerRuleViolationCancel:
  251. parseRuleViolationCancel(msg);
  252. break;
  253. case Proto::GameServerRuleViolationLock:
  254. parseRuleViolationLock(msg);
  255. break;
  256. case Proto::GameServerOpenOwnChannel:
  257. parseOpenOwnPrivateChannel(msg);
  258. break;
  259. case Proto::GameServerCloseChannel:
  260. parseCloseChannel(msg);
  261. break;
  262. case Proto::GameServerTextMessage:
  263. parseTextMessage(msg);
  264. break;
  265. case Proto::GameServerCancelWalk:
  266. parseCancelWalk(msg);
  267. break;
  268. case Proto::GameServerWalkWait:
  269. parseWalkWait(msg);
  270. break;
  271. case Proto::GameServerFloorChangeUp:
  272. parseFloorChangeUp(msg);
  273. break;
  274. case Proto::GameServerFloorChangeDown:
  275. parseFloorChangeDown(msg);
  276. break;
  277. case Proto::GameServerChooseOutfit:
  278. parseOpenOutfitWindow(msg);
  279. break;
  280. case Proto::GameServerVipAdd:
  281. parseVipAdd(msg);
  282. break;
  283. case Proto::GameServerVipState:
  284. parseVipState(msg);
  285. break;
  286. case Proto::GameServerVipLogout:
  287. parseVipLogout(msg);
  288. break;
  289. case Proto::GameServerTutorialHint:
  290. parseTutorialHint(msg);
  291. break;
  292. case Proto::GameServerAutomapFlag:
  293. parseAutomapFlag(msg);
  294. break;
  295. case Proto::GameServerQuestLog:
  296. parseQuestLog(msg);
  297. break;
  298. case Proto::GameServerQuestLine:
  299. parseQuestLine(msg);
  300. break;
  301. // PROTOCOL>=870
  302. case Proto::GameServerSpellDelay:
  303. parseSpellCooldown(msg);
  304. break;
  305. case Proto::GameServerSpellGroupDelay:
  306. parseSpellGroupCooldown(msg);
  307. break;
  308. case Proto::GameServerMultiUseDelay:
  309. parseMultiUseCooldown(msg);
  310. break;
  311. // PROTOCOL>=910
  312. case Proto::GameServerChannelEvent:
  313. parseChannelEvent(msg);
  314. break;
  315. case Proto::GameServerItemInfo:
  316. parseItemInfo(msg);
  317. break;
  318. case Proto::GameServerPlayerInventory:
  319. parsePlayerInventory(msg);
  320. break;
  321. // PROTOCOL>=950
  322. case Proto::GameServerPlayerDataBasic:
  323. parsePlayerInfo(msg);
  324. break;
  325. // PROTOCOL>=970
  326. case Proto::GameServerModalDialog:
  327. parseModalDialog(msg);
  328. break;
  329. // PROTOCOL>=980
  330. case Proto::GameServerLoginSuccess:
  331. parseLogin(msg);
  332. break;
  333. case Proto::GameServerEnterGame:
  334. parseEnterGame(msg);
  335. break;
  336. case Proto::GameServerPlayerHelpers:
  337. parsePlayerHelpers(msg);
  338. break;
  339. // PROTOCOL>=1000
  340. case Proto::GameServerCreatureMarks:
  341. parseCreaturesMark(msg);
  342. break;
  343. case Proto::GameServerCreatureType:
  344. parseCreatureType(msg);
  345. break;
  346. // PROTOCOL>=1055
  347. case Proto::GameServerBlessings:
  348. parseBlessings(msg);
  349. break;
  350. case Proto::GameServerUnjustifiedStats:
  351. parseUnjustifiedStats(msg);
  352. break;
  353. case Proto::GameServerPvpSituations:
  354. parsePvpSituations(msg);
  355. break;
  356. case Proto::GameServerPreset:
  357. parsePreset(msg);
  358. break;
  359. // PROTOCOL>=1080
  360. case Proto::GameServerCoinBalanceUpdating:
  361. parseCoinBalanceUpdating(msg);
  362. break;
  363. case Proto::GameServerCoinBalance:
  364. parseCoinBalance(msg);
  365. break;
  366. case Proto::GameServerRequestPurchaseData:
  367. parseRequestPurchaseData(msg);
  368. break;
  369. case Proto::GameServerStoreCompletePurchase:
  370. parseCompleteStorePurchase(msg);
  371. break;
  372. case Proto::GameServerStoreOffers:
  373. parseStoreOffers(msg);
  374. break;
  375. case Proto::GameServerStoreTransactionHistory:
  376. parseStoreTransactionHistory(msg);
  377. break;
  378. case Proto::GameServerStoreError:
  379. parseStoreError(msg);
  380. break;
  381. case Proto::GameServerStore:
  382. parseStore(msg);
  383. break;
  384. // PROTOCOL>=1097
  385. case Proto::GameServerStoreButtonIndicators:
  386. parseStoreButtonIndicators(msg);
  387. break;
  388. case Proto::GameServerSetStoreDeepLink:
  389. parseSetStoreDeepLink(msg);
  390. break;
  391. // otclient ONLY
  392. case Proto::GameServerExtendedOpcode:
  393. parseExtendedOpcode(msg);
  394. break;
  395. case Proto::GameServerChangeMapAwareRange:
  396. parseChangeMapAwareRange(msg);
  397. break;
  398. default:
  399. stdext::throw_exception(stdext::format("unhandled opcode %d", (int)opcode));
  400. break;
  401. }
  402. prevOpcode = opcode;
  403. }
  404. } catch(stdext::exception& e) {
  405. g_logger.error(stdext::format("ProtocolGame parse message exception (%d bytes unread, last opcode is %d, prev opcode is %d): %s",
  406. msg->getUnreadSize(), opcode, prevOpcode, e.what()));
  407. }
  408. }
  409.  
  410. void ProtocolGame::parseLogin(const InputMessagePtr& msg)
  411. {
  412. uint playerId = msg->getU32();
  413. int serverBeat = msg->getU16();
  414.  
  415. if(g_game.getFeature(Otc::GameNewSpeedLaw)) {
  416. double speedA = msg->getDouble();
  417. double speedB = msg->getDouble();
  418. double speedC = msg->getDouble();
  419. m_localPlayer->setSpeedFormula(speedA, speedB, speedC);
  420. }
  421. bool canReportBugs = msg->getU8();
  422.  
  423. if(g_game.getClientVersion() >= 1054)
  424. msg->getU8(); // can change pvp frame option
  425.  
  426. if(g_game.getClientVersion() >= 1058) {
  427. int expertModeEnabled = msg->getU8();
  428. g_game.setExpertPvpMode(expertModeEnabled);
  429. }
  430.  
  431. if(g_game.getFeature(Otc::GameIngameStore)) {
  432. // URL to ingame store images
  433. msg->getString();
  434.  
  435. // premium coin package size
  436. // e.g you can only buy packs of 25, 50, 75, .. coins in the market
  437. msg->getU16();
  438. }
  439.  
  440. m_localPlayer->setId(playerId);
  441. g_game.setServerBeat(serverBeat);
  442. g_game.setCanReportBugs(canReportBugs);
  443.  
  444. g_game.processLogin();
  445. }
  446.  
  447. void ProtocolGame::parsePendingGame(const InputMessagePtr& msg)
  448. {
  449. //set player to pending game state
  450. g_game.processPendingGame();
  451. }
  452.  
  453. void ProtocolGame::parseEnterGame(const InputMessagePtr& msg)
  454. {
  455. //set player to entered game state
  456. g_game.processEnterGame();
  457.  
  458. if(!m_gameInitialized) {
  459. g_game.processGameStart();
  460. m_gameInitialized = true;
  461. }
  462. }
  463.  
  464. void ProtocolGame::parseStoreButtonIndicators(const InputMessagePtr& msg)
  465. {
  466. msg->getU8(); // unknown
  467. msg->getU8(); // unknown
  468. }
  469.  
  470. void ProtocolGame::parseSetStoreDeepLink(const InputMessagePtr& msg)
  471. {
  472. int currentlyFeaturedServiceType = msg->getU8();
  473. }
  474.  
  475. void ProtocolGame::parseBlessings(const InputMessagePtr& msg)
  476. {
  477. uint16 blessings = msg->getU16();
  478. m_localPlayer->setBlessings(blessings);
  479. }
  480.  
  481. void ProtocolGame::parsePreset(const InputMessagePtr& msg)
  482. {
  483. uint32 preset = msg->getU32();
  484. }
  485.  
  486. void ProtocolGame::parseRequestPurchaseData(const InputMessagePtr& msg)
  487. {
  488. int transactionId = msg->getU32();
  489. int productType = msg->getU8();
  490. }
  491.  
  492. void ProtocolGame::parseStore(const InputMessagePtr& msg)
  493. {
  494. parseCoinBalance(msg);
  495.  
  496. // Parse all categories
  497. int count = msg->getU16();
  498. for(int i = 0; i < count; i++) {
  499. std::string category = msg->getString();
  500. std::string description = msg->getString();
  501.  
  502. int highlightState = 0;
  503. if(g_game.getFeature(Otc::GameIngameStoreHighlights))
  504. highlightState = msg->getU8();
  505.  
  506. std::vector<std::string> icons;
  507. int iconCount = msg->getU8();
  508. for(int i = 0; i < iconCount; i++) {
  509. std::string icon = msg->getString();
  510. icons.push_back(icon);
  511. }
  512.  
  513. // If this is a valid category name then
  514. // the category we just parsed is a child of that
  515. std::string parentCategory = msg->getString();
  516. }
  517. }
  518.  
  519. void ProtocolGame::parseCoinBalance(const InputMessagePtr& msg)
  520. {
  521. bool update = msg->getU8() == 1;
  522. int coins = -1;
  523. int transferableCoins = -1;
  524. if(update) {
  525. // amount of coins that can be used to buy prodcuts
  526. // in the ingame store
  527. coins = msg->getU32();
  528.  
  529. // amount of coins that can be sold in market
  530. // or be transfered to another player
  531. transferableCoins = msg->getU32();
  532. }
  533. }
  534.  
  535. void ProtocolGame::parseCoinBalanceUpdating(const InputMessagePtr& msg)
  536. {
  537. // coin balance can be updating and might not be accurate
  538. bool isUpdating = msg->getU8() == 1;
  539. }
  540.  
  541. void ProtocolGame::parseCompleteStorePurchase(const InputMessagePtr& msg)
  542. {
  543. // not used
  544. msg->getU8();
  545.  
  546. std::string message = msg->getString();
  547. int coins = msg->getU32();
  548. int transferableCoins = msg->getU32();
  549.  
  550. g_logger.info(stdext::format("Purchase Complete: %s", message));
  551. }
  552.  
  553. void ProtocolGame::parseStoreTransactionHistory(const InputMessagePtr &msg)
  554. {
  555. int currentPage;
  556. if(g_game.getClientVersion() <= 1096) {
  557. currentPage = msg->getU16();
  558. bool hasNextPage = msg->getU8() == 1;
  559. } else {
  560. currentPage = msg->getU32();
  561. int pageCount = msg->getU32();
  562. }
  563.  
  564. int entries = msg->getU8();
  565. for(int i = 0; i < entries; i++) {
  566. int time = msg->getU16();
  567. int productType = msg->getU8();
  568. int coinChange = msg->getU32();
  569. std::string productName = msg->getString();
  570. g_logger.error(stdext::format("Time %i, type %i, change %i, product name %s", time, productType, coinChange, productName));
  571. }
  572. }
  573.  
  574. void ProtocolGame::parseStoreOffers(const InputMessagePtr& msg)
  575. {
  576. std::string categoryName = msg->getString();
  577.  
  578. int offers = msg->getU16();
  579. for(int i = 0; i < offers; i++) {
  580. int offerId = msg->getU32();
  581. std::string offerName = msg->getString();
  582. std::string offerDescription = msg->getString();
  583.  
  584. int price = msg->getU32();
  585. int highlightState = msg->getU8();
  586. if(highlightState == 2 && g_game.getFeature(Otc::GameIngameStoreHighlights) && g_game.getClientVersion() >= 1097) {
  587. int saleValidUntilTimestamp = msg->getU32();
  588. int basePrice = msg->getU32();
  589. }
  590.  
  591. int disabledState = msg->getU8();
  592. std::string disabledReason = "";
  593. if(g_game.getFeature(Otc::GameIngameStoreHighlights) && disabledState == 1) {
  594. disabledReason = msg->getString();
  595. }
  596.  
  597. int icons = msg->getU8();
  598. for(int j = 0; j < icons; j++) {
  599. std::string icon = msg->getString();
  600. }
  601.  
  602. int subOffers = msg->getU16();
  603. for(int j = 0; j < subOffers; j++) {
  604. std::string name = msg->getString();
  605. std::string description = msg->getString();
  606.  
  607. int subIcons = msg->getU8();
  608. for(int k = 0; k < subIcons; k++) {
  609. std::string icon = msg->getString();
  610. }
  611. std::string serviceType = msg->getString();
  612. }
  613. }
  614. }
  615.  
  616. void ProtocolGame::parseStoreError(const InputMessagePtr& msg)
  617. {
  618. int errorType = msg->getU8();
  619. std::string message = msg->getString();
  620. g_logger.error(stdext::format("Store Error: %s [%i]", message, errorType));
  621. }
  622.  
  623. void ProtocolGame::parseUnjustifiedStats(const InputMessagePtr& msg)
  624. {
  625. UnjustifiedPoints unjustifiedPoints;
  626. unjustifiedPoints.killsDay = msg->getU8();
  627. unjustifiedPoints.killsDayRemaining = msg->getU8();
  628. unjustifiedPoints.killsWeek = msg->getU8();
  629. unjustifiedPoints.killsWeekRemaining = msg->getU8();
  630. unjustifiedPoints.killsMonth = msg->getU8();
  631. unjustifiedPoints.killsMonthRemaining = msg->getU8();
  632. unjustifiedPoints.skullTime = msg->getU8();
  633.  
  634. g_game.setUnjustifiedPoints(unjustifiedPoints);
  635. }
  636.  
  637. void ProtocolGame::parsePvpSituations(const InputMessagePtr& msg)
  638. {
  639. uint8 openPvpSituations = msg->getU8();
  640.  
  641. g_game.setOpenPvpSituations(openPvpSituations);
  642. }
  643.  
  644. void ProtocolGame::parsePlayerHelpers(const InputMessagePtr& msg)
  645. {
  646. uint id = msg->getU32();
  647. int helpers = msg->getU16();
  648.  
  649. CreaturePtr creature = g_map.getCreatureById(id);
  650. if(creature)
  651. g_game.processPlayerHelpers(helpers);
  652. else
  653. g_logger.traceError(stdext::format("could not get creature with id %d", id));
  654. }
  655.  
  656. void ProtocolGame::parseGMActions(const InputMessagePtr& msg)
  657. {
  658. std::vector<uint8> actions;
  659.  
  660. int numViolationReasons;
  661.  
  662. if(g_game.getClientVersion() >= 850)
  663. numViolationReasons = 20;
  664. else if(g_game.getClientVersion() >= 840)
  665. numViolationReasons = 23;
  666. else
  667. numViolationReasons = 32;
  668.  
  669. for(int i = 0; i < numViolationReasons; ++i)
  670. actions.push_back(msg->getU8());
  671. g_game.processGMActions(actions);
  672. }
  673.  
  674. void ProtocolGame::parseUpdateNeeded(const InputMessagePtr& msg)
  675. {
  676. std::string signature = msg->getString();
  677. g_game.processUpdateNeeded(signature);
  678. }
  679.  
  680. void ProtocolGame::parseLoginError(const InputMessagePtr& msg)
  681. {
  682. std::string error = msg->getString();
  683.  
  684. g_game.processLoginError(error);
  685. }
  686.  
  687. void ProtocolGame::parseLoginAdvice(const InputMessagePtr& msg)
  688. {
  689. std::string message = msg->getString();
  690.  
  691. g_game.processLoginAdvice(message);
  692. }
  693.  
  694. void ProtocolGame::parseLoginWait(const InputMessagePtr& msg)
  695. {
  696. std::string message = msg->getString();
  697. int time = msg->getU8();
  698.  
  699. g_game.processLoginWait(message, time);
  700. }
  701.  
  702. void ProtocolGame::parseLoginToken(const InputMessagePtr& msg)
  703. {
  704. bool unknown = (msg->getU8() == 0);
  705. g_game.processLoginToken(unknown);
  706. }
  707.  
  708. void ProtocolGame::parsePing(const InputMessagePtr& msg)
  709. {
  710. g_game.processPing();
  711. }
  712.  
  713. void ProtocolGame::parsePingBack(const InputMessagePtr& msg)
  714. {
  715. g_game.processPingBack();
  716. }
  717.  
  718. void ProtocolGame::parseChallenge(const InputMessagePtr& msg)
  719. {
  720. uint timestamp = msg->getU32();
  721. uint8 random = msg->getU8();
  722.  
  723. sendLoginPacket(timestamp, random);
  724. }
  725.  
  726. void ProtocolGame::parseDeath(const InputMessagePtr& msg)
  727. {
  728. int penality = 100;
  729. int deathType = Otc::DeathRegular;
  730.  
  731. if(g_game.getFeature(Otc::GameDeathType))
  732. deathType = msg->getU8();
  733.  
  734. if(g_game.getFeature(Otc::GamePenalityOnDeath) && deathType == Otc::DeathRegular)
  735. penality = msg->getU8();
  736.  
  737. g_game.processDeath(deathType, penality);
  738. }
  739.  
  740. void ProtocolGame::parseMapDescription(const InputMessagePtr& msg)
  741. {
  742. Position pos = getPosition(msg);
  743.  
  744. if(!m_mapKnown)
  745. m_localPlayer->setPosition(pos);
  746.  
  747. g_map.setCentralPosition(pos);
  748.  
  749. AwareRange range = g_map.getAwareRange();
  750. setMapDescription(msg, pos.x - range.left, pos.y - range.top, pos.z, range.horizontal(), range.vertical());
  751.  
  752. if(!m_mapKnown) {
  753. g_dispatcher.addEvent([] { g_lua.callGlobalField("g_game", "onMapKnown"); });
  754. m_mapKnown = true;
  755. }
  756.  
  757. g_dispatcher.addEvent([] { g_lua.callGlobalField("g_game", "onMapDescription"); });
  758. }
  759.  
  760. void ProtocolGame::parseMapMoveNorth(const InputMessagePtr& msg)
  761. {
  762. Position pos;
  763. if(g_game.getFeature(Otc::GameMapMovePosition))
  764. pos = getPosition(msg);
  765. else
  766. pos = g_map.getCentralPosition();
  767. pos.y--;
  768.  
  769. AwareRange range = g_map.getAwareRange();
  770. setMapDescription(msg, pos.x - range.left, pos.y - range.top, pos.z, range.horizontal(), 1);
  771. g_map.setCentralPosition(pos);
  772. }
  773.  
  774. void ProtocolGame::parseMapMoveEast(const InputMessagePtr& msg)
  775. {
  776. Position pos;
  777. if(g_game.getFeature(Otc::GameMapMovePosition))
  778. pos = getPosition(msg);
  779. else
  780. pos = g_map.getCentralPosition();
  781. pos.x++;
  782.  
  783. AwareRange range = g_map.getAwareRange();
  784. setMapDescription(msg, pos.x + range.right, pos.y - range.top, pos.z, 1, range.vertical());
  785. g_map.setCentralPosition(pos);
  786. }
  787.  
  788. void ProtocolGame::parseMapMoveSouth(const InputMessagePtr& msg)
  789. {
  790. Position pos;
  791. if(g_game.getFeature(Otc::GameMapMovePosition))
  792. pos = getPosition(msg);
  793. else
  794. pos = g_map.getCentralPosition();
  795. pos.y++;
  796.  
  797. AwareRange range = g_map.getAwareRange();
  798. setMapDescription(msg, pos.x - range.left, pos.y + range.bottom, pos.z, range.horizontal(), 1);
  799. g_map.setCentralPosition(pos);
  800. }
  801.  
  802. void ProtocolGame::parseMapMoveWest(const InputMessagePtr& msg)
  803. {
  804. Position pos;
  805. if(g_game.getFeature(Otc::GameMapMovePosition))
  806. pos = getPosition(msg);
  807. else
  808. pos = g_map.getCentralPosition();
  809. pos.x--;
  810.  
  811. AwareRange range = g_map.getAwareRange();
  812. setMapDescription(msg, pos.x - range.left, pos.y - range.top, pos.z, 1, range.vertical());
  813. g_map.setCentralPosition(pos);
  814. }
  815.  
  816. void ProtocolGame::parseUpdateTile(const InputMessagePtr& msg)
  817. {
  818. Position tilePos = getPosition(msg);
  819. setTileDescription(msg, tilePos);
  820. }
  821.  
  822. void ProtocolGame::parseTileAddThing(const InputMessagePtr& msg)
  823. {
  824. Position pos = getPosition(msg);
  825. int stackPos = -1;
  826.  
  827. if(g_game.getClientVersion() >= 841)
  828. stackPos = msg->getU8();
  829.  
  830. ThingPtr thing = getThing(msg);
  831. g_map.addThing(thing, pos, stackPos);
  832. }
  833.  
  834. void ProtocolGame::parseTileTransformThing(const InputMessagePtr& msg)
  835. {
  836. ThingPtr thing = getMappedThing(msg);
  837. ThingPtr newThing = getThing(msg);
  838.  
  839. if(!thing) {
  840. g_logger.traceError("no thing");
  841. return;
  842. }
  843.  
  844. Position pos = thing->getPosition();
  845. int stackpos = thing->getStackPos();
  846.  
  847. if(!g_map.removeThing(thing)) {
  848. g_logger.traceError("unable to remove thing");
  849. return;
  850. }
  851.  
  852. g_map.addThing(newThing, pos, stackpos);
  853. }
  854.  
  855. void ProtocolGame::parseTileRemoveThing(const InputMessagePtr& msg)
  856. {
  857. ThingPtr thing = getMappedThing(msg);
  858. if(!thing) {
  859. g_logger.traceError("no thing");
  860. return;
  861. }
  862.  
  863. if(!g_map.removeThing(thing))
  864. g_logger.traceError("unable to remove thing");
  865. }
  866.  
  867. void ProtocolGame::parseCreatureMove(const InputMessagePtr& msg)
  868. {
  869. ThingPtr thing = getMappedThing(msg);
  870. Position newPos = getPosition(msg);
  871.  
  872. if(!thing || !thing->isCreature()) {
  873. g_logger.traceError("no creature found to move");
  874. return;
  875. }
  876.  
  877. if(!g_map.removeThing(thing)) {
  878. g_logger.traceError("unable to remove creature");
  879. return;
  880. }
  881.  
  882. CreaturePtr creature = thing->static_self_cast<Creature>();
  883. creature->allowAppearWalk();
  884.  
  885. g_map.addThing(thing, newPos, -1);
  886. }
  887.  
  888. void ProtocolGame::parseOpenContainer(const InputMessagePtr& msg)
  889. {
  890. int containerId = msg->getU8();
  891. ItemPtr containerItem = getItem(msg);
  892. std::string name = msg->getString();
  893. int capacity = msg->getU8();
  894. bool hasParent = (msg->getU8() != 0);
  895.  
  896. bool isUnlocked = true;
  897. bool hasPages = false;
  898. int containerSize = 0;
  899. int firstIndex = 0;
  900.  
  901. if(g_game.getFeature(Otc::GameContainerPagination)) {
  902. isUnlocked = (msg->getU8() != 0); // drag and drop
  903. hasPages = (msg->getU8() != 0); // pagination
  904. containerSize = msg->getU16(); // container size
  905. firstIndex = msg->getU16(); // first index
  906. }
  907.  
  908. int itemCount = msg->getU8();
  909.  
  910. std::vector<ItemPtr> items(itemCount);
  911. for(int i = 0; i < itemCount; i++)
  912. items[i] = getItem(msg);
  913.  
  914. g_game.processOpenContainer(containerId, containerItem, name, capacity, hasParent, items, isUnlocked, hasPages, containerSize, firstIndex);
  915. }
  916.  
  917. void ProtocolGame::parseCloseContainer(const InputMessagePtr& msg)
  918. {
  919. int containerId = msg->getU8();
  920. g_game.processCloseContainer(containerId);
  921. }
  922.  
  923. void ProtocolGame::parseContainerAddItem(const InputMessagePtr& msg)
  924. {
  925. int containerId = msg->getU8();
  926. int slot = 0;
  927. if(g_game.getFeature(Otc::GameContainerPagination)) {
  928. slot = msg->getU16(); // slot
  929. }
  930. ItemPtr item = getItem(msg);
  931. g_game.processContainerAddItem(containerId, item, slot);
  932. }
  933.  
  934. void ProtocolGame::parseContainerUpdateItem(const InputMessagePtr& msg)
  935. {
  936. int containerId = msg->getU8();
  937. int slot;
  938. if(g_game.getFeature(Otc::GameContainerPagination)) {
  939. slot = msg->getU16();
  940. } else {
  941. slot = msg->getU8();
  942. }
  943. ItemPtr item = getItem(msg);
  944. g_game.processContainerUpdateItem(containerId, slot, item);
  945. }
  946.  
  947. void ProtocolGame::parseContainerRemoveItem(const InputMessagePtr& msg)
  948. {
  949. int containerId = msg->getU8();
  950. int slot;
  951. ItemPtr lastItem;
  952. if(g_game.getFeature(Otc::GameContainerPagination)) {
  953. slot = msg->getU16();
  954.  
  955. int itemId = msg->getU16();
  956. if(itemId != 0)
  957. lastItem = getItem(msg, itemId);
  958. } else {
  959. slot = msg->getU8();
  960. }
  961. g_game.processContainerRemoveItem(containerId, slot, lastItem);
  962. }
  963.  
  964. void ProtocolGame::parseAddInventoryItem(const InputMessagePtr& msg)
  965. {
  966. int slot = msg->getU8();
  967. ItemPtr item = getItem(msg);
  968. g_game.processInventoryChange(slot, item);
  969. }
  970.  
  971. void ProtocolGame::parseRemoveInventoryItem(const InputMessagePtr& msg)
  972. {
  973. int slot = msg->getU8();
  974. g_game.processInventoryChange(slot, ItemPtr());
  975. }
  976.  
  977. void ProtocolGame::parseOpenNpcTrade(const InputMessagePtr& msg)
  978. {
  979. std::vector<std::tuple<ItemPtr, std::string, int, int, int>> items;
  980. std::string npcName;
  981.  
  982. if(g_game.getFeature(Otc::GameNameOnNpcTrade))
  983. npcName = msg->getString();
  984.  
  985. int listCount;
  986.  
  987. if(g_game.getClientVersion() >= 900)
  988. listCount = msg->getU16();
  989. else
  990. listCount = msg->getU8();
  991.  
  992. for(int i = 0; i < listCount; ++i) {
  993. uint16 itemId = msg->getU16();
  994. uint8 count = msg->getU8();
  995.  
  996. ItemPtr item = Item::create(itemId);
  997. item->setCountOrSubType(count);
  998.  
  999. std::string name = msg->getString();
  1000. int weight = msg->getU32();
  1001. int buyPrice = msg->getU32();
  1002. int sellPrice = msg->getU32();
  1003. items.push_back(std::make_tuple(item, name, weight, buyPrice, sellPrice));
  1004. }
  1005.  
  1006. g_game.processOpenNpcTrade(items);
  1007. }
  1008.  
  1009. void ProtocolGame::parsePlayerGoods(const InputMessagePtr& msg)
  1010. {
  1011. std::vector<std::tuple<ItemPtr, int>> goods;
  1012.  
  1013. int money;
  1014. if(g_game.getClientVersion() >= 973)
  1015. money = msg->getU64();
  1016. else
  1017. money = msg->getU32();
  1018.  
  1019. int size = msg->getU8();
  1020. for(int i = 0; i < size; i++) {
  1021. int itemId = msg->getU16();
  1022. int amount;
  1023.  
  1024. if(g_game.getFeature(Otc::GameDoubleShopSellAmount))
  1025. amount = msg->getU16();
  1026. else
  1027. amount = msg->getU8();
  1028.  
  1029. goods.push_back(std::make_tuple(Item::create(itemId), amount));
  1030. }
  1031.  
  1032. g_game.processPlayerGoods(money, goods);
  1033. }
  1034.  
  1035. void ProtocolGame::parseCloseNpcTrade(const InputMessagePtr&)
  1036. {
  1037. g_game.processCloseNpcTrade();
  1038. }
  1039.  
  1040. void ProtocolGame::parseOwnTrade(const InputMessagePtr& msg)
  1041. {
  1042. std::string name = g_game.formatCreatureName(msg->getString());
  1043. int count = msg->getU8();
  1044.  
  1045. std::vector<ItemPtr> items(count);
  1046. for(int i = 0; i < count; i++)
  1047. items[i] = getItem(msg);
  1048.  
  1049. g_game.processOwnTrade(name, items);
  1050. }
  1051.  
  1052. void ProtocolGame::parseCounterTrade(const InputMessagePtr& msg)
  1053. {
  1054. std::string name = g_game.formatCreatureName(msg->getString());
  1055. int count = msg->getU8();
  1056.  
  1057. std::vector<ItemPtr> items(count);
  1058. for(int i = 0; i < count; i++)
  1059. items[i] = getItem(msg);
  1060.  
  1061. g_game.processCounterTrade(name, items);
  1062. }
  1063.  
  1064. void ProtocolGame::parseCloseTrade(const InputMessagePtr&)
  1065. {
  1066. g_game.processCloseTrade();
  1067. }
  1068.  
  1069. void ProtocolGame::parseWorldLight(const InputMessagePtr& msg)
  1070. {
  1071. Light light;
  1072. light.intensity = msg->getU8();
  1073. light.color = msg->getU8();
  1074.  
  1075. g_map.setLight(light);
  1076. }
  1077.  
  1078. void ProtocolGame::parseMagicEffect(const InputMessagePtr& msg)
  1079. {
  1080. Position pos = getPosition(msg);
  1081. int effectId;
  1082.  
  1083. effectId = msg->getU16();
  1084.  
  1085. if(!g_things.isValidDatId(effectId, ThingCategoryEffect)) {
  1086. g_logger.traceError(stdext::format("invalid effect id %d", effectId));
  1087. return;
  1088. }
  1089.  
  1090. EffectPtr effect = EffectPtr(new Effect());
  1091. effect->setId(effectId);
  1092. g_map.addThing(effect, pos);
  1093. }
  1094.  
  1095. void ProtocolGame::parseAnimatedText(const InputMessagePtr& msg)
  1096. {
  1097. Position position = getPosition(msg);
  1098. int color = msg->getU8();
  1099. std::string text = msg->getString();
  1100.  
  1101. AnimatedTextPtr animatedText = AnimatedTextPtr(new AnimatedText);
  1102. animatedText->setColor(color);
  1103. animatedText->setText(text);
  1104. g_map.addThing(animatedText, position);
  1105. }
  1106.  
  1107. void ProtocolGame::parseDistanceMissile(const InputMessagePtr& msg)
  1108. {
  1109. Position fromPos = getPosition(msg);
  1110. Position toPos = getPosition(msg);
  1111. int shotId = msg->getU16();
  1112.  
  1113. if(!g_things.isValidDatId(shotId, ThingCategoryMissile)) {
  1114. g_logger.traceError(stdext::format("invalid missile id %d", shotId));
  1115. return;
  1116. }
  1117.  
  1118. MissilePtr missile = MissilePtr(new Missile());
  1119. missile->setId(shotId);
  1120. missile->setPath(fromPos, toPos);
  1121. g_map.addThing(missile, fromPos);
  1122. }
  1123.  
  1124. void ProtocolGame::parseCreatureMark(const InputMessagePtr& msg)
  1125. {
  1126. uint id = msg->getU32();
  1127. int color = msg->getU8();
  1128.  
  1129. CreaturePtr creature = g_map.getCreatureById(id);
  1130. if(creature)
  1131. creature->addTimedSquare(color);
  1132. else
  1133. g_logger.traceError("could not get creature");
  1134. }
  1135.  
  1136. void ProtocolGame::parseTrappers(const InputMessagePtr& msg)
  1137. {
  1138. int numTrappers = msg->getU8();
  1139.  
  1140. if(numTrappers > 8)
  1141. g_logger.traceError("too many trappers");
  1142.  
  1143. for(int i=0;i<numTrappers;++i) {
  1144. uint id = msg->getU32();
  1145. CreaturePtr creature = g_map.getCreatureById(id);
  1146. if(creature) {
  1147. //TODO: set creature as trapper
  1148. } else
  1149. g_logger.traceError("could not get creature");
  1150. }
  1151. }
  1152.  
  1153. void ProtocolGame::parseCreatureHealth(const InputMessagePtr& msg)
  1154. {
  1155. uint id = msg->getU32();
  1156. int healthPercent = msg->getU8();
  1157.  
  1158. CreaturePtr creature = g_map.getCreatureById(id);
  1159. if(creature)
  1160. creature->setHealthPercent(healthPercent);
  1161.  
  1162. // some servers has a bug in get spectators and sends unknown creatures updates
  1163. // so this code is disabled
  1164. /*
  1165. else
  1166. g_logger.traceError("could not get creature");
  1167. */
  1168. }
  1169.  
  1170. void ProtocolGame::parseCreatureLight(const InputMessagePtr& msg)
  1171. {
  1172. uint id = msg->getU32();
  1173.  
  1174. Light light;
  1175. light.intensity = msg->getU8();
  1176. light.color = msg->getU8();
  1177.  
  1178. CreaturePtr creature = g_map.getCreatureById(id);
  1179. if(creature)
  1180. creature->setLight(light);
  1181. else
  1182. g_logger.traceError("could not get creature");
  1183. }
  1184.  
  1185. void ProtocolGame::parseCreatureOutfit(const InputMessagePtr& msg)
  1186. {
  1187. uint id = msg->getU32();
  1188. Outfit outfit = getOutfit(msg);
  1189.  
  1190. CreaturePtr creature = g_map.getCreatureById(id);
  1191. if(creature)
  1192. creature->setOutfit(outfit);
  1193. else
  1194. g_logger.traceError("could not get creature");
  1195. }
  1196.  
  1197. void ProtocolGame::parseCreatureSpeed(const InputMessagePtr& msg)
  1198. {
  1199. uint id = msg->getU32();
  1200.  
  1201. int baseSpeed = -1;
  1202. if(g_game.getClientVersion() >= 1059)
  1203. baseSpeed = msg->getU16();
  1204.  
  1205. int speed = msg->getU16();
  1206.  
  1207. CreaturePtr creature = g_map.getCreatureById(id);
  1208. if(creature) {
  1209. creature->setSpeed(speed);
  1210. if(baseSpeed != -1)
  1211. creature->setBaseSpeed(baseSpeed);
  1212. }
  1213.  
  1214. // some servers has a bug in get spectators and sends unknown creatures updates
  1215. // so this code is disabled
  1216. /*
  1217. else
  1218. g_logger.traceError("could not get creature");
  1219. */
  1220. }
  1221.  
  1222. void ProtocolGame::parseCreatureSkulls(const InputMessagePtr& msg)
  1223. {
  1224. uint id = msg->getU32();
  1225. int skull = msg->getU8();
  1226.  
  1227. CreaturePtr creature = g_map.getCreatureById(id);
  1228. if(creature)
  1229. creature->setSkull(skull);
  1230. else
  1231. g_logger.traceError("could not get creature");
  1232. }
  1233.  
  1234. void ProtocolGame::parseCreatureShields(const InputMessagePtr& msg)
  1235. {
  1236. uint id = msg->getU32();
  1237. int shield = msg->getU8();
  1238.  
  1239. CreaturePtr creature = g_map.getCreatureById(id);
  1240. if(creature)
  1241. creature->setShield(shield);
  1242. else
  1243. g_logger.traceError("could not get creature");
  1244. }
  1245.  
  1246. void ProtocolGame::parseCreatureUnpass(const InputMessagePtr& msg)
  1247. {
  1248. uint id = msg->getU32();
  1249. bool unpass = msg->getU8();
  1250.  
  1251. CreaturePtr creature = g_map.getCreatureById(id);
  1252. if(creature)
  1253. creature->setPassable(!unpass);
  1254. else
  1255. g_logger.traceError("could not get creature");
  1256. }
  1257.  
  1258. void ProtocolGame::parseEditText(const InputMessagePtr& msg)
  1259. {
  1260. uint id = msg->getU32();
  1261.  
  1262. int itemId;
  1263. if(g_game.getClientVersion() >= 1010) {
  1264. // TODO: processEditText with ItemPtr as parameter
  1265. ItemPtr item = getItem(msg);
  1266. itemId = item->getId();
  1267. } else
  1268. itemId = msg->getU16();
  1269.  
  1270. int maxLength = msg->getU16();
  1271. std::string text = msg->getString();
  1272.  
  1273. std::string writer = msg->getString();
  1274. std::string date = "";
  1275. if(g_game.getFeature(Otc::GameWritableDate))
  1276. date = msg->getString();
  1277.  
  1278. g_game.processEditText(id, itemId, maxLength, text, writer, date);
  1279. }
  1280.  
  1281. void ProtocolGame::parseEditList(const InputMessagePtr& msg)
  1282. {
  1283. int doorId = msg->getU8();
  1284. uint id = msg->getU32();
  1285. const std::string& text = msg->getString();
  1286.  
  1287. g_game.processEditList(id, doorId, text);
  1288. }
  1289.  
  1290. void ProtocolGame::parsePremiumTrigger(const InputMessagePtr& msg)
  1291. {
  1292. int triggerCount = msg->getU8();
  1293. std::vector<int> triggers;
  1294. for(int i=0;i<triggerCount;++i) {
  1295. triggers.push_back(msg->getU8());
  1296. }
  1297.  
  1298. if(g_game.getClientVersion() <= 1096) {
  1299. bool something = msg->getU8() == 1;
  1300. }
  1301. }
  1302.  
  1303. void ProtocolGame::parsePlayerInfo(const InputMessagePtr& msg)
  1304. {
  1305. bool premium = msg->getU8(); // premium
  1306. if(g_game.getFeature(Otc::GamePremiumExpiration))
  1307. int premiumEx = msg->getU32(); // premium expiration used for premium advertisement
  1308. int vocation = msg->getU8(); // vocation
  1309.  
  1310. int spellCount = msg->getU16();
  1311. std::vector<int> spells;
  1312. for(int i=0;i<spellCount;++i)
  1313. spells.push_back(msg->getU8()); // spell id
  1314.  
  1315. m_localPlayer->setPremium(premium);
  1316. m_localPlayer->setVocation(vocation);
  1317. m_localPlayer->setSpells(spells);
  1318. }
  1319.  
  1320. void ProtocolGame::parsePlayerStats(const InputMessagePtr& msg)
  1321. {
  1322. double health;
  1323. double maxHealth;
  1324.  
  1325. if(g_game.getFeature(Otc::GameDoubleHealth)) {
  1326. health = msg->getU32();
  1327. maxHealth = msg->getU32();
  1328. } else {
  1329. health = msg->getU16();
  1330. maxHealth = msg->getU16();
  1331. }
  1332.  
  1333. double freeCapacity;
  1334. if(g_game.getFeature(Otc::GameDoubleFreeCapacity))
  1335. freeCapacity = msg->getU32() / 100.0;
  1336. else
  1337. freeCapacity = msg->getU16() / 100.0;
  1338.  
  1339. double totalCapacity = 0;
  1340. if(g_game.getFeature(Otc::GameTotalCapacity))
  1341. totalCapacity = msg->getU32() / 100.0;
  1342.  
  1343. double experience;
  1344. if(g_game.getFeature(Otc::GameDoubleExperience))
  1345. experience = msg->getU64();
  1346. else
  1347. experience = msg->getU32();
  1348.  
  1349. double level = msg->getU16();
  1350. double levelPercent = msg->getU8();
  1351.  
  1352. if(g_game.getFeature(Otc::GameExperienceBonus)) {
  1353. if(g_game.getClientVersion() <= 1096) {
  1354. double experienceBonus = msg->getDouble();
  1355. } else {
  1356. int baseXpGain = msg->getU16();
  1357. int voucherAddend = msg->getU16();
  1358. int grindingAddend = msg->getU16();
  1359. int storeBoostAddend = msg->getU16();
  1360. int huntingBoostFactor = msg->getU16();
  1361. }
  1362. }
  1363.  
  1364. double mana;
  1365. double maxMana;
  1366.  
  1367. if(g_game.getFeature(Otc::GameDoubleHealth)) {
  1368. mana = msg->getU32();
  1369. maxMana = msg->getU32();
  1370. } else {
  1371. mana = msg->getU16();
  1372. maxMana = msg->getU16();
  1373. }
  1374.  
  1375. double magicLevel = msg->getU8();
  1376.  
  1377. double baseMagicLevel;
  1378. if(g_game.getFeature(Otc::GameSkillsBase))
  1379. baseMagicLevel = msg->getU8();
  1380. else
  1381. baseMagicLevel = magicLevel;
  1382.  
  1383. double magicLevelPercent = msg->getU8();
  1384. double soul = msg->getU8();
  1385. double stamina = 0;
  1386. if(g_game.getFeature(Otc::GamePlayerStamina))
  1387. stamina = msg->getU16();
  1388.  
  1389. double baseSpeed = 0;
  1390. if(g_game.getFeature(Otc::GameSkillsBase))
  1391. baseSpeed = msg->getU16();
  1392.  
  1393. double regeneration = 0;
  1394. if(g_game.getFeature(Otc::GamePlayerRegenerationTime))
  1395. regeneration = msg->getU16();
  1396.  
  1397. double training = 0;
  1398. if(g_game.getFeature(Otc::GameOfflineTrainingTime)) {
  1399. training = msg->getU16();
  1400. if(g_game.getClientVersion() >= 1097) {
  1401. int remainingStoreXpBoostSeconds = msg->getU16();
  1402. bool canBuyMoreStoreXpBoosts = msg->getU8();
  1403. }
  1404. }
  1405.  
  1406. m_localPlayer->setHealth(health, maxHealth);
  1407. m_localPlayer->setFreeCapacity(freeCapacity);
  1408. m_localPlayer->setTotalCapacity(totalCapacity);
  1409. m_localPlayer->setExperience(experience);
  1410. m_localPlayer->setLevel(level, levelPercent);
  1411. m_localPlayer->setMana(mana, maxMana);
  1412. m_localPlayer->setMagicLevel(magicLevel, magicLevelPercent);
  1413. m_localPlayer->setBaseMagicLevel(baseMagicLevel);
  1414. m_localPlayer->setStamina(stamina);
  1415. m_localPlayer->setSoul(soul);
  1416. m_localPlayer->setBaseSpeed(baseSpeed);
  1417. m_localPlayer->setRegenerationTime(regeneration);
  1418. m_localPlayer->setOfflineTrainingTime(training);
  1419. }
  1420.  
  1421. void ProtocolGame::parsePlayerSkills(const InputMessagePtr& msg)
  1422. {
  1423. int lastSkill = Otc::Fishing + 1;
  1424. if(g_game.getFeature(Otc::GameAdditionalSkills))
  1425. lastSkill = Otc::LastSkill;
  1426.  
  1427. for(int skill = 0; skill < lastSkill; skill++) {
  1428. int level;
  1429.  
  1430. if(g_game.getFeature(Otc::GameDoubleSkills))
  1431. level = msg->getU16();
  1432. else
  1433. level = msg->getU8();
  1434.  
  1435. int baseLevel;
  1436. if(g_game.getFeature(Otc::GameSkillsBase))
  1437. if(g_game.getFeature(Otc::GameBaseSkillU16))
  1438. baseLevel = msg->getU16();
  1439. else
  1440. baseLevel = msg->getU8();
  1441. else
  1442. baseLevel = level;
  1443.  
  1444. int levelPercent = 0;
  1445. // Critical, Life Leech and Mana Leech have no level percent
  1446. if(skill <= Otc::Fishing)
  1447. levelPercent = msg->getU8();
  1448.  
  1449. m_localPlayer->setSkill((Otc::Skill)skill, level, levelPercent);
  1450. m_localPlayer->setBaseSkill((Otc::Skill)skill, baseLevel);
  1451. }
  1452. }
  1453.  
  1454. void ProtocolGame::parsePlayerState(const InputMessagePtr& msg)
  1455. {
  1456. int states;
  1457. if(g_game.getFeature(Otc::GamePlayerStateU16))
  1458. states = msg->getU16();
  1459. else
  1460. states = msg->getU8();
  1461.  
  1462. m_localPlayer->setStates(states);
  1463. }
  1464.  
  1465. void ProtocolGame::parsePlayerCancelAttack(const InputMessagePtr& msg)
  1466. {
  1467. uint seq = 0;
  1468. if(g_game.getFeature(Otc::GameAttackSeq))
  1469. seq = msg->getU32();
  1470.  
  1471. g_game.processAttackCancel(seq);
  1472. }
  1473.  
  1474.  
  1475. void ProtocolGame::parsePlayerModes(const InputMessagePtr& msg)
  1476. {
  1477. int fightMode = msg->getU8();
  1478. int chaseMode = msg->getU8();
  1479. bool safeMode = msg->getU8();
  1480.  
  1481. int pvpMode = 0;
  1482. if(g_game.getFeature(Otc::GamePVPMode))
  1483. pvpMode = msg->getU8();
  1484.  
  1485. g_game.processPlayerModes((Otc::FightModes)fightMode, (Otc::ChaseModes)chaseMode, safeMode, (Otc::PVPModes)pvpMode);
  1486. }
  1487.  
  1488. void ProtocolGame::parseSpellCooldown(const InputMessagePtr& msg)
  1489. {
  1490. int spellId = msg->getU8();
  1491. int delay = msg->getU32();
  1492.  
  1493. g_lua.callGlobalField("g_game", "onSpellCooldown", spellId, delay);
  1494. }
  1495.  
  1496. void ProtocolGame::parseSpellGroupCooldown(const InputMessagePtr& msg)
  1497. {
  1498. int groupId = msg->getU8();
  1499. int delay = msg->getU32();
  1500.  
  1501. g_lua.callGlobalField("g_game", "onSpellGroupCooldown", groupId, delay);
  1502. }
  1503.  
  1504. void ProtocolGame::parseMultiUseCooldown(const InputMessagePtr& msg)
  1505. {
  1506. int delay = msg->getU32();
  1507.  
  1508. g_lua.callGlobalField("g_game", "onMultiUseCooldown", delay);
  1509. }
  1510.  
  1511. void ProtocolGame::parseTalk(const InputMessagePtr& msg)
  1512. {
  1513. if(g_game.getFeature(Otc::GameMessageStatements))
  1514. msg->getU32(); // channel statement guid
  1515.  
  1516. std::string name = g_game.formatCreatureName(msg->getString());
  1517.  
  1518. int level = 0;
  1519. if(g_game.getFeature(Otc::GameMessageLevel))
  1520. level = msg->getU16();
  1521.  
  1522. Otc::MessageMode mode = Proto::translateMessageModeFromServer(msg->getU8());
  1523. int channelId = 0;
  1524. Position pos;
  1525.  
  1526. switch(mode) {
  1527. case Otc::MessageSay:
  1528. case Otc::MessageWhisper:
  1529. case Otc::MessageYell:
  1530. case Otc::MessageMonsterSay:
  1531. case Otc::MessageMonsterYell:
  1532. case Otc::MessageNpcTo:
  1533. case Otc::MessageBarkLow:
  1534. case Otc::MessageBarkLoud:
  1535. case Otc::MessageSpell:
  1536. case Otc::MessageNpcFromStartBlock:
  1537. pos = getPosition(msg);
  1538. break;
  1539. case Otc::MessageChannel:
  1540. case Otc::MessageChannelManagement:
  1541. case Otc::MessageChannelHighlight:
  1542. case Otc::MessageGamemasterChannel:
  1543. channelId = msg->getU16();
  1544. break;
  1545. case Otc::MessageNpcFrom:
  1546. case Otc::MessagePrivateFrom:
  1547. case Otc::MessageGamemasterBroadcast:
  1548. case Otc::MessageGamemasterPrivateFrom:
  1549. case Otc::MessageRVRAnswer:
  1550. case Otc::MessageRVRContinue:
  1551. break;
  1552. case Otc::MessageRVRChannel:
  1553. msg->getU32();
  1554. break;
  1555. default:
  1556. stdext::throw_exception(stdext::format("unknown message mode %d", mode));
  1557. break;
  1558. }
  1559.  
  1560. std::string text = msg->getString();
  1561.  
  1562. g_game.processTalk(name, level, mode, text, channelId, pos);
  1563. }
  1564.  
  1565. void ProtocolGame::parseChannelList(const InputMessagePtr& msg)
  1566. {
  1567. int count = msg->getU8();
  1568. std::vector<std::tuple<int, std::string> > channelList;
  1569. for(int i = 0; i < count; i++) {
  1570. int id = msg->getU16();
  1571. std::string name = msg->getString();
  1572. channelList.push_back(std::make_tuple(id, name));
  1573. }
  1574.  
  1575. g_game.processChannelList(channelList);
  1576. }
  1577.  
  1578. void ProtocolGame::parseOpenChannel(const InputMessagePtr& msg)
  1579. {
  1580. int channelId = msg->getU16();
  1581. std::string name = msg->getString();
  1582.  
  1583. if(g_game.getFeature(Otc::GameChannelPlayerList)) {
  1584. int joinedPlayers = msg->getU16();
  1585. for(int i=0;i<joinedPlayers;++i)
  1586. g_game.formatCreatureName(msg->getString()); // player name
  1587. int invitedPlayers = msg->getU16();
  1588. for(int i=0;i<invitedPlayers;++i)
  1589. g_game.formatCreatureName(msg->getString()); // player name
  1590. }
  1591.  
  1592. g_game.processOpenChannel(channelId, name);
  1593. }
  1594.  
  1595. void ProtocolGame::parseOpenPrivateChannel(const InputMessagePtr& msg)
  1596. {
  1597. std::string name = g_game.formatCreatureName(msg->getString());
  1598.  
  1599. g_game.processOpenPrivateChannel(name);
  1600. }
  1601.  
  1602. void ProtocolGame::parseOpenOwnPrivateChannel(const InputMessagePtr& msg)
  1603. {
  1604. int channelId = msg->getU16();
  1605. std::string name = msg->getString();
  1606.  
  1607. g_game.processOpenOwnPrivateChannel(channelId, name);
  1608. }
  1609.  
  1610. void ProtocolGame::parseCloseChannel(const InputMessagePtr& msg)
  1611. {
  1612. int channelId = msg->getU16();
  1613.  
  1614. g_game.processCloseChannel(channelId);
  1615. }
  1616.  
  1617. void ProtocolGame::parseRuleViolationChannel(const InputMessagePtr& msg)
  1618. {
  1619. int channelId = msg->getU16();
  1620.  
  1621. g_game.processRuleViolationChannel(channelId);
  1622. }
  1623.  
  1624. void ProtocolGame::parseRuleViolationRemove(const InputMessagePtr& msg)
  1625. {
  1626. std::string name = msg->getString();
  1627.  
  1628. g_game.processRuleViolationRemove(name);
  1629. }
  1630.  
  1631. void ProtocolGame::parseRuleViolationCancel(const InputMessagePtr& msg)
  1632. {
  1633. std::string name = msg->getString();
  1634.  
  1635. g_game.processRuleViolationCancel(name);
  1636. }
  1637.  
  1638. void ProtocolGame::parseRuleViolationLock(const InputMessagePtr& msg)
  1639. {
  1640. g_game.processRuleViolationLock();
  1641. }
  1642.  
  1643. void ProtocolGame::parseTextMessage(const InputMessagePtr& msg)
  1644. {
  1645. int code = msg->getU8();
  1646. Otc::MessageMode mode = Proto::translateMessageModeFromServer(code);
  1647. std::string text;
  1648.  
  1649. switch(mode) {
  1650. case Otc::MessageChannelManagement: {
  1651. int channel = msg->getU16();
  1652. text = msg->getString();
  1653. break;
  1654. }
  1655. case Otc::MessageGuild:
  1656. case Otc::MessagePartyManagement:
  1657. case Otc::MessageParty: {
  1658. int channel = msg->getU16();
  1659. text = msg->getString();
  1660. break;
  1661. }
  1662. case Otc::MessageDamageDealed:
  1663. case Otc::MessageDamageReceived:
  1664. case Otc::MessageDamageOthers: {
  1665. Position pos = getPosition(msg);
  1666. uint value[2];
  1667. int color[2];
  1668.  
  1669. // physical damage
  1670. value[0] = msg->getU32();
  1671. color[0] = msg->getU8();
  1672.  
  1673. // magic damage
  1674. value[1] = msg->getU32();
  1675. color[1] = msg->getU8();
  1676. text = msg->getString();
  1677.  
  1678. for(int i=0;i<2;++i) {
  1679. if(value[i] == 0)
  1680. continue;
  1681. AnimatedTextPtr animatedText = AnimatedTextPtr(new AnimatedText);
  1682. animatedText->setColor(color[i]);
  1683. animatedText->setText(stdext::to_string(value[i]));
  1684. g_map.addThing(animatedText, pos);
  1685. }
  1686. break;
  1687. }
  1688. case Otc::MessageHeal:
  1689. case Otc::MessageMana:
  1690. case Otc::MessageExp:
  1691. case Otc::MessageHealOthers:
  1692. case Otc::MessageExpOthers: {
  1693. Position pos = getPosition(msg);
  1694. uint value = msg->getU32();
  1695. int color = msg->getU8();
  1696. text = msg->getString();
  1697.  
  1698. AnimatedTextPtr animatedText = AnimatedTextPtr(new AnimatedText);
  1699. animatedText->setColor(color);
  1700. animatedText->setText(stdext::to_string(value));
  1701. g_map.addThing(animatedText, pos);
  1702. break;
  1703. }
  1704. case Otc::MessageInvalid:
  1705. stdext::throw_exception(stdext::format("unknown message mode %d", mode));
  1706. break;
  1707. default:
  1708. text = msg->getString();
  1709. break;
  1710. }
  1711.  
  1712. g_game.processTextMessage(mode, text);
  1713. }
  1714.  
  1715. void ProtocolGame::parseCancelWalk(const InputMessagePtr& msg)
  1716. {
  1717. Otc::Direction direction = (Otc::Direction)msg->getU8();
  1718.  
  1719. g_game.processWalkCancel(direction);
  1720. }
  1721.  
  1722. void ProtocolGame::parseWalkWait(const InputMessagePtr& msg)
  1723. {
  1724. int millis = msg->getU16();
  1725. m_localPlayer->lockWalk(millis);
  1726. }
  1727.  
  1728. void ProtocolGame::parseFloorChangeUp(const InputMessagePtr& msg)
  1729. {
  1730. Position pos;
  1731. if(g_game.getFeature(Otc::GameMapMovePosition))
  1732. pos = getPosition(msg);
  1733. else
  1734. pos = g_map.getCentralPosition();
  1735. AwareRange range = g_map.getAwareRange();
  1736. pos.z--;
  1737.  
  1738. int skip = 0;
  1739. if(pos.z == Otc::SEA_FLOOR)
  1740. for(int i = Otc::SEA_FLOOR - Otc::AWARE_UNDEGROUND_FLOOR_RANGE; i >= 0; i--)
  1741. skip = setFloorDescription(msg, pos.x - range.left, pos.y - range.top, i, range.horizontal(), range.vertical(), 8 - i, skip);
  1742. else if(pos.z > Otc::SEA_FLOOR)
  1743. skip = setFloorDescription(msg, pos.x - range.left, pos.y - range.top, pos.z - Otc::AWARE_UNDEGROUND_FLOOR_RANGE, range.horizontal(), range.vertical(), 3, skip);
  1744.  
  1745. pos.x++;
  1746. pos.y++;
  1747. g_map.setCentralPosition(pos);
  1748. }
  1749.  
  1750. void ProtocolGame::parseFloorChangeDown(const InputMessagePtr& msg)
  1751. {
  1752. Position pos;
  1753. if(g_game.getFeature(Otc::GameMapMovePosition))
  1754. pos = getPosition(msg);
  1755. else
  1756. pos = g_map.getCentralPosition();
  1757. AwareRange range = g_map.getAwareRange();
  1758. pos.z++;
  1759.  
  1760. int skip = 0;
  1761. if(pos.z == Otc::UNDERGROUND_FLOOR) {
  1762. int j, i;
  1763. for(i = pos.z, j = -1; i <= pos.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE; ++i, --j)
  1764. skip = setFloorDescription(msg, pos.x - range.left, pos.y - range.top, i, range.horizontal(), range.vertical(), j, skip);
  1765. }
  1766. else if(pos.z > Otc::UNDERGROUND_FLOOR && pos.z < Otc::MAX_Z-1)
  1767. skip = setFloorDescription(msg, pos.x - range.left, pos.y - range.top, pos.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE, range.horizontal(), range.vertical(), -3, skip);
  1768.  
  1769. pos.x--;
  1770. pos.y--;
  1771. g_map.setCentralPosition(pos);
  1772. }
  1773.  
  1774. void ProtocolGame::parseOpenOutfitWindow(const InputMessagePtr& msg)
  1775. {
  1776. Outfit currentOutfit = getOutfit(msg);
  1777. std::vector<std::tuple<int, std::string, int> > outfitList;
  1778.  
  1779. if(g_game.getFeature(Otc::GameNewOutfitProtocol)) {
  1780. int outfitCount = msg->getU8();
  1781. for(int i = 0; i < outfitCount; i++) {
  1782. int outfitId = msg->getU16();
  1783. std::string outfitName = msg->getString();
  1784. int outfitAddons = msg->getU8();
  1785.  
  1786. outfitList.push_back(std::make_tuple(outfitId, outfitName, outfitAddons));
  1787. }
  1788. } else {
  1789. int outfitStart, outfitEnd;
  1790. if(g_game.getFeature(Otc::GameLooktypeU16)) {
  1791. outfitStart = msg->getU16();
  1792. outfitEnd = msg->getU16();
  1793. } else {
  1794. outfitStart = msg->getU8();
  1795. outfitEnd = msg->getU8();
  1796. }
  1797.  
  1798. for(int i = outfitStart; i <= outfitEnd; i++)
  1799. outfitList.push_back(std::make_tuple(i, "", 0));
  1800. }
  1801.  
  1802. std::vector<std::tuple<int, std::string> > mountList;
  1803. if(g_game.getFeature(Otc::GamePlayerMounts)) {
  1804. int mountCount = msg->getU8();
  1805. for(int i = 0; i < mountCount; ++i) {
  1806. int mountId = msg->getU16(); // mount type
  1807. std::string mountName = msg->getString(); // mount name
  1808.  
  1809. mountList.push_back(std::make_tuple(mountId, mountName));
  1810. }
  1811. }
  1812.  
  1813. g_game.processOpenOutfitWindow(currentOutfit, outfitList, mountList);
  1814. }
  1815.  
  1816. void ProtocolGame::parseVipAdd(const InputMessagePtr& msg)
  1817. {
  1818. uint id, iconId = 0, status;
  1819. std::string name, desc = "";
  1820. bool notifyLogin = false;
  1821.  
  1822. id = msg->getU32();
  1823. name = g_game.formatCreatureName(msg->getString());
  1824. if(g_game.getFeature(Otc::GameAdditionalVipInfo)) {
  1825. desc = msg->getString();
  1826. iconId = msg->getU32();
  1827. notifyLogin = msg->getU8();
  1828. }
  1829. status = msg->getU8();
  1830.  
  1831. g_game.processVipAdd(id, name, status, desc, iconId, notifyLogin);
  1832. }
  1833.  
  1834. void ProtocolGame::parseVipState(const InputMessagePtr& msg)
  1835. {
  1836. uint id = msg->getU32();
  1837. if(g_game.getFeature(Otc::GameLoginPending)) {
  1838. uint status = msg->getU8();
  1839. g_game.processVipStateChange(id, status);
  1840. }
  1841. else {
  1842. g_game.processVipStateChange(id, 1);
  1843. }
  1844. }
  1845.  
  1846. void ProtocolGame::parseVipLogout(const InputMessagePtr& msg)
  1847. {
  1848. uint id = msg->getU32();
  1849. g_game.processVipStateChange(id, 0);
  1850. }
  1851.  
  1852. void ProtocolGame::parseTutorialHint(const InputMessagePtr& msg)
  1853. {
  1854. int id = msg->getU8();
  1855. g_game.processTutorialHint(id);
  1856. }
  1857.  
  1858. void ProtocolGame::parseAutomapFlag(const InputMessagePtr& msg)
  1859. {
  1860. Position pos = getPosition(msg);
  1861. int icon = msg->getU8();
  1862. std::string description = msg->getString();
  1863.  
  1864. bool remove = false;
  1865. if(g_game.getFeature(Otc::GameMinimapRemove))
  1866. remove = msg->getU8() != 0;
  1867.  
  1868. if(!remove)
  1869. g_game.processAddAutomapFlag(pos, icon, description);
  1870. else
  1871. g_game.processRemoveAutomapFlag(pos, icon, description);
  1872. }
  1873.  
  1874. void ProtocolGame::parseQuestLog(const InputMessagePtr& msg)
  1875. {
  1876. std::vector<std::tuple<int, std::string, bool> > questList;
  1877. int questsCount = msg->getU16();
  1878. for(int i = 0; i < questsCount; i++) {
  1879. int id = msg->getU16();
  1880. std::string name = msg->getString();
  1881. bool completed = msg->getU8();
  1882. questList.push_back(std::make_tuple(id, name, completed));
  1883. }
  1884.  
  1885. g_game.processQuestLog(questList);
  1886. }
  1887.  
  1888. void ProtocolGame::parseQuestLine(const InputMessagePtr& msg)
  1889. {
  1890. std::vector<std::tuple<std::string, std::string>> questMissions;
  1891. int questId = msg->getU16();
  1892. int missionCount = msg->getU8();
  1893. for(int i = 0; i < missionCount; i++) {
  1894. std::string missionName = msg->getString();
  1895. std::string missionDescrition = msg->getString();
  1896. questMissions.push_back(std::make_tuple(missionName, missionDescrition));
  1897. }
  1898.  
  1899. g_game.processQuestLine(questId, questMissions);
  1900. }
  1901.  
  1902. void ProtocolGame::parseChannelEvent(const InputMessagePtr& msg)
  1903. {
  1904. uint16 channelId = msg->getU16();
  1905. std::string name = g_game.formatCreatureName(msg->getString());
  1906. uint8 type = msg->getU8();
  1907.  
  1908. g_lua.callGlobalField("g_game", "onChannelEvent", channelId, name, type);
  1909. }
  1910.  
  1911. void ProtocolGame::parseItemInfo(const InputMessagePtr& msg)
  1912. {
  1913. std::vector<std::tuple<ItemPtr, std::string>> list;
  1914. int size = msg->getU8();
  1915. for(int i=0;i<size;++i) {
  1916. ItemPtr item(new Item);
  1917. item->setId(msg->getU16());
  1918. item->setCountOrSubType(msg->getU8());
  1919.  
  1920. std::string desc = msg->getString();
  1921. list.push_back(std::make_tuple(item, desc));
  1922. }
  1923.  
  1924. g_lua.callGlobalField("g_game", "onItemInfo", list);
  1925. }
  1926.  
  1927. void ProtocolGame::parsePlayerInventory(const InputMessagePtr& msg)
  1928. {
  1929. int size = msg->getU16();
  1930. for(int i=0;i<size;++i) {
  1931. msg->getU16(); // id
  1932. msg->getU8(); // subtype
  1933. msg->getU16(); // count
  1934. }
  1935. }
  1936.  
  1937. void ProtocolGame::parseModalDialog(const InputMessagePtr& msg)
  1938. {
  1939. uint32 id = msg->getU32();
  1940. std::string title = msg->getString();
  1941. std::string message = msg->getString();
  1942.  
  1943. int sizeButtons = msg->getU8();
  1944. std::vector<std::tuple<int, std::string> > buttonList;
  1945. for(int i = 0; i < sizeButtons; ++i) {
  1946. std::string value = msg->getString();
  1947. int id = msg->getU8();
  1948. buttonList.push_back(std::make_tuple(id, value));
  1949. }
  1950.  
  1951. int sizeChoices = msg->getU8();
  1952. std::vector<std::tuple<int, std::string> > choiceList;
  1953. for(int i = 0; i < sizeChoices; ++i) {
  1954. std::string value = msg->getString();
  1955. int id = msg->getU8();
  1956. choiceList.push_back(std::make_tuple(id, value));
  1957. }
  1958.  
  1959. int enterButton, escapeButton;
  1960. if(g_game.getClientVersion() > 970) {
  1961. escapeButton = msg->getU8();
  1962. enterButton = msg->getU8();
  1963. }
  1964. else {
  1965. enterButton = msg->getU8();
  1966. escapeButton = msg->getU8();
  1967. }
  1968.  
  1969. bool priority = msg->getU8() == 0x01;
  1970.  
  1971. g_game.processModalDialog(id, title, message, buttonList, enterButton, escapeButton, choiceList, priority);
  1972. }
  1973.  
  1974. void ProtocolGame::parseExtendedOpcode(const InputMessagePtr& msg)
  1975. {
  1976. int opcode = msg->getU8();
  1977. std::string buffer = msg->getString();
  1978.  
  1979. if(opcode == 0)
  1980. m_enableSendExtendedOpcode = true;
  1981. else if(opcode == 2)
  1982. parsePingBack(msg);
  1983. else
  1984. callLuaField("onExtendedOpcode", opcode, buffer);
  1985. }
  1986.  
  1987. void ProtocolGame::parseChangeMapAwareRange(const InputMessagePtr& msg)
  1988. {
  1989. int xrange = msg->getU8();
  1990. int yrange = msg->getU8();
  1991.  
  1992. AwareRange range;
  1993. range.left = xrange/2 - ((xrange+1) % 2);
  1994. range.right = xrange/2;
  1995. range.top = yrange/2 - ((yrange+1) % 2);
  1996. range.bottom = yrange/2;
  1997.  
  1998. g_map.setAwareRange(range);
  1999. g_lua.callGlobalField("g_game", "onMapChangeAwareRange", xrange, yrange);
  2000. }
  2001.  
  2002. void ProtocolGame::parseCreaturesMark(const InputMessagePtr& msg)
  2003. {
  2004. int len;
  2005. if(g_game.getClientVersion() >= 1035) {
  2006. len = 1;
  2007. } else {
  2008. len = msg->getU8();
  2009. }
  2010.  
  2011. for(int i=0; i<len; ++i) {
  2012. uint32 id = msg->getU32();
  2013. bool isPermanent = msg->getU8() != 1;
  2014. uint8 markType = msg->getU8();
  2015.  
  2016. CreaturePtr creature = g_map.getCreatureById(id);
  2017. if(creature) {
  2018. if(isPermanent) {
  2019. if(markType == 0xff)
  2020. creature->hideStaticSquare();
  2021. else
  2022. creature->showStaticSquare(Color::from8bit(markType));
  2023. } else
  2024. creature->addTimedSquare(markType);
  2025. } else
  2026. g_logger.traceError("could not get creature");
  2027. }
  2028. }
  2029.  
  2030. void ProtocolGame::parseCreatureType(const InputMessagePtr& msg)
  2031. {
  2032. uint32 id = msg->getU32();
  2033. uint8 type = msg->getU8();
  2034.  
  2035. CreaturePtr creature = g_map.getCreatureById(id);
  2036. if(creature)
  2037. creature->setType(type);
  2038. else
  2039. g_logger.traceError("could not get creature");
  2040. }
  2041.  
  2042. void ProtocolGame::setMapDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height)
  2043. {
  2044. int startz, endz, zstep;
  2045.  
  2046. if(z > Otc::SEA_FLOOR) {
  2047. startz = z - Otc::AWARE_UNDEGROUND_FLOOR_RANGE;
  2048. endz = std::min<int>(z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE, (int)Otc::MAX_Z);
  2049. zstep = 1;
  2050. }
  2051. else {
  2052. startz = Otc::SEA_FLOOR;
  2053. endz = 0;
  2054. zstep = -1;
  2055. }
  2056.  
  2057. int skip = 0;
  2058. for(int nz = startz; nz != endz + zstep; nz += zstep)
  2059. skip = setFloorDescription(msg, x, y, nz, width, height, z - nz, skip);
  2060. }
  2061.  
  2062. int ProtocolGame::setFloorDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height, int offset, int skip)
  2063. {
  2064. for(int nx = 0; nx < width; nx++) {
  2065. for(int ny = 0; ny < height; ny++) {
  2066. Position tilePos(x + nx + offset, y + ny + offset, z);
  2067. if(skip == 0)
  2068. skip = setTileDescription(msg, tilePos);
  2069. else {
  2070. g_map.cleanTile(tilePos);
  2071. skip--;
  2072. }
  2073. }
  2074. }
  2075. return skip;
  2076. }
  2077.  
  2078. int ProtocolGame::setTileDescription(const InputMessagePtr& msg, Position position)
  2079. {
  2080. g_map.cleanTile(position);
  2081.  
  2082. bool gotEffect = false;
  2083. for(int stackPos=0;stackPos<256;stackPos++) {
  2084. if(msg->peekU16() >= 0xff00)
  2085. return msg->getU16() & 0xff;
  2086.  
  2087. if(g_game.getFeature(Otc::GameEnvironmentEffect) && !gotEffect) {
  2088. msg->getU16(); // environment effect
  2089. gotEffect = true;
  2090. continue;
  2091. }
  2092.  
  2093. if(stackPos > 10)
  2094. g_logger.traceError(stdext::format("too many things, pos=%s, stackpos=%d", stdext::to_string(position), stackPos));
  2095.  
  2096. ThingPtr thing = getThing(msg);
  2097. g_map.addThing(thing, position, stackPos);
  2098. }
  2099.  
  2100. return 0;
  2101. }
  2102. Outfit ProtocolGame::getOutfit(const InputMessagePtr& msg)
  2103. {
  2104. Outfit outfit;
  2105.  
  2106. int lookType;
  2107. if(g_game.getFeature(Otc::GameLooktypeU16))
  2108. lookType = msg->getU16();
  2109. else
  2110. lookType = msg->getU8();
  2111.  
  2112. if(lookType != 0) {
  2113. outfit.setCategory(ThingCategoryCreature);
  2114. int head = msg->getU8();
  2115. int body = msg->getU8();
  2116. int legs = msg->getU8();
  2117. int feet = msg->getU8();
  2118. int addons = 0;
  2119. if(g_game.getFeature(Otc::GamePlayerAddons))
  2120. addons = msg->getU8();
  2121.  
  2122. if(!g_things.isValidDatId(lookType, ThingCategoryCreature)) {
  2123. g_logger.traceError(stdext::format("invalid outfit looktype %d", lookType));
  2124. lookType = 0;
  2125. }
  2126.  
  2127. outfit.setId(lookType);
  2128. outfit.setHead(head);
  2129. outfit.setBody(body);
  2130. outfit.setLegs(legs);
  2131. outfit.setFeet(feet);
  2132. outfit.setAddons(addons);
  2133. }
  2134. else {
  2135. int lookTypeEx = msg->getU16();
  2136. if(lookTypeEx == 0) {
  2137. outfit.setCategory(ThingCategoryEffect);
  2138. outfit.setAuxId(13); // invisible effect id
  2139. }
  2140. else {
  2141. if(!g_things.isValidDatId(lookTypeEx, ThingCategoryItem)) {
  2142. g_logger.traceError(stdext::format("invalid outfit looktypeex %d", lookTypeEx));
  2143. lookTypeEx = 0;
  2144. }
  2145. outfit.setCategory(ThingCategoryItem);
  2146. outfit.setAuxId(lookTypeEx);
  2147. }
  2148. }
  2149.  
  2150. if(g_game.getFeature(Otc::GamePlayerMounts)) {
  2151. int mount = msg->getU16();
  2152. outfit.setMount(mount);
  2153. }
  2154.  
  2155. return outfit;
  2156. }
  2157.  
  2158. ThingPtr ProtocolGame::getThing(const InputMessagePtr& msg)
  2159. {
  2160. ThingPtr thing;
  2161.  
  2162. int id = msg->getU16();
  2163.  
  2164. if(id == 0)
  2165. stdext::throw_exception("invalid thing id");
  2166. else if(id == Proto::UnknownCreature || id == Proto::OutdatedCreature || id == Proto::Creature)
  2167. thing = getCreature(msg, id);
  2168. else if(id == Proto::StaticText) // otclient only
  2169. thing = getStaticText(msg, id);
  2170. else // item
  2171. thing = getItem(msg, id);
  2172.  
  2173. return thing;
  2174. }
  2175.  
  2176. ThingPtr ProtocolGame::getMappedThing(const InputMessagePtr& msg)
  2177. {
  2178. ThingPtr thing;
  2179. uint16 x = msg->getU16();
  2180.  
  2181. if(x != 0xffff) {
  2182. Position pos;
  2183. pos.x = x;
  2184. pos.y = msg->getU16();
  2185. pos.z = msg->getU8();
  2186. uint8 stackpos = msg->getU8();
  2187. assert(stackpos != 255);
  2188. thing = g_map.getThing(pos, stackpos);
  2189. if(!thing)
  2190. g_logger.traceError(stdext::format("no thing at pos:%s, stackpos:%d", stdext::to_string(pos), stackpos));
  2191. } else {
  2192. uint32 id = msg->getU32();
  2193. thing = g_map.getCreatureById(id);
  2194. if(!thing)
  2195. g_logger.traceError(stdext::format("no creature with id %u", id));
  2196. }
  2197.  
  2198. return thing;
  2199. }
  2200.  
  2201. CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
  2202. {
  2203. if(type == 0)
  2204. type = msg->getU16();
  2205.  
  2206. CreaturePtr creature;
  2207. bool known = (type != Proto::UnknownCreature);
  2208. if(type == Proto::OutdatedCreature || type == Proto::UnknownCreature) {
  2209. if(known) {
  2210. uint id = msg->getU32();
  2211. creature = g_map.getCreatureById(id);
  2212. if(!creature)
  2213. g_logger.traceError("server said that a creature is known, but it's not");
  2214. } else {
  2215. uint removeId = msg->getU32();
  2216. g_map.removeCreatureById(removeId);
  2217.  
  2218. uint id = msg->getU32();
  2219.  
  2220. int creatureType;
  2221. if(g_game.getClientVersion() >= 910)
  2222. creatureType = msg->getU8();
  2223. else {
  2224. if(id >= Proto::PlayerStartId && id < Proto::PlayerEndId)
  2225. creatureType = Proto::CreatureTypePlayer;
  2226. else if(id >= Proto::MonsterStartId && id < Proto::MonsterEndId)
  2227. creatureType = Proto::CreatureTypeMonster;
  2228. else
  2229. creatureType = Proto::CreatureTypeNpc;
  2230. }
  2231.  
  2232. std::string name = g_game.formatCreatureName(msg->getString());
  2233.  
  2234. if(id == m_localPlayer->getId())
  2235. creature = m_localPlayer;
  2236. else if(creatureType == Proto::CreatureTypePlayer) {
  2237. // fixes a bug server side bug where GameInit is not sent and local player id is unknown
  2238. if(m_localPlayer->getId() == 0 && name == m_localPlayer->getName())
  2239. creature = m_localPlayer;
  2240. else
  2241. creature = PlayerPtr(new Player);
  2242. }
  2243. else if(creatureType == Proto::CreatureTypeMonster)
  2244. creature = MonsterPtr(new Monster);
  2245. else if(creatureType == Proto::CreatureTypeNpc)
  2246. creature = NpcPtr(new Npc);
  2247. else
  2248. g_logger.traceError("creature type is invalid");
  2249.  
  2250. if(creature) {
  2251. creature->setId(id);
  2252. creature->setName(name);
  2253.  
  2254. g_map.addCreature(creature);
  2255. }
  2256. }
  2257.  
  2258. int healthPercent = msg->getU8();
  2259. Otc::Direction direction = (Otc::Direction)msg->getU8();
  2260.  
  2261. // Archaic World Coloured Monsters/NPC names
  2262. uint8 namecolorR = msg->getU8();
  2263. uint8 namecolorG = msg->getU8();
  2264. uint8 namecolorB = msg->getU8();
  2265. Color nameColor = Color(namecolorR, namecolorG, namecolorB);
  2266.  
  2267.  
  2268. Outfit outfit = getOutfit(msg);
  2269.  
  2270. Light light;
  2271. light.intensity = msg->getU8();
  2272. light.color = msg->getU8();
  2273.  
  2274. int speed = msg->getU16();
  2275. int skull = msg->getU8();
  2276. int shield = msg->getU8();
  2277.  
  2278. // emblem is sent only when the creature is not known
  2279. int8 emblem = -1;
  2280. int8 creatureType = -1;
  2281. int8 icon = -1;
  2282. bool unpass = true;
  2283. uint8 mark;
  2284.  
  2285. if(g_game.getFeature(Otc::GameCreatureEmblems) && !known)
  2286. emblem = msg->getU8();
  2287.  
  2288. if(g_game.getFeature(Otc::GameThingMarks)) {
  2289. creatureType = msg->getU8();
  2290. }
  2291.  
  2292. if(g_game.getFeature(Otc::GameCreatureIcons)) {
  2293. icon = msg->getU8();
  2294. }
  2295.  
  2296. if(g_game.getFeature(Otc::GameThingMarks)) {
  2297. mark = msg->getU8(); // mark
  2298. msg->getU16(); // helpers
  2299.  
  2300. if(creature) {
  2301. if(mark == 0xff)
  2302. creature->hideStaticSquare();
  2303. else
  2304. creature->showStaticSquare(Color::from8bit(mark));
  2305. }
  2306. }
  2307.  
  2308. if(g_game.getClientVersion() >= 854)
  2309. unpass = msg->getU8();
  2310.  
  2311. if(creature) {
  2312. creature->setHealthPercent(healthPercent);
  2313. creature->setDirection(direction);
  2314. creature->setOutfit(outfit);
  2315. creature->setSpeed(speed);
  2316. creature->setSkull(skull);
  2317. creature->setShield(shield);
  2318. creature->setPassable(!unpass);
  2319. creature->setLight(light);
  2320.  
  2321. // Archaic World Coloured Monsters/NPC names
  2322. creature->setNameColor(nameColor);
  2323.  
  2324. if(emblem != -1)
  2325. creature->setEmblem(emblem);
  2326.  
  2327. if(creatureType != -1)
  2328. creature->setType(creatureType);
  2329.  
  2330. if(icon != -1)
  2331. creature->setIcon(icon);
  2332.  
  2333. if(creature == m_localPlayer && !m_localPlayer->isKnown())
  2334. m_localPlayer->setKnown(true);
  2335. }
  2336. } else if(type == Proto::Creature) {
  2337. uint id = msg->getU32();
  2338. creature = g_map.getCreatureById(id);
  2339.  
  2340. if(!creature)
  2341. g_logger.traceError("invalid creature");
  2342.  
  2343. Otc::Direction direction = (Otc::Direction)msg->getU8();
  2344. if(creature)
  2345. creature->turn(direction);
  2346.  
  2347. if(g_game.getClientVersion() >= 953) {
  2348. bool unpass = msg->getU8();
  2349.  
  2350. if(creature)
  2351. creature->setPassable(!unpass);
  2352. }
  2353.  
  2354. } else {
  2355. stdext::throw_exception("invalid creature opcode");
  2356. }
  2357.  
  2358. return creature;
  2359. }
  2360.  
  2361. ItemPtr ProtocolGame::getItem(const InputMessagePtr& msg, int id)
  2362. {
  2363. if(id == 0)
  2364. id = msg->getU16();
  2365.  
  2366. ItemPtr item = Item::create(id);
  2367. if(item->getId() == 0)
  2368. stdext::throw_exception(stdext::format("unable to create item with invalid id %d", id));
  2369.  
  2370. if(g_game.getFeature(Otc::GameThingMarks)) {
  2371. msg->getU8(); // mark
  2372. }
  2373.  
  2374. if(item->isStackable() || item->isFluidContainer() || item->isSplash() || item->isChargeable())
  2375. item->setCountOrSubType(msg->getU8());
  2376.  
  2377. if(g_game.getFeature(Otc::GameItemAnimationPhase)) {
  2378. if(item->getAnimationPhases() > 1) {
  2379. // 0x00 => automatic phase
  2380. // 0xFE => random phase
  2381. // 0xFF => async phase
  2382. msg->getU8();
  2383. //item->setPhase(msg->getU8());
  2384. }
  2385. }
  2386.  
  2387. return item;
  2388. }
  2389.  
  2390. StaticTextPtr ProtocolGame::getStaticText(const InputMessagePtr& msg, int id)
  2391. {
  2392. int colorByte = msg->getU8();
  2393. Color color = Color::from8bit(colorByte);
  2394. std::string fontName = msg->getString();
  2395. std::string text = msg->getString();
  2396. StaticTextPtr staticText = StaticTextPtr(new StaticText);
  2397. staticText->setText(text);
  2398. staticText->setFont(fontName);
  2399. staticText->setColor(color);
  2400. return staticText;
  2401. }
  2402.  
  2403. Position ProtocolGame::getPosition(const InputMessagePtr& msg)
  2404. {
  2405. uint16 x = msg->getU16();
  2406. uint16 y = msg->getU16();
  2407. uint8 z = msg->getU8();
  2408.  
  2409. return Position(x, y, z);
  2410. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement