No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

protocolgameparse.cpp 34KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148
  1. /*
  2. * Copyright (c) 2010-2012 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. #include "protocolgame.h"
  23. #include <otclient/core/localplayer.h>
  24. #include <otclient/core/thingstype.h>
  25. #include <otclient/core/game.h>
  26. #include <otclient/core/map.h>
  27. #include <otclient/core/item.h>
  28. #include <otclient/core/effect.h>
  29. #include <otclient/core/missile.h>
  30. #include <otclient/core/tile.h>
  31. #include <otclient/luascript/luavaluecasts.h>
  32. #include <framework/core/eventdispatcher.h>
  33. void ProtocolGame::parseMessage(InputMessage& msg)
  34. {
  35. try {
  36. while(!msg.eof()) {
  37. int opt = msg.getU8();
  38. switch(opt) {
  39. case Proto::GameServerInitGame:
  40. parseInitGame(msg);
  41. break;
  42. case Proto::GameServerGMActions:
  43. parseGMActions(msg);
  44. break;
  45. case Proto::GameServerLoginError:
  46. parseLoginError(msg);
  47. break;
  48. case Proto::GameServerLoginAdvice:
  49. parseFYIMessage(msg);
  50. break;
  51. case Proto::GameServerLoginWait:
  52. parseWaitList(msg);
  53. break;
  54. case Proto::GameServerPing:
  55. parsePing(msg);
  56. break;
  57. //case Proto::GameServerChallange:
  58. case Proto::GameServerDead:
  59. parseDeath(msg);
  60. break;
  61. case Proto::GameServerFullMap:
  62. parseMapDescription(msg);
  63. break;
  64. case Proto::GameServerMapTopRow:
  65. parseMoveNorth(msg);
  66. break;
  67. case Proto::GameServerMapRightRow:
  68. parseMoveEast(msg);
  69. break;
  70. case Proto::GameServerMapBottomRow:
  71. parseMoveSouth(msg);
  72. break;
  73. case Proto::GameServerMapLeftRow:
  74. parseMoveWest(msg);
  75. break;
  76. case Proto::GameServerTileData:
  77. parseUpdateTile(msg);
  78. break;
  79. case Proto::GameServerCreateOnMap:
  80. parseTileAddThing(msg);
  81. break;
  82. case Proto::GameServerChangeOnMap:
  83. parseTileTransformThing(msg);
  84. break;
  85. case Proto::GameServerDeleteOnMap:
  86. parseTileRemoveThing(msg);
  87. break;
  88. case Proto::GameServerMoveCreature:
  89. parseCreatureMove(msg);
  90. break;
  91. case Proto::GameServerOpenContainer:
  92. parseOpenContainer(msg);
  93. break;
  94. case Proto::GameServerCloseContainer:
  95. parseCloseContainer(msg);
  96. break;
  97. case Proto::GameServerCreateContainer:
  98. parseContainerAddItem(msg);
  99. break;
  100. case Proto::GameServerChangeInContainer:
  101. parseContainerUpdateItem(msg);
  102. break;
  103. case Proto::GameServerDeleteInContainer:
  104. parseContainerRemoveItem(msg);
  105. break;
  106. case Proto::GameServerSetInventory:
  107. parseAddInventoryItem(msg);
  108. break;
  109. case Proto::GameServerDeleteInventory:
  110. parseRemoveInventoryItem(msg);
  111. break;
  112. case Proto::GameServerNpcOffer:
  113. parseOpenShopWindow(msg);
  114. break;
  115. case Proto::GameServerPlayerGoods:
  116. parsePlayerCash(msg);
  117. break;
  118. case Proto::GameServerCloseNpcTrade:
  119. parseCloseShopWindow(msg);
  120. break;
  121. case Proto::GameServerOwnOffer:
  122. parseSafeTradeRequest(msg);
  123. break;
  124. case Proto::GameServerCounterOffer:
  125. parseSafeTradeRequest(msg);
  126. break;
  127. case Proto::GameServerCloseTrade:
  128. parseSafeTradeClose(msg);
  129. break;
  130. case Proto::GameServerAmbient:
  131. parseWorldLight(msg);
  132. break;
  133. case Proto::GameServerGraphicalEffect:
  134. parseMagicEffect(msg);
  135. break;
  136. case Proto::GameServerTextEffect:
  137. parseAnimatedText(msg);
  138. break;
  139. case Proto::GameServerMissleEffect:
  140. parseDistanceMissile(msg);
  141. break;
  142. case Proto::GameServerMarkCreature:
  143. parseCreatureSquare(msg);
  144. break;
  145. //case Proto::GameServerTrappers
  146. case Proto::GameServerCreatureHealth:
  147. parseCreatureHealth(msg);
  148. break;
  149. case Proto::GameServerCreatureLight:
  150. parseCreatureLight(msg);
  151. break;
  152. case Proto::GameServerCreatureOutfit:
  153. parseCreatureOutfit(msg);
  154. break;
  155. case Proto::GameServerCreatureSpeed:
  156. parseCreatureSpeed(msg);
  157. break;
  158. case Proto::GameServerCreatureSkull:
  159. parseCreatureSkulls(msg);
  160. break;
  161. case Proto::GameServerCreatureParty:
  162. parseCreatureShields(msg);
  163. break;
  164. // case Proto::GameServerCreatureUnpass
  165. case Proto::GameServerEditText:
  166. parseItemTextWindow(msg);
  167. break;
  168. case Proto::GameServerEditList:
  169. parseHouseTextWindow(msg);
  170. break;
  171. case Proto::GameServerPlayerData:
  172. parsePlayerStats(msg);
  173. break;
  174. case Proto::GameServerPlayerSkills:
  175. parsePlayerSkills(msg);
  176. break;
  177. case Proto::GameServerPlayerState:
  178. parsePlayerIcons(msg);
  179. break;
  180. case Proto::GameServerClearTarget:
  181. parsePlayerCancelAttack(msg);
  182. break;
  183. //case Proto::GameServerSpellDelay:
  184. //case Proto::GameServerSpellGroupDelay:
  185. case Proto::GameServerTalk:
  186. parseCreatureSpeak(msg);
  187. break;
  188. case Proto::GameServerChannels:
  189. parseChannelList(msg);
  190. break;
  191. case Proto::GameServerOpenChannel:
  192. parseOpenChannel(msg);
  193. break;
  194. case Proto::GameServerOpenPrivateChannel:
  195. parseOpenPrivateChannel(msg);
  196. break;
  197. case Proto::GameServerRuleViolationChannel:
  198. msg.getU16();
  199. break;
  200. case Proto::GameServerRuleViolationRemove:
  201. msg.getString();
  202. break;
  203. case Proto::GameServerRuleViolationCancel:
  204. msg.getString();
  205. break;
  206. case Proto::GameServerRuleViolationLock:
  207. break;
  208. case Proto::GameServerOpenOwnChannel:
  209. parseCreateOwnPrivateChannel(msg);
  210. break;
  211. case Proto::GameServerCloseChannel:
  212. parseCloseChannel(msg);
  213. break;
  214. case Proto::GameServerMessage:
  215. parseTextMessage(msg);
  216. break;
  217. case Proto::GameServerSnapBack:
  218. parseCancelWalk(msg);
  219. break;
  220. //case Proto::GameServerWait:
  221. case Proto::GameServerTopFloor:
  222. parseFloorChangeUp(msg);
  223. break;
  224. case Proto::GameServerBottomFloor:
  225. parseFloorChangeDown(msg);
  226. break;
  227. case Proto::GameServerOutfit:
  228. parseOutfitWindow(msg);
  229. break;
  230. case Proto::GameServerBuddyData:
  231. parseVipState(msg);
  232. break;
  233. case Proto::GameServerBuddyLogin:
  234. parseVipLogin(msg);
  235. break;
  236. case Proto::GameServerBuddyLogout:
  237. parseVipLogout(msg);
  238. break;
  239. case Proto::GameServerTutorialHint:
  240. parseShowTutorial(msg);
  241. break;
  242. case Proto::GameServerAutomapFlag:
  243. parseAddMarker(msg);
  244. break;
  245. case Proto::GameServerQuestLog:
  246. parseQuestList(msg);
  247. break;
  248. case Proto::GameServerQuestLine:
  249. parseQuestPartList(msg);
  250. break;
  251. //case Proto::GameServerChannelEvent:
  252. //case Proto::GameServerObjectInfo:
  253. //case Proto::GameServerPlayerInventory:
  254. default:
  255. Fw::throwException("unknown opt byte ", (int)opt);
  256. break;
  257. }
  258. }
  259. } catch(Exception& e) {
  260. logTraceError(e.what());
  261. }
  262. }
  263. void ProtocolGame::parseInitGame(InputMessage& msg)
  264. {
  265. uint playerId = msg.getU32();
  266. int serverBeat = msg.getU16();
  267. int playerCanReportBugs = msg.getU8();
  268. m_localPlayer = LocalPlayerPtr(new LocalPlayer);
  269. m_localPlayer->setId(playerId);
  270. m_localPlayer->setCanReportBugs(playerCanReportBugs);
  271. g_game.processGameStart(m_localPlayer, serverBeat);
  272. }
  273. void ProtocolGame::parseGMActions(InputMessage& msg)
  274. {
  275. for(int i = 0; i < Proto::NumViolationReasons; ++i)
  276. msg.getU8();
  277. }
  278. void ProtocolGame::parseLoginError(InputMessage& msg)
  279. {
  280. std::string error = msg.getString();
  281. g_game.processLoginError(error);
  282. }
  283. void ProtocolGame::parseFYIMessage(InputMessage& msg)
  284. {
  285. msg.getString(); // message
  286. }
  287. void ProtocolGame::parseWaitList(InputMessage& msg)
  288. {
  289. msg.getString(); // message
  290. msg.getU8();// + 1 // time
  291. }
  292. void ProtocolGame::parsePing(InputMessage&)
  293. {
  294. sendPing();
  295. }
  296. void ProtocolGame::parseDeath(InputMessage& msg)
  297. {
  298. #if PROTOCOL==862
  299. msg.getU8(); // 100 is a fair death. < 100 is a unfair death.
  300. #endif
  301. g_game.processDeath();
  302. }
  303. void ProtocolGame::parseMapDescription(InputMessage& msg)
  304. {
  305. Position pos = parsePosition(msg);
  306. g_map.setCentralPosition(pos);
  307. setMapDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z, Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES);
  308. }
  309. void ProtocolGame::parseMoveNorth(InputMessage& msg)
  310. {
  311. Position pos = g_map.getCentralPosition();
  312. pos.y--;
  313. setMapDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z, Otc::AWARE_X_TILES, 1);
  314. g_map.setCentralPosition(pos);
  315. }
  316. void ProtocolGame::parseMoveEast(InputMessage& msg)
  317. {
  318. Position pos = g_map.getCentralPosition();
  319. pos.x++;
  320. setMapDescription(msg, pos.x + Otc::AWARE_X_RIGHT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z, 1, Otc::AWARE_Y_TILES);
  321. g_map.setCentralPosition(pos);
  322. }
  323. void ProtocolGame::parseMoveSouth(InputMessage& msg)
  324. {
  325. Position pos = g_map.getCentralPosition();
  326. pos.y++;
  327. setMapDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y + Otc::AWARE_Y_BOTTOM_TILES, pos.z, Otc::AWARE_X_TILES, 1);
  328. g_map.setCentralPosition(pos);
  329. }
  330. void ProtocolGame::parseMoveWest(InputMessage& msg)
  331. {
  332. Position pos = g_map.getCentralPosition();
  333. pos.x--;
  334. setMapDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z, 1, Otc::AWARE_Y_TILES);
  335. g_map.setCentralPosition(pos);
  336. }
  337. void ProtocolGame::parseUpdateTile(InputMessage& msg)
  338. {
  339. Position tilePos = parsePosition(msg);
  340. int thingId = msg.getU16(true);
  341. if(thingId == 0xFF01) {
  342. msg.getU16();
  343. } else {
  344. setTileDescription(msg, tilePos);
  345. msg.getU16();
  346. }
  347. }
  348. void ProtocolGame::parseTileAddThing(InputMessage& msg)
  349. {
  350. Position pos = parsePosition(msg);
  351. int stackPos = msg.getU8();
  352. ThingPtr thing = internalGetThing(msg);
  353. g_map.addThing(thing, pos, stackPos);
  354. }
  355. void ProtocolGame::parseTileTransformThing(InputMessage& msg)
  356. {
  357. Position pos = parsePosition(msg);
  358. int stackPos = msg.getU8();
  359. int thingId = msg.getU16();
  360. assert(thingId != 0);
  361. if(thingId == 0x0061 || thingId == 0x0062 || thingId == 0x0063) {
  362. parseCreatureTurn(msg);
  363. } else {
  364. ThingPtr thing = internalGetItem(msg, thingId);
  365. g_map.removeThingByPos(pos, stackPos);
  366. g_map.addThing(thing, pos, stackPos);
  367. }
  368. }
  369. void ProtocolGame::parseTileRemoveThing(InputMessage& msg)
  370. {
  371. Position pos = parsePosition(msg);
  372. int stackPos = msg.getU8();
  373. g_map.removeThingByPos(pos, stackPos);
  374. }
  375. void ProtocolGame::parseCreatureMove(InputMessage& msg)
  376. {
  377. Position oldPos = parsePosition(msg);
  378. int oldStackpos = msg.getU8();
  379. Position newPos = parsePosition(msg);
  380. ThingPtr thing = g_map.getThing(oldPos, oldStackpos);
  381. if(!thing) {
  382. logTraceError("could not get thing");
  383. return;
  384. }
  385. CreaturePtr creature = thing->asCreature();
  386. if(!creature) {
  387. logTraceError("thing is not a creature");
  388. return;
  389. }
  390. // update map tiles
  391. g_map.removeThing(thing);
  392. g_map.addThing(thing, newPos);
  393. g_game.processCreatureMove(creature, oldPos, newPos);
  394. }
  395. void ProtocolGame::parseOpenContainer(InputMessage& msg)
  396. {
  397. int containerId = msg.getU8();
  398. int itemId = msg.getU16();
  399. std::string name = msg.getString();
  400. int capacity = msg.getU8();
  401. bool hasParent = (msg.getU8() != 0);
  402. int itemCount = msg.getU8();
  403. std::vector<ItemPtr> items;
  404. items.reserve(itemCount);
  405. for(int i = 0; i < itemCount; i++) {
  406. ItemPtr item = internalGetItem(msg);
  407. items.push_back(item);
  408. }
  409. g_lua.callGlobalField("Game", "onContainerOpen", containerId, itemId, name, capacity, hasParent, items);
  410. }
  411. void ProtocolGame::parseCloseContainer(InputMessage& msg)
  412. {
  413. int containerId = msg.getU8();
  414. g_lua.callGlobalField("Game", "onContainerClose", containerId);
  415. }
  416. void ProtocolGame::parseContainerAddItem(InputMessage& msg)
  417. {
  418. int containerId = msg.getU8();
  419. ItemPtr item = internalGetItem(msg);
  420. g_game.processContainerAddItem(containerId, item);
  421. }
  422. void ProtocolGame::parseContainerUpdateItem(InputMessage& msg)
  423. {
  424. int containerId = msg.getU8();
  425. int slot = msg.getU8();
  426. ItemPtr item = internalGetItem(msg);
  427. g_lua.callGlobalField("Game", "onContainerUpdateItem", containerId, slot, item);
  428. }
  429. void ProtocolGame::parseContainerRemoveItem(InputMessage& msg)
  430. {
  431. int containerId = msg.getU8();
  432. int slot = msg.getU8();
  433. g_lua.callGlobalField("Game", "onContainerRemoveItem", containerId, slot);
  434. }
  435. void ProtocolGame::parseAddInventoryItem(InputMessage& msg)
  436. {
  437. int slot = msg.getU8();
  438. ItemPtr item = internalGetItem(msg);
  439. g_game.processInventoryChange(slot, item);
  440. }
  441. void ProtocolGame::parseRemoveInventoryItem(InputMessage& msg)
  442. {
  443. int slot = msg.getU8();
  444. g_game.processInventoryChange(slot, ItemPtr());
  445. }
  446. void ProtocolGame::parseOpenShopWindow(InputMessage& msg)
  447. {
  448. int listCount = msg.getU8();
  449. for(int i = 0; i < listCount; ++i) {
  450. msg.getU16(); // item id
  451. msg.getU8(); // runecharges
  452. msg.getString(); // item name
  453. msg.getU32(); // weight
  454. msg.getU32(); // buy price
  455. msg.getU32(); // sell price
  456. }
  457. }
  458. void ProtocolGame::parsePlayerCash(InputMessage& msg)
  459. {
  460. msg.getU32();
  461. int size = msg.getU8();
  462. for(int i = 0; i < size; i++) {
  463. msg.getU16(); // itemid
  464. msg.getU8(); // runecharges
  465. }
  466. }
  467. void ProtocolGame::parseCloseShopWindow(InputMessage&)
  468. {
  469. }
  470. void ProtocolGame::parseSafeTradeRequest(InputMessage& msg)
  471. {
  472. msg.getString(); // name
  473. int count = msg.getU8();
  474. for(int i = 0; i < count; i++)
  475. internalGetItem(msg);
  476. }
  477. void ProtocolGame::parseSafeTradeClose(InputMessage&)
  478. {
  479. }
  480. void ProtocolGame::parseWorldLight(InputMessage& msg)
  481. {
  482. Light light;
  483. light.intensity = msg.getU8();
  484. light.color = msg.getU8();
  485. g_map.setLight(light);
  486. }
  487. void ProtocolGame::parseMagicEffect(InputMessage& msg)
  488. {
  489. Position pos = parsePosition(msg);
  490. int effectId = msg.getU8();
  491. EffectPtr effect = EffectPtr(new Effect());
  492. effect->setId(effectId);
  493. g_map.addThing(effect, pos);
  494. }
  495. void ProtocolGame::parseAnimatedText(InputMessage& msg)
  496. {
  497. Position position = parsePosition(msg);
  498. int color = msg.getU8();
  499. std::string text = msg.getString();
  500. AnimatedTextPtr animatedText = AnimatedTextPtr(new AnimatedText);
  501. animatedText->setColor(color);
  502. animatedText->setText(text);
  503. g_map.addThing(animatedText, position);
  504. }
  505. void ProtocolGame::parseDistanceMissile(InputMessage& msg)
  506. {
  507. Position fromPos = parsePosition(msg);
  508. Position toPos = parsePosition(msg);
  509. int shotId = msg.getU8();
  510. MissilePtr missile = MissilePtr(new Missile());
  511. missile->setId(shotId);
  512. missile->setPath(fromPos, toPos);
  513. g_map.addThing(missile, fromPos);
  514. }
  515. void ProtocolGame::parseCreatureSquare(InputMessage& msg)
  516. {
  517. uint id = msg.getU32();
  518. int color = msg.getU8();
  519. CreaturePtr creature = g_map.getCreatureById(id);
  520. if(creature)
  521. creature->addVolatileSquare(color);
  522. }
  523. void ProtocolGame::parseCreatureHealth(InputMessage& msg)
  524. {
  525. uint id = msg.getU32();
  526. int healthPercent = msg.getU8();
  527. CreaturePtr creature = g_map.getCreatureById(id);
  528. if(creature)
  529. creature->setHealthPercent(healthPercent);
  530. }
  531. void ProtocolGame::parseCreatureLight(InputMessage& msg)
  532. {
  533. uint id = msg.getU32();
  534. Light light;
  535. light.intensity = msg.getU8();
  536. light.color = msg.getU8();
  537. CreaturePtr creature = g_map.getCreatureById(id);
  538. if(creature)
  539. creature->setLight(light);
  540. }
  541. void ProtocolGame::parseCreatureOutfit(InputMessage& msg)
  542. {
  543. uint id = msg.getU32();
  544. Outfit outfit = internalGetOutfit(msg);
  545. CreaturePtr creature = g_map.getCreatureById(id);
  546. if(creature)
  547. creature->setOutfit(outfit);
  548. }
  549. void ProtocolGame::parseCreatureSpeed(InputMessage& msg)
  550. {
  551. uint id = msg.getU32();
  552. int speed = msg.getU16();
  553. CreaturePtr creature = g_map.getCreatureById(id);
  554. if(creature)
  555. creature->setSpeed(speed);
  556. }
  557. void ProtocolGame::parseCreatureSkulls(InputMessage& msg)
  558. {
  559. uint id = msg.getU32();
  560. int skull = msg.getU8();
  561. CreaturePtr creature = g_map.getCreatureById(id);
  562. if(creature)
  563. creature->setSkull(skull);
  564. }
  565. void ProtocolGame::parseCreatureShields(InputMessage& msg)
  566. {
  567. uint id = msg.getU32();
  568. int shield = msg.getU8();
  569. CreaturePtr creature = g_map.getCreatureById(id);
  570. if(creature)
  571. creature->setShield(shield);
  572. }
  573. void ProtocolGame::parseCreatureTurn(InputMessage& msg)
  574. {
  575. uint id = msg.getU32();
  576. Otc::Direction direction = (Otc::Direction)msg.getU8();
  577. CreaturePtr creature = g_map.getCreatureById(id);
  578. if(creature)
  579. creature->turn(direction);
  580. }
  581. void ProtocolGame::parseItemTextWindow(InputMessage& msg)
  582. {
  583. msg.getU32(); // windowId
  584. msg.getU16(); // itemid
  585. msg.getU16(); // max length
  586. msg.getString(); // text
  587. msg.getString(); // writter
  588. msg.getString(); // date
  589. }
  590. void ProtocolGame::parseHouseTextWindow(InputMessage& msg)
  591. {
  592. msg.getU8(); // unknown
  593. msg.getU32(); // windowId
  594. msg.getString(); // text
  595. }
  596. void ProtocolGame::parsePlayerStats(InputMessage& msg)
  597. {
  598. double health = msg.getU16();
  599. double maxHealth = msg.getU16();
  600. double freeCapacity = msg.getU32() / 100.0;
  601. double experience = msg.getU32();
  602. double level = msg.getU16();
  603. double levelPercent = msg.getU8();
  604. double mana = msg.getU16();
  605. double maxMana = msg.getU16();
  606. double magicLevel = msg.getU8();
  607. double magicLevelPercent = msg.getU8();
  608. double soul = msg.getU8();
  609. double stamina = msg.getU16();
  610. g_game.processPlayerStats(health, maxHealth, freeCapacity, experience, level, levelPercent, mana, maxMana, magicLevel, magicLevelPercent, soul, stamina);
  611. }
  612. void ProtocolGame::parsePlayerSkills(InputMessage& msg)
  613. {
  614. for(int skill = 0; skill < Otc::LastSkill; skill++) {
  615. int values[Otc::LastSkillType];
  616. for(int skillType = 0; skillType < Otc::LastSkillType; skillType++) {
  617. values[skillType] = msg.getU8();
  618. m_localPlayer->setSkill((Otc::Skill)skill, (Otc::SkillType)skillType, values[skillType]);
  619. }
  620. g_lua.callGlobalField("Game", "onSkillChange", skill, values[Otc::SkillLevel], values[Otc::SkillPercent]);
  621. }
  622. }
  623. void ProtocolGame::parsePlayerIcons(InputMessage& msg)
  624. {
  625. int icons = msg.getU16();
  626. m_localPlayer->setIcons((Otc::PlayerIcons)icons);
  627. }
  628. void ProtocolGame::parsePlayerCancelAttack(InputMessage& msg)
  629. {
  630. msg.getU32(); // unknown
  631. g_game.processAttackCancel();
  632. }
  633. void ProtocolGame::parseCreatureSpeak(InputMessage& msg)
  634. {
  635. msg.getU32(); // unkSpeak
  636. std::string name = msg.getString();
  637. int level = msg.getU16();
  638. int serverType = msg.getU8();
  639. int channelId = 0;
  640. Position creaturePos;
  641. switch(serverType) {
  642. case Proto::ServerSpeakSay:
  643. case Proto::ServerSpeakWhisper:
  644. case Proto::ServerSpeakYell:
  645. case Proto::ServerSpeakMonsterSay:
  646. case Proto::ServerSpeakMonsterYell:
  647. case Proto::ServerSpeakPrivateNpcToPlayer:
  648. creaturePos = parsePosition(msg);
  649. break;
  650. case Proto::ServerSpeakChannelYellow:
  651. case Proto::ServerSpeakChannelWhite:
  652. case Proto::ServerSpeakChannelRed:
  653. case Proto::ServerSpeakChannelRed2:
  654. case Proto::ServerSpeakChannelOrange:
  655. channelId = msg.getU16();
  656. break;
  657. case Proto::ServerSpeakPrivate:
  658. case Proto::ServerSpeakPrivatePlayerToNpc:
  659. case Proto::ServerSpeakBroadcast:
  660. case Proto::ServerSpeakPrivateRed:
  661. break;
  662. case Proto::ServerSpeakRVRChannel:
  663. msg.getU32();
  664. break;
  665. default:
  666. logTraceError("unknown speak type ", serverType);
  667. break;
  668. }
  669. std::string message = msg.getString();
  670. Otc::SpeakType type = Proto::translateSpeakTypeFromServer(serverType);
  671. g_game.processCreatureSpeak(name, level, type, message, channelId, creaturePos);
  672. }
  673. void ProtocolGame::parseChannelList(InputMessage& msg)
  674. {
  675. int count = msg.getU8();
  676. std::vector<std::tuple<int, std::string> > channelList(count);
  677. for(int i = 0; i < count; i++) {
  678. int id = msg.getU16();
  679. std::string name = msg.getString();
  680. channelList.push_back(std::make_tuple(id, name));
  681. }
  682. g_lua.callGlobalField("Game", "onChannelList", channelList);
  683. }
  684. void ProtocolGame::parseOpenChannel(InputMessage& msg)
  685. {
  686. int channelId = msg.getU16();
  687. std::string name = msg.getString();
  688. g_lua.callGlobalField("Game", "onOpenChannel", channelId, name);
  689. }
  690. void ProtocolGame::parseOpenPrivateChannel(InputMessage& msg)
  691. {
  692. std::string name = msg.getString();
  693. g_lua.callGlobalField("Game", "onOpenPrivateChannel", name);
  694. }
  695. void ProtocolGame::parseCreateOwnPrivateChannel(InputMessage& msg)
  696. {
  697. int id = msg.getU16(); // channel id
  698. std::string name = msg.getString(); // channel name
  699. g_lua.callGlobalField("Game", "onOpenOwnPrivateChannel", id, name);
  700. }
  701. void ProtocolGame::parseCloseChannel(InputMessage& msg)
  702. {
  703. int id = msg.getU16(); // channel id
  704. g_lua.callGlobalField("Game", "onCloseChannel", id);
  705. }
  706. void ProtocolGame::parseTextMessage(InputMessage& msg)
  707. {
  708. int type = msg.getU8();
  709. std::string typeDesc = Proto::translateTextMessageType(type);
  710. std::string message = msg.getString();
  711. g_game.processTextMessage(typeDesc, message);
  712. }
  713. void ProtocolGame::parseCancelWalk(InputMessage& msg)
  714. {
  715. Otc::Direction direction = (Otc::Direction)msg.getU8();
  716. g_game.processWalkCancel(direction);
  717. }
  718. void ProtocolGame::parseFloorChangeUp(InputMessage& msg)
  719. {
  720. Position pos = g_map.getCentralPosition();
  721. pos.z--;
  722. int skip = 0;
  723. if(pos.z == Otc::SEA_FLOOR)
  724. for(int i = Otc::SEA_FLOOR - Otc::AWARE_UNDEGROUND_FLOOR_RANGE; i >= 0; i--)
  725. setFloorDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, i, Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES, 8 - i, &skip);
  726. else if(pos.z > Otc::SEA_FLOOR)
  727. setFloorDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z - Otc::AWARE_UNDEGROUND_FLOOR_RANGE, Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES, 3, &skip);
  728. pos.x++;
  729. pos.y++;
  730. g_map.setCentralPosition(pos);
  731. }
  732. void ProtocolGame::parseFloorChangeDown(InputMessage& msg)
  733. {
  734. Position pos = g_map.getCentralPosition();
  735. pos.z++;
  736. int skip = 0;
  737. if(pos.z == Otc::UNDERGROUND_FLOOR) {
  738. int j, i;
  739. for(i = pos.z, j = -1; i <= pos.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE; ++i, --j)
  740. setFloorDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, i, Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES, j, &skip);
  741. }
  742. else if(pos.z > Otc::UNDERGROUND_FLOOR && pos.z < Otc::MAX_Z-1)
  743. setFloorDescription(msg, pos.x - Otc::AWARE_X_LEFT_TILES, pos.y - Otc::AWARE_Y_TOP_TILES, pos.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE, Otc::AWARE_X_TILES, Otc::AWARE_Y_TILES, -3, &skip);
  744. pos.x--;
  745. pos.y--;
  746. g_map.setCentralPosition(pos);
  747. }
  748. void ProtocolGame::parseOutfitWindow(InputMessage& msg)
  749. {
  750. Outfit outfit = internalGetOutfit(msg);
  751. typedef std::tuple<int, std::string, int> OutfitInfo;
  752. std::vector<OutfitInfo> outfitList;
  753. uint8 outfitCount = msg.getU8();
  754. for(int i = 0; i < outfitCount; i++) {
  755. uint16 outfitId = msg.getU16();
  756. std::string outfitName = msg.getString();
  757. uint8 outfitAddons = msg.getU8();
  758. outfitList.push_back(OutfitInfo(outfitId, outfitName, outfitAddons));
  759. }
  760. CreaturePtr creature = CreaturePtr(new Creature);
  761. creature->setDirection(Otc::South);
  762. creature->setOutfit(outfit);
  763. g_lua.callGlobalField("Game", "onOpenOutfitWindow", creature, outfitList);
  764. }
  765. void ProtocolGame::parseVipState(InputMessage& msg)
  766. {
  767. uint id = msg.getU32();
  768. std::string name = msg.getString();
  769. bool online = msg.getU8() != 0;
  770. g_lua.callGlobalField("Game", "onAddVip", id, name, online);
  771. }
  772. void ProtocolGame::parseVipLogin(InputMessage& msg)
  773. {
  774. uint id = msg.getU32();
  775. g_lua.callGlobalField("Game", "onVipStateChange", id, true);
  776. }
  777. void ProtocolGame::parseVipLogout(InputMessage& msg)
  778. {
  779. uint id = msg.getU32();
  780. g_lua.callGlobalField("Game", "onVipStateChange", id, false);
  781. }
  782. void ProtocolGame::parseShowTutorial(InputMessage& msg)
  783. {
  784. msg.getU8(); // tutorial id
  785. }
  786. void ProtocolGame::parseAddMarker(InputMessage& msg)
  787. {
  788. parsePosition(msg); // position
  789. msg.getU8(); // icon
  790. msg.getString(); // message
  791. }
  792. void ProtocolGame::parseQuestList(InputMessage& msg)
  793. {
  794. int questsCount = msg.getU16();
  795. for(int i = 0; i < questsCount; i++) {
  796. msg.getU16(); // quest id
  797. msg.getString(); // quest name
  798. msg.getU8(); // quest state
  799. }
  800. }
  801. void ProtocolGame::parseQuestPartList(InputMessage& msg)
  802. {
  803. msg.getU16(); // quest id
  804. int missionCount = msg.getU8();
  805. for(int i = 0; i < missionCount; i++) {
  806. msg.getString(); // quest name
  807. msg.getString(); // quest description
  808. }
  809. }
  810. void ProtocolGame::setMapDescription(InputMessage& msg, int32 x, int32 y, int32 z, int32 width, int32 height)
  811. {
  812. int startz, endz, zstep, skip = 0;
  813. if(z > Otc::SEA_FLOOR) {
  814. startz = z - Otc::AWARE_UNDEGROUND_FLOOR_RANGE;
  815. endz = std::min(z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE, (int)Otc::MAX_Z);
  816. zstep = 1;
  817. }
  818. else {
  819. startz = Otc::SEA_FLOOR;
  820. endz = 0;
  821. zstep = -1;
  822. }
  823. for(int nz = startz; nz != endz + zstep; nz += zstep)
  824. setFloorDescription(msg, x, y, nz, width, height, z - nz, &skip);
  825. }
  826. void ProtocolGame::setFloorDescription(InputMessage& msg, int32 x, int32 y, int32 z, int32 width, int32 height, int32 offset, int32* skipTiles)
  827. {
  828. int skip = *skipTiles;
  829. for(int nx = 0; nx < width; nx++) {
  830. for(int ny = 0; ny < height; ny++) {
  831. Position tilePos(x + nx + offset, y + ny + offset, z);
  832. // clean pre stored tiles
  833. g_map.cleanTile(tilePos);
  834. if(skip == 0) {
  835. int tileOpt = msg.getU16(true);
  836. if(tileOpt >= 0xFF00)
  837. skip = (msg.getU16() & 0xFF);
  838. else {
  839. setTileDescription(msg, tilePos);
  840. skip = (msg.getU16() & 0xFF);
  841. }
  842. }
  843. else
  844. skip--;
  845. }
  846. }
  847. *skipTiles = skip;
  848. }
  849. void ProtocolGame::setTileDescription(InputMessage& msg, Position position)
  850. {
  851. g_map.cleanTile(position);
  852. int stackPos = 0;
  853. while(true) {
  854. int inspectTileId = msg.getU16(true);
  855. if(inspectTileId >= 0xFF00)
  856. return;
  857. else {
  858. if(stackPos >= 10)
  859. logTraceError("too many things, stackpos=", stackPos, " pos=", position);
  860. ThingPtr thing = internalGetThing(msg);
  861. if(thing)
  862. g_map.addThing(thing, position, 255);
  863. }
  864. stackPos++;
  865. }
  866. }
  867. Outfit ProtocolGame::internalGetOutfit(InputMessage& msg)
  868. {
  869. Outfit outfit;
  870. int id = msg.getU16();
  871. if(id != 0) {
  872. outfit.setCategory(ThingsType::Creature);
  873. int head = msg.getU8();
  874. int body = msg.getU8();
  875. int legs = msg.getU8();
  876. int feet = msg.getU8();
  877. int addons = msg.getU8();
  878. outfit.setId(id);
  879. outfit.setHead(head);
  880. outfit.setBody(body);
  881. outfit.setLegs(legs);
  882. outfit.setFeet(feet);
  883. outfit.setAddons(addons);
  884. }
  885. else {
  886. int id = msg.getU16();
  887. if(id == 0) {
  888. outfit.setCategory(ThingsType::Effect);
  889. outfit.setId(13);
  890. }
  891. else {
  892. outfit.setCategory(ThingsType::Item);
  893. outfit.setId(id);
  894. }
  895. }
  896. return outfit;
  897. }
  898. ThingPtr ProtocolGame::internalGetThing(InputMessage& msg)
  899. {
  900. ThingPtr thing;
  901. int thingId = msg.getU16();
  902. assert(thingId != 0);
  903. if(thingId == 0x0061 || thingId == 0x0062) { // add new creature
  904. CreaturePtr creature;
  905. if(thingId == 0x0062) { //creature is known
  906. uint id = msg.getU32();
  907. CreaturePtr knownCreature = g_map.getCreatureById(id);
  908. if(knownCreature)
  909. creature = knownCreature;
  910. else
  911. logTraceError("server said that a creature is known, but it's not");
  912. } else if(thingId == 0x0061) { //creature is not known
  913. uint removeId = msg.getU32();
  914. uint id = msg.getU32();
  915. std::string name = msg.getString();
  916. if(name.length() > 0) // every creature name must start with a capital letter
  917. name[0] = toupper(name[0]);
  918. g_map.removeCreatureById(removeId);
  919. if(id == m_localPlayer->getId())
  920. creature = m_localPlayer;
  921. else if(id >= Proto::PlayerStartId && id < Proto::PlayerEndId)
  922. creature = PlayerPtr(new Player);
  923. else if(id >= Proto::MonsterStartId && id < Proto::MonsterEndId)
  924. creature = MonsterPtr(new Monster);
  925. else if(id >= Proto::NpcStartId && id < Proto::NpcEndId)
  926. creature = NpcPtr(new Npc);
  927. else
  928. logTraceError("creature id is invalid");
  929. creature->setId(id);
  930. creature->setName(name);
  931. g_map.addCreature(creature);
  932. }
  933. uint8 healthPercent = msg.getU8();
  934. Otc::Direction direction = (Otc::Direction)msg.getU8();
  935. Outfit outfit = internalGetOutfit(msg);
  936. Light light;
  937. light.intensity = msg.getU8();
  938. light.color = msg.getU8();
  939. int speed = msg.getU16();
  940. int skull = msg.getU8();
  941. int shield = msg.getU8();
  942. int emblem = -1;
  943. if(thingId == 0x0061) // emblem is sent only in packet type 0x61
  944. emblem = msg.getU8();
  945. bool passable = (msg.getU8() == 0);
  946. if(creature) {
  947. creature->setHealthPercent(healthPercent);
  948. creature->setDirection(direction);
  949. creature->setOutfit(outfit);
  950. creature->setLight(light);
  951. creature->setSpeed(speed);
  952. creature->setSkull(skull);
  953. creature->setShield(shield);
  954. if(emblem != -1)
  955. creature->setEmblem(emblem);
  956. creature->setPassable(passable);
  957. creature->setDirection(direction);
  958. // now that the local player is known, we can schedule login event
  959. if(creature == m_localPlayer) {
  960. m_localPlayer->setKnown(true);
  961. g_dispatcher.addEvent([] { g_game.processLogin(); });
  962. }
  963. }
  964. thing = creature;
  965. } else if(thingId == 0x0063) { // creature turn
  966. parseCreatureTurn(msg);
  967. } else // item
  968. thing = internalGetItem(msg, thingId);
  969. return thing;
  970. }
  971. ItemPtr ProtocolGame::internalGetItem(InputMessage& msg, int id)
  972. {
  973. if(id == 0)
  974. id = msg.getU16();
  975. ItemPtr item = Item::create(id);
  976. if(item->isStackable() || item->isFluidContainer() || item->isFluid())
  977. item->setCountOrSubType(msg.getU8());
  978. return item;
  979. }
  980. Position ProtocolGame::parsePosition(InputMessage& msg)
  981. {
  982. uint16 x = msg.getU16();
  983. uint16 y = msg.getU16();
  984. uint8 z = msg.getU8();
  985. return Position(x, y, z);
  986. }