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 63KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159
  1. /*
  2. * Copyright (c) 2010-2014 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 "localplayer.h"
  24. #include "thingtypemanager.h"
  25. #include "game.h"
  26. #include "map.h"
  27. #include "item.h"
  28. #include "effect.h"
  29. #include "missile.h"
  30. #include "tile.h"
  31. #include "luavaluecasts.h"
  32. #include <framework/core/eventdispatcher.h>
  33. void ProtocolGame::parseMessage(const InputMessagePtr& msg)
  34. {
  35. int opcode = -1;
  36. int prevOpcode = -1;
  37. try {
  38. while(!msg->eof()) {
  39. opcode = msg->getU8();
  40. // must be > so extended will be enabled before GameStart.
  41. if(!g_game.getFeature(Otc::GameLoginPending)) {
  42. if(!m_gameInitialized && opcode > Proto::GameServerFirstGameOpcode) {
  43. g_game.processGameStart();
  44. m_gameInitialized = true;
  45. }
  46. }
  47. // try to parse in lua first
  48. int readPos = msg->getReadPos();
  49. if(callLuaField<bool>("onOpcode", opcode, msg))
  50. continue;
  51. else
  52. msg->setReadPos(readPos); // restore read pos
  53. switch(opcode) {
  54. case Proto::GameServerLoginOrPendingState:
  55. if(g_game.getFeature(Otc::GameLoginPending))
  56. parsePendingGame(msg);
  57. else
  58. parseLogin(msg);
  59. break;
  60. case Proto::GameServerGMActions:
  61. parseGMActions(msg);
  62. break;
  63. case Proto::GameServerUpdateNeeded:
  64. parseUpdateNeeded(msg);
  65. break;
  66. case Proto::GameServerLoginError:
  67. parseLoginError(msg);
  68. break;
  69. case Proto::GameServerLoginAdvice:
  70. parseLoginAdvice(msg);
  71. break;
  72. case Proto::GameServerLoginWait:
  73. parseLoginWait(msg);
  74. break;
  75. case Proto::GameServerLoginToken:
  76. parseLoginToken(msg);
  77. break;
  78. case Proto::GameServerPing:
  79. case Proto::GameServerPingBack:
  80. if((opcode == Proto::GameServerPing && g_game.getFeature(Otc::GameClientPing)) ||
  81. (opcode == Proto::GameServerPingBack && !g_game.getFeature(Otc::GameClientPing)))
  82. parsePingBack(msg);
  83. else
  84. parsePing(msg);
  85. break;
  86. case Proto::GameServerChallenge:
  87. parseChallenge(msg);
  88. break;
  89. case Proto::GameServerDeath:
  90. parseDeath(msg);
  91. break;
  92. case Proto::GameServerFullMap:
  93. parseMapDescription(msg);
  94. break;
  95. case Proto::GameServerMapTopRow:
  96. parseMapMoveNorth(msg);
  97. break;
  98. case Proto::GameServerMapRightRow:
  99. parseMapMoveEast(msg);
  100. break;
  101. case Proto::GameServerMapBottomRow:
  102. parseMapMoveSouth(msg);
  103. break;
  104. case Proto::GameServerMapLeftRow:
  105. parseMapMoveWest(msg);
  106. break;
  107. case Proto::GameServerUpdateTile:
  108. parseUpdateTile(msg);
  109. break;
  110. case Proto::GameServerCreateOnMap:
  111. parseTileAddThing(msg);
  112. break;
  113. case Proto::GameServerChangeOnMap:
  114. parseTileTransformThing(msg);
  115. break;
  116. case Proto::GameServerDeleteOnMap:
  117. parseTileRemoveThing(msg);
  118. break;
  119. case Proto::GameServerMoveCreature:
  120. parseCreatureMove(msg);
  121. break;
  122. case Proto::GameServerOpenContainer:
  123. parseOpenContainer(msg);
  124. break;
  125. case Proto::GameServerCloseContainer:
  126. parseCloseContainer(msg);
  127. break;
  128. case Proto::GameServerCreateContainer:
  129. parseContainerAddItem(msg);
  130. break;
  131. case Proto::GameServerChangeInContainer:
  132. parseContainerUpdateItem(msg);
  133. break;
  134. case Proto::GameServerDeleteInContainer:
  135. parseContainerRemoveItem(msg);
  136. break;
  137. case Proto::GameServerSetInventory:
  138. parseAddInventoryItem(msg);
  139. break;
  140. case Proto::GameServerDeleteInventory:
  141. parseRemoveInventoryItem(msg);
  142. break;
  143. case Proto::GameServerOpenNpcTrade:
  144. parseOpenNpcTrade(msg);
  145. break;
  146. case Proto::GameServerPlayerGoods:
  147. parsePlayerGoods(msg);
  148. break;
  149. case Proto::GameServerCloseNpcTrade:
  150. parseCloseNpcTrade(msg);
  151. break;
  152. case Proto::GameServerOwnTrade:
  153. parseOwnTrade(msg);
  154. break;
  155. case Proto::GameServerCounterTrade:
  156. parseCounterTrade(msg);
  157. break;
  158. case Proto::GameServerCloseTrade:
  159. parseCloseTrade(msg);
  160. break;
  161. case Proto::GameServerAmbient:
  162. parseWorldLight(msg);
  163. break;
  164. case Proto::GameServerGraphicalEffect:
  165. parseMagicEffect(msg);
  166. break;
  167. case Proto::GameServerTextEffect:
  168. parseAnimatedText(msg);
  169. break;
  170. case Proto::GameServerMissleEffect:
  171. parseDistanceMissile(msg);
  172. break;
  173. case Proto::GameServerMarkCreature:
  174. parseCreatureMark(msg);
  175. break;
  176. case Proto::GameServerTrappers:
  177. parseTrappers(msg);
  178. break;
  179. case Proto::GameServerCreatureHealth:
  180. parseCreatureHealth(msg);
  181. break;
  182. case Proto::GameServerCreatureLight:
  183. parseCreatureLight(msg);
  184. break;
  185. case Proto::GameServerCreatureOutfit:
  186. parseCreatureOutfit(msg);
  187. break;
  188. case Proto::GameServerCreatureSpeed:
  189. parseCreatureSpeed(msg);
  190. break;
  191. case Proto::GameServerCreatureSkull:
  192. parseCreatureSkulls(msg);
  193. break;
  194. case Proto::GameServerCreatureParty:
  195. parseCreatureShields(msg);
  196. break;
  197. case Proto::GameServerCreatureUnpass:
  198. parseCreatureUnpass(msg);
  199. break;
  200. case Proto::GameServerEditText:
  201. parseEditText(msg);
  202. break;
  203. case Proto::GameServerEditList:
  204. parseEditList(msg);
  205. break;
  206. // PROTOCOL>=1038
  207. case Proto::GameServerPremiumTrigger:
  208. parsePremiumTrigger(msg);
  209. break;
  210. case Proto::GameServerPlayerData:
  211. parsePlayerStats(msg);
  212. break;
  213. case Proto::GameServerPlayerSkills:
  214. parsePlayerSkills(msg);
  215. break;
  216. case Proto::GameServerPlayerState:
  217. parsePlayerState(msg);
  218. break;
  219. case Proto::GameServerClearTarget:
  220. parsePlayerCancelAttack(msg);
  221. break;
  222. case Proto::GameServerPlayerModes:
  223. parsePlayerModes(msg);
  224. break;
  225. case Proto::GameServerTalk:
  226. parseTalk(msg);
  227. break;
  228. case Proto::GameServerChannels:
  229. parseChannelList(msg);
  230. break;
  231. case Proto::GameServerOpenChannel:
  232. parseOpenChannel(msg);
  233. break;
  234. case Proto::GameServerOpenPrivateChannel:
  235. parseOpenPrivateChannel(msg);
  236. break;
  237. case Proto::GameServerRuleViolationChannel:
  238. parseRuleViolationChannel(msg);
  239. break;
  240. case Proto::GameServerRuleViolationRemove:
  241. parseRuleViolationRemove(msg);
  242. break;
  243. case Proto::GameServerRuleViolationCancel:
  244. parseRuleViolationCancel(msg);
  245. break;
  246. case Proto::GameServerRuleViolationLock:
  247. parseRuleViolationLock(msg);
  248. break;
  249. case Proto::GameServerOpenOwnChannel:
  250. parseOpenOwnPrivateChannel(msg);
  251. break;
  252. case Proto::GameServerCloseChannel:
  253. parseCloseChannel(msg);
  254. break;
  255. case Proto::GameServerTextMessage:
  256. parseTextMessage(msg);
  257. break;
  258. case Proto::GameServerCancelWalk:
  259. parseCancelWalk(msg);
  260. break;
  261. case Proto::GameServerWalkWait:
  262. parseWalkWait(msg);
  263. break;
  264. case Proto::GameServerFloorChangeUp:
  265. parseFloorChangeUp(msg);
  266. break;
  267. case Proto::GameServerFloorChangeDown:
  268. parseFloorChangeDown(msg);
  269. break;
  270. case Proto::GameServerChooseOutfit:
  271. parseOpenOutfitWindow(msg);
  272. break;
  273. case Proto::GameServerVipAdd:
  274. parseVipAdd(msg);
  275. break;
  276. case Proto::GameServerVipState:
  277. parseVipState(msg);
  278. break;
  279. case Proto::GameServerVipLogout:
  280. parseVipLogout(msg);
  281. break;
  282. case Proto::GameServerTutorialHint:
  283. parseTutorialHint(msg);
  284. break;
  285. case Proto::GameServerAutomapFlag:
  286. parseAutomapFlag(msg);
  287. break;
  288. case Proto::GameServerQuestLog:
  289. parseQuestLog(msg);
  290. break;
  291. case Proto::GameServerQuestLine:
  292. parseQuestLine(msg);
  293. break;
  294. // PROTOCOL>=870
  295. case Proto::GameServerSpellDelay:
  296. parseSpellCooldown(msg);
  297. break;
  298. case Proto::GameServerSpellGroupDelay:
  299. parseSpellGroupCooldown(msg);
  300. break;
  301. case Proto::GameServerMultiUseDelay:
  302. parseMultiUseCooldown(msg);
  303. break;
  304. // PROTOCOL>=910
  305. case Proto::GameServerChannelEvent:
  306. parseChannelEvent(msg);
  307. break;
  308. case Proto::GameServerItemInfo:
  309. parseItemInfo(msg);
  310. break;
  311. case Proto::GameServerPlayerInventory:
  312. parsePlayerInventory(msg);
  313. break;
  314. // PROTOCOL>=950
  315. case Proto::GameServerPlayerDataBasic:
  316. parsePlayerInfo(msg);
  317. break;
  318. // PROTOCOL>=970
  319. case Proto::GameServerModalDialog:
  320. parseModalDialog(msg);
  321. break;
  322. // PROTOCOL>=980
  323. case Proto::GameServerLoginSuccess:
  324. parseLogin(msg);
  325. break;
  326. case Proto::GameServerEnterGame:
  327. parseEnterGame(msg);
  328. break;
  329. case Proto::GameServerPlayerHelpers:
  330. parsePlayerHelpers(msg);
  331. break;
  332. // PROTOCOL>=1000
  333. case Proto::GameServerCreatureMarks:
  334. parseCreaturesMark(msg);
  335. break;
  336. case Proto::GameServerCreatureType:
  337. parseCreatureType(msg);
  338. break;
  339. // PROTOCOL>=1055
  340. case Proto::GameServerBlessings:
  341. parseBlessings(msg);
  342. break;
  343. case Proto::GameServerUnjustifiedStats:
  344. parseUnjustifiedStats(msg);
  345. break;
  346. case Proto::GameServerPvpSituations:
  347. parsePvpSituations(msg);
  348. break;
  349. case Proto::GameServerPreset:
  350. parsePreset(msg);
  351. break;
  352. // otclient ONLY
  353. case Proto::GameServerExtendedOpcode:
  354. parseExtendedOpcode(msg);
  355. break;
  356. case Proto::GameServerChangeMapAwareRange:
  357. parseChangeMapAwareRange(msg);
  358. break;
  359. default:
  360. stdext::throw_exception(stdext::format("unhandled opcode %d", (int)opcode));
  361. break;
  362. }
  363. prevOpcode = opcode;
  364. }
  365. } catch(stdext::exception& e) {
  366. g_logger.error(stdext::format("ProtocolGame parse message exception (%d bytes unread, last opcode is %d, prev opcode is %d): %s",
  367. msg->getUnreadSize(), opcode, prevOpcode, e.what()));
  368. }
  369. }
  370. void ProtocolGame::parseLogin(const InputMessagePtr& msg)
  371. {
  372. uint playerId = msg->getU32();
  373. int serverBeat = msg->getU16();
  374. if(g_game.getFeature(Otc::GameNewSpeedLaw)) {
  375. double speedA = msg->getDouble();
  376. double speedB = msg->getDouble();
  377. double speedC = msg->getDouble();
  378. m_localPlayer->setSpeedFormula(speedA, speedB, speedC);
  379. }
  380. bool canReportBugs = msg->getU8();
  381. if(g_game.getClientVersion() >= 1054)
  382. msg->getU8(); // can change pvp frame option
  383. if(g_game.getClientVersion() >= 1058) {
  384. int expertModeEnabled = msg->getU8();
  385. g_game.setExpertPvpMode(expertModeEnabled);
  386. }
  387. m_localPlayer->setId(playerId);
  388. g_game.setServerBeat(serverBeat);
  389. g_game.setCanReportBugs(canReportBugs);
  390. g_game.processLogin();
  391. }
  392. void ProtocolGame::parsePendingGame(const InputMessagePtr& msg)
  393. {
  394. //set player to pending game state
  395. g_game.processPendingGame();
  396. }
  397. void ProtocolGame::parseEnterGame(const InputMessagePtr& msg)
  398. {
  399. //set player to entered game state
  400. g_game.processEnterGame();
  401. if(!m_gameInitialized) {
  402. g_game.processGameStart();
  403. m_gameInitialized = true;
  404. }
  405. }
  406. void ProtocolGame::parseBlessings(const InputMessagePtr& msg)
  407. {
  408. uint16 blessings = msg->getU16();
  409. m_localPlayer->setBlessings(blessings);
  410. }
  411. void ProtocolGame::parsePreset(const InputMessagePtr& msg)
  412. {
  413. uint16 preset = msg->getU32();
  414. }
  415. void ProtocolGame::parseUnjustifiedStats(const InputMessagePtr& msg)
  416. {
  417. UnjustifiedPoints unjustifiedPoints;
  418. unjustifiedPoints.killsDay = msg->getU8();
  419. unjustifiedPoints.killsDayRemaining = msg->getU8();
  420. unjustifiedPoints.killsWeek = msg->getU8();
  421. unjustifiedPoints.killsWeekRemaining = msg->getU8();
  422. unjustifiedPoints.killsMonth = msg->getU8();
  423. unjustifiedPoints.killsMonthRemaining = msg->getU8();
  424. unjustifiedPoints.skullTime = msg->getU8();
  425. g_game.setUnjustifiedPoints(unjustifiedPoints);
  426. }
  427. void ProtocolGame::parsePvpSituations(const InputMessagePtr& msg)
  428. {
  429. uint8 openPvpSituations = msg->getU8();
  430. g_game.setOpenPvpSituations(openPvpSituations);
  431. }
  432. void ProtocolGame::parsePlayerHelpers(const InputMessagePtr& msg)
  433. {
  434. uint id = msg->getU32();
  435. int helpers = msg->getU16();
  436. CreaturePtr creature = g_map.getCreatureById(id);
  437. if(creature)
  438. g_game.processPlayerHelpers(helpers);
  439. else
  440. g_logger.traceError(stdext::format("could not get creature with id %d", id));
  441. }
  442. void ProtocolGame::parseGMActions(const InputMessagePtr& msg)
  443. {
  444. std::vector<uint8> actions;
  445. int numViolationReasons;
  446. if(g_game.getClientVersion() >= 850)
  447. numViolationReasons = 20;
  448. else if(g_game.getClientVersion() >= 840)
  449. numViolationReasons = 23;
  450. else
  451. numViolationReasons = 32;
  452. for(int i = 0; i < numViolationReasons; ++i)
  453. actions.push_back(msg->getU8());
  454. g_game.processGMActions(actions);
  455. }
  456. void ProtocolGame::parseUpdateNeeded(const InputMessagePtr& msg)
  457. {
  458. std::string signature = msg->getString();
  459. g_game.processUpdateNeeded(signature);
  460. }
  461. void ProtocolGame::parseLoginError(const InputMessagePtr& msg)
  462. {
  463. std::string error = msg->getString();
  464. g_game.processLoginError(error);
  465. }
  466. void ProtocolGame::parseLoginAdvice(const InputMessagePtr& msg)
  467. {
  468. std::string message = msg->getString();
  469. g_game.processLoginAdvice(message);
  470. }
  471. void ProtocolGame::parseLoginWait(const InputMessagePtr& msg)
  472. {
  473. std::string message = msg->getString();
  474. int time = msg->getU8();
  475. g_game.processLoginWait(message, time);
  476. }
  477. void ProtocolGame::parseLoginToken(const InputMessagePtr& msg)
  478. {
  479. bool unknown = (msg->getU8() == 0);
  480. g_game.processLoginToken(unknown);
  481. }
  482. void ProtocolGame::parsePing(const InputMessagePtr& msg)
  483. {
  484. g_game.processPing();
  485. }
  486. void ProtocolGame::parsePingBack(const InputMessagePtr& msg)
  487. {
  488. g_game.processPingBack();
  489. }
  490. void ProtocolGame::parseChallenge(const InputMessagePtr& msg)
  491. {
  492. uint timestamp = msg->getU32();
  493. uint8 random = msg->getU8();
  494. sendLoginPacket(timestamp, random);
  495. }
  496. void ProtocolGame::parseDeath(const InputMessagePtr& msg)
  497. {
  498. int penality = 100;
  499. if(g_game.getFeature(Otc::GamePenalityOnDeath))
  500. penality = msg->getU8();
  501. g_game.processDeath(penality);
  502. }
  503. void ProtocolGame::parseMapDescription(const InputMessagePtr& msg)
  504. {
  505. Position pos = getPosition(msg);
  506. if(!m_mapKnown)
  507. m_localPlayer->setPosition(pos);
  508. g_map.setCentralPosition(pos);
  509. AwareRange range = g_map.getAwareRange();
  510. setMapDescription(msg, pos.x - range.left, pos.y - range.top, pos.z, range.horizontal(), range.vertical());
  511. if(!m_mapKnown) {
  512. g_dispatcher.addEvent([] { g_lua.callGlobalField("g_game", "onMapKnown"); });
  513. m_mapKnown = true;
  514. }
  515. g_dispatcher.addEvent([] { g_lua.callGlobalField("g_game", "onMapDescription"); });
  516. }
  517. void ProtocolGame::parseMapMoveNorth(const InputMessagePtr& msg)
  518. {
  519. Position pos;
  520. if(g_game.getFeature(Otc::GameMapMovePosition))
  521. pos = getPosition(msg);
  522. else
  523. pos = g_map.getCentralPosition();
  524. pos.y--;
  525. AwareRange range = g_map.getAwareRange();
  526. setMapDescription(msg, pos.x - range.left, pos.y - range.top, pos.z, range.horizontal(), 1);
  527. g_map.setCentralPosition(pos);
  528. }
  529. void ProtocolGame::parseMapMoveEast(const InputMessagePtr& msg)
  530. {
  531. Position pos;
  532. if(g_game.getFeature(Otc::GameMapMovePosition))
  533. pos = getPosition(msg);
  534. else
  535. pos = g_map.getCentralPosition();
  536. pos.x++;
  537. AwareRange range = g_map.getAwareRange();
  538. setMapDescription(msg, pos.x + range.right, pos.y - range.top, pos.z, 1, range.vertical());
  539. g_map.setCentralPosition(pos);
  540. }
  541. void ProtocolGame::parseMapMoveSouth(const InputMessagePtr& msg)
  542. {
  543. Position pos;
  544. if(g_game.getFeature(Otc::GameMapMovePosition))
  545. pos = getPosition(msg);
  546. else
  547. pos = g_map.getCentralPosition();
  548. pos.y++;
  549. AwareRange range = g_map.getAwareRange();
  550. setMapDescription(msg, pos.x - range.left, pos.y + range.bottom, pos.z, range.horizontal(), 1);
  551. g_map.setCentralPosition(pos);
  552. }
  553. void ProtocolGame::parseMapMoveWest(const InputMessagePtr& msg)
  554. {
  555. Position pos;
  556. if(g_game.getFeature(Otc::GameMapMovePosition))
  557. pos = getPosition(msg);
  558. else
  559. pos = g_map.getCentralPosition();
  560. pos.x--;
  561. AwareRange range = g_map.getAwareRange();
  562. setMapDescription(msg, pos.x - range.left, pos.y - range.top, pos.z, 1, range.vertical());
  563. g_map.setCentralPosition(pos);
  564. }
  565. void ProtocolGame::parseUpdateTile(const InputMessagePtr& msg)
  566. {
  567. Position tilePos = getPosition(msg);
  568. setTileDescription(msg, tilePos);
  569. }
  570. void ProtocolGame::parseTileAddThing(const InputMessagePtr& msg)
  571. {
  572. Position pos = getPosition(msg);
  573. int stackPos = -1;
  574. if(g_game.getClientVersion() >= 841)
  575. stackPos = msg->getU8();
  576. ThingPtr thing = getThing(msg);
  577. g_map.addThing(thing, pos, stackPos);
  578. }
  579. void ProtocolGame::parseTileTransformThing(const InputMessagePtr& msg)
  580. {
  581. ThingPtr thing = getMappedThing(msg);
  582. ThingPtr newThing = getThing(msg);
  583. if(!thing) {
  584. g_logger.traceError("no thing");
  585. return;
  586. }
  587. Position pos = thing->getPosition();
  588. int stackpos = thing->getStackPos();
  589. if(!g_map.removeThing(thing)) {
  590. g_logger.traceError("unable to remove thing");
  591. return;
  592. }
  593. g_map.addThing(newThing, pos, stackpos);
  594. }
  595. void ProtocolGame::parseTileRemoveThing(const InputMessagePtr& msg)
  596. {
  597. ThingPtr thing = getMappedThing(msg);
  598. if(!thing) {
  599. g_logger.traceError("no thing");
  600. return;
  601. }
  602. if(!g_map.removeThing(thing))
  603. g_logger.traceError("unable to remove thing");
  604. }
  605. void ProtocolGame::parseCreatureMove(const InputMessagePtr& msg)
  606. {
  607. ThingPtr thing = getMappedThing(msg);
  608. Position newPos = getPosition(msg);
  609. if(!thing || !thing->isCreature()) {
  610. g_logger.traceError("no creature found to move");
  611. return;
  612. }
  613. if(!g_map.removeThing(thing)) {
  614. g_logger.traceError("unable to remove creature");
  615. return;
  616. }
  617. CreaturePtr creature = thing->static_self_cast<Creature>();
  618. creature->allowAppearWalk();
  619. g_map.addThing(thing, newPos, -1);
  620. }
  621. void ProtocolGame::parseOpenContainer(const InputMessagePtr& msg)
  622. {
  623. int containerId = msg->getU8();
  624. ItemPtr containerItem = getItem(msg);
  625. std::string name = msg->getString();
  626. int capacity = msg->getU8();
  627. bool hasParent = (msg->getU8() != 0);
  628. bool isUnlocked = true;
  629. bool hasPages = false;
  630. int containerSize = 0;
  631. int firstIndex = 0;
  632. if(g_game.getFeature(Otc::GameContainerPagination)) {
  633. isUnlocked = (msg->getU8() != 0); // drag and drop
  634. hasPages = (msg->getU8() != 0); // pagination
  635. containerSize = msg->getU16(); // container size
  636. firstIndex = msg->getU16(); // first index
  637. }
  638. int itemCount = msg->getU8();
  639. std::vector<ItemPtr> items(itemCount);
  640. for(int i = 0; i < itemCount; i++)
  641. items[i] = getItem(msg);
  642. g_game.processOpenContainer(containerId, containerItem, name, capacity, hasParent, items, isUnlocked, hasPages, containerSize, firstIndex);
  643. }
  644. void ProtocolGame::parseCloseContainer(const InputMessagePtr& msg)
  645. {
  646. int containerId = msg->getU8();
  647. g_game.processCloseContainer(containerId);
  648. }
  649. void ProtocolGame::parseContainerAddItem(const InputMessagePtr& msg)
  650. {
  651. int containerId = msg->getU8();
  652. int slot = 0;
  653. if(g_game.getFeature(Otc::GameContainerPagination)) {
  654. slot = msg->getU16(); // slot
  655. }
  656. ItemPtr item = getItem(msg);
  657. g_game.processContainerAddItem(containerId, item, slot);
  658. }
  659. void ProtocolGame::parseContainerUpdateItem(const InputMessagePtr& msg)
  660. {
  661. int containerId = msg->getU8();
  662. int slot;
  663. if(g_game.getFeature(Otc::GameContainerPagination)) {
  664. slot = msg->getU16();
  665. } else {
  666. slot = msg->getU8();
  667. }
  668. ItemPtr item = getItem(msg);
  669. g_game.processContainerUpdateItem(containerId, slot, item);
  670. }
  671. void ProtocolGame::parseContainerRemoveItem(const InputMessagePtr& msg)
  672. {
  673. int containerId = msg->getU8();
  674. int slot;
  675. ItemPtr lastItem;
  676. if(g_game.getFeature(Otc::GameContainerPagination)) {
  677. slot = msg->getU16();
  678. int itemId = msg->getU16();
  679. if(itemId != 0)
  680. lastItem = getItem(msg, itemId);
  681. } else {
  682. slot = msg->getU8();
  683. }
  684. g_game.processContainerRemoveItem(containerId, slot, lastItem);
  685. }
  686. void ProtocolGame::parseAddInventoryItem(const InputMessagePtr& msg)
  687. {
  688. int slot = msg->getU8();
  689. ItemPtr item = getItem(msg);
  690. g_game.processInventoryChange(slot, item);
  691. }
  692. void ProtocolGame::parseRemoveInventoryItem(const InputMessagePtr& msg)
  693. {
  694. int slot = msg->getU8();
  695. g_game.processInventoryChange(slot, ItemPtr());
  696. }
  697. void ProtocolGame::parseOpenNpcTrade(const InputMessagePtr& msg)
  698. {
  699. std::vector<std::tuple<ItemPtr, std::string, int, int, int>> items;
  700. std::string npcName;
  701. if(g_game.getFeature(Otc::GameNameOnNpcTrade))
  702. npcName = msg->getString();
  703. int listCount;
  704. if(g_game.getClientVersion() >= 900)
  705. listCount = msg->getU16();
  706. else
  707. listCount = msg->getU8();
  708. for(int i = 0; i < listCount; ++i) {
  709. uint16 itemId = msg->getU16();
  710. uint8 count = msg->getU8();
  711. ItemPtr item = Item::create(itemId);
  712. item->setCountOrSubType(count);
  713. std::string name = msg->getString();
  714. int weight = msg->getU32();
  715. int buyPrice = msg->getU32();
  716. int sellPrice = msg->getU32();
  717. items.push_back(std::make_tuple(item, name, weight, buyPrice, sellPrice));
  718. }
  719. g_game.processOpenNpcTrade(items);
  720. }
  721. void ProtocolGame::parsePlayerGoods(const InputMessagePtr& msg)
  722. {
  723. std::vector<std::tuple<ItemPtr, int>> goods;
  724. int money;
  725. if(g_game.getClientVersion() >= 973)
  726. money = msg->getU64();
  727. else
  728. money = msg->getU32();
  729. int size = msg->getU8();
  730. for(int i = 0; i < size; i++) {
  731. int itemId = msg->getU16();
  732. int amount;
  733. if(g_game.getFeature(Otc::GameDoubleShopSellAmount))
  734. amount = msg->getU16();
  735. else
  736. amount = msg->getU8();
  737. goods.push_back(std::make_tuple(Item::create(itemId), amount));
  738. }
  739. g_game.processPlayerGoods(money, goods);
  740. }
  741. void ProtocolGame::parseCloseNpcTrade(const InputMessagePtr&)
  742. {
  743. g_game.processCloseNpcTrade();
  744. }
  745. void ProtocolGame::parseOwnTrade(const InputMessagePtr& msg)
  746. {
  747. std::string name = g_game.formatCreatureName(msg->getString());
  748. int count = msg->getU8();
  749. std::vector<ItemPtr> items(count);
  750. for(int i = 0; i < count; i++)
  751. items[i] = getItem(msg);
  752. g_game.processOwnTrade(name, items);
  753. }
  754. void ProtocolGame::parseCounterTrade(const InputMessagePtr& msg)
  755. {
  756. std::string name = g_game.formatCreatureName(msg->getString());
  757. int count = msg->getU8();
  758. std::vector<ItemPtr> items(count);
  759. for(int i = 0; i < count; i++)
  760. items[i] = getItem(msg);
  761. g_game.processCounterTrade(name, items);
  762. }
  763. void ProtocolGame::parseCloseTrade(const InputMessagePtr&)
  764. {
  765. g_game.processCloseTrade();
  766. }
  767. void ProtocolGame::parseWorldLight(const InputMessagePtr& msg)
  768. {
  769. Light light;
  770. light.intensity = msg->getU8();
  771. light.color = msg->getU8();
  772. g_map.setLight(light);
  773. }
  774. void ProtocolGame::parseMagicEffect(const InputMessagePtr& msg)
  775. {
  776. Position pos = getPosition(msg);
  777. int effectId;
  778. if(g_game.getFeature(Otc::GameMagicEffectU16))
  779. effectId = msg->getU16();
  780. else
  781. effectId = msg->getU8();
  782. if(!g_things.isValidDatId(effectId, ThingCategoryEffect)) {
  783. g_logger.traceError(stdext::format("invalid effect id %d", effectId));
  784. return;
  785. }
  786. EffectPtr effect = EffectPtr(new Effect());
  787. effect->setId(effectId);
  788. g_map.addThing(effect, pos);
  789. }
  790. void ProtocolGame::parseAnimatedText(const InputMessagePtr& msg)
  791. {
  792. Position position = getPosition(msg);
  793. int color = msg->getU8();
  794. std::string text = msg->getString();
  795. AnimatedTextPtr animatedText = AnimatedTextPtr(new AnimatedText);
  796. animatedText->setColor(color);
  797. animatedText->setText(text);
  798. g_map.addThing(animatedText, position);
  799. }
  800. void ProtocolGame::parseDistanceMissile(const InputMessagePtr& msg)
  801. {
  802. Position fromPos = getPosition(msg);
  803. Position toPos = getPosition(msg);
  804. int shotId = msg->getU8();
  805. if(!g_things.isValidDatId(shotId, ThingCategoryMissile)) {
  806. g_logger.traceError(stdext::format("invalid missile id %d", shotId));
  807. return;
  808. }
  809. MissilePtr missile = MissilePtr(new Missile());
  810. missile->setId(shotId);
  811. missile->setPath(fromPos, toPos);
  812. g_map.addThing(missile, fromPos);
  813. }
  814. void ProtocolGame::parseCreatureMark(const InputMessagePtr& msg)
  815. {
  816. uint id = msg->getU32();
  817. int color = msg->getU8();
  818. CreaturePtr creature = g_map.getCreatureById(id);
  819. if(creature)
  820. creature->addTimedSquare(color);
  821. else
  822. g_logger.traceError("could not get creature");
  823. }
  824. void ProtocolGame::parseTrappers(const InputMessagePtr& msg)
  825. {
  826. int numTrappers = msg->getU8();
  827. if(numTrappers > 8)
  828. g_logger.traceError("too many trappers");
  829. for(int i=0;i<numTrappers;++i) {
  830. uint id = msg->getU32();
  831. CreaturePtr creature = g_map.getCreatureById(id);
  832. if(creature) {
  833. //TODO: set creature as trapper
  834. } else
  835. g_logger.traceError("could not get creature");
  836. }
  837. }
  838. void ProtocolGame::parseCreatureHealth(const InputMessagePtr& msg)
  839. {
  840. uint id = msg->getU32();
  841. int healthPercent = msg->getU8();
  842. CreaturePtr creature = g_map.getCreatureById(id);
  843. if(creature)
  844. creature->setHealthPercent(healthPercent);
  845. // some servers has a bug in get spectators and sends unknown creatures updates
  846. // so this code is disabled
  847. /*
  848. else
  849. g_logger.traceError("could not get creature");
  850. */
  851. }
  852. void ProtocolGame::parseCreatureLight(const InputMessagePtr& msg)
  853. {
  854. uint id = msg->getU32();
  855. Light light;
  856. light.intensity = msg->getU8();
  857. light.color = msg->getU8();
  858. CreaturePtr creature = g_map.getCreatureById(id);
  859. if(creature)
  860. creature->setLight(light);
  861. else
  862. g_logger.traceError("could not get creature");
  863. }
  864. void ProtocolGame::parseCreatureOutfit(const InputMessagePtr& msg)
  865. {
  866. uint id = msg->getU32();
  867. Outfit outfit = getOutfit(msg);
  868. CreaturePtr creature = g_map.getCreatureById(id);
  869. if(creature)
  870. creature->setOutfit(outfit);
  871. else
  872. g_logger.traceError("could not get creature");
  873. }
  874. void ProtocolGame::parseCreatureSpeed(const InputMessagePtr& msg)
  875. {
  876. uint id = msg->getU32();
  877. int baseSpeed = -1;
  878. if(g_game.getClientVersion() >= 1059)
  879. baseSpeed = msg->getU16();
  880. int speed = msg->getU16();
  881. CreaturePtr creature = g_map.getCreatureById(id);
  882. if(creature) {
  883. creature->setSpeed(speed);
  884. if(baseSpeed != -1)
  885. creature->setBaseSpeed(baseSpeed);
  886. }
  887. // some servers has a bug in get spectators and sends unknown creatures updates
  888. // so this code is disabled
  889. /*
  890. else
  891. g_logger.traceError("could not get creature");
  892. */
  893. }
  894. void ProtocolGame::parseCreatureSkulls(const InputMessagePtr& msg)
  895. {
  896. uint id = msg->getU32();
  897. int skull = msg->getU8();
  898. CreaturePtr creature = g_map.getCreatureById(id);
  899. if(creature)
  900. creature->setSkull(skull);
  901. else
  902. g_logger.traceError("could not get creature");
  903. }
  904. void ProtocolGame::parseCreatureShields(const InputMessagePtr& msg)
  905. {
  906. uint id = msg->getU32();
  907. int shield = msg->getU8();
  908. CreaturePtr creature = g_map.getCreatureById(id);
  909. if(creature)
  910. creature->setShield(shield);
  911. else
  912. g_logger.traceError("could not get creature");
  913. }
  914. void ProtocolGame::parseCreatureUnpass(const InputMessagePtr& msg)
  915. {
  916. uint id = msg->getU32();
  917. bool unpass = msg->getU8();
  918. CreaturePtr creature = g_map.getCreatureById(id);
  919. if(creature)
  920. creature->setPassable(!unpass);
  921. else
  922. g_logger.traceError("could not get creature");
  923. }
  924. void ProtocolGame::parseEditText(const InputMessagePtr& msg)
  925. {
  926. uint id = msg->getU32();
  927. int itemId;
  928. if(g_game.getClientVersion() >= 1010) {
  929. // TODO: processEditText with ItemPtr as parameter
  930. ItemPtr item = getItem(msg);
  931. itemId = item->getId();
  932. } else
  933. itemId = msg->getU16();
  934. int maxLength = msg->getU16();
  935. std::string text = msg->getString();
  936. std::string writer = msg->getString();
  937. std::string date = "";
  938. if(g_game.getFeature(Otc::GameWritableDate))
  939. date = msg->getString();
  940. g_game.processEditText(id, itemId, maxLength, text, writer, date);
  941. }
  942. void ProtocolGame::parseEditList(const InputMessagePtr& msg)
  943. {
  944. int doorId = msg->getU8();
  945. uint id = msg->getU32();
  946. const std::string& text = msg->getString();
  947. g_game.processEditList(id, doorId, text);
  948. }
  949. void ProtocolGame::parsePremiumTrigger(const InputMessagePtr& msg)
  950. {
  951. int triggerCount = msg->getU8();
  952. std::vector<int> triggers;
  953. for(int i=0;i<triggerCount;++i) {
  954. triggers.push_back(msg->getU8());
  955. }
  956. bool something = msg->getU8() == 1;
  957. }
  958. void ProtocolGame::parsePlayerInfo(const InputMessagePtr& msg)
  959. {
  960. bool premium = msg->getU8(); // premium
  961. int vocation = msg->getU8(); // vocation
  962. if(g_game.getFeature(Otc::GamePremiumExpiration))
  963. int premiumEx = msg->getU32(); // premium expiration used for premium advertisement
  964. int spellCount = msg->getU16();
  965. std::vector<int> spells;
  966. for(int i=0;i<spellCount;++i)
  967. spells.push_back(msg->getU8()); // spell id
  968. m_localPlayer->setPremium(premium);
  969. m_localPlayer->setVocation(vocation);
  970. m_localPlayer->setSpells(spells);
  971. }
  972. void ProtocolGame::parsePlayerStats(const InputMessagePtr& msg)
  973. {
  974. double health;
  975. double maxHealth;
  976. if(g_game.getFeature(Otc::GameDoubleHealth)) {
  977. health = msg->getU32();
  978. maxHealth = msg->getU32();
  979. } else {
  980. health = msg->getU16();
  981. maxHealth = msg->getU16();
  982. }
  983. double freeCapacity;
  984. if(g_game.getFeature(Otc::GameDoubleFreeCapacity))
  985. freeCapacity = msg->getU32() / 100.0;
  986. else
  987. freeCapacity = msg->getU16() / 100.0;
  988. double totalCapacity = 0;
  989. if(g_game.getFeature(Otc::GameTotalCapacity))
  990. totalCapacity = msg->getU32() / 100.0;
  991. double experience;
  992. if(g_game.getFeature(Otc::GameDoubleExperience))
  993. experience = msg->getU64();
  994. else
  995. experience = msg->getU32();
  996. double level = msg->getU16();
  997. double levelPercent = msg->getU8();
  998. if(g_game.getFeature(Otc::GameExperienceBonus))
  999. double experienceBonus = msg->getDouble();
  1000. double mana;
  1001. double maxMana;
  1002. if(g_game.getFeature(Otc::GameDoubleHealth)) {
  1003. mana = msg->getU32();
  1004. maxMana = msg->getU32();
  1005. } else {
  1006. mana = msg->getU16();
  1007. maxMana = msg->getU16();
  1008. }
  1009. double magicLevel = msg->getU8();
  1010. double baseMagicLevel;
  1011. if(g_game.getFeature(Otc::GameSkillsBase))
  1012. baseMagicLevel = msg->getU8();
  1013. else
  1014. baseMagicLevel = magicLevel;
  1015. double magicLevelPercent = msg->getU8();
  1016. double soul = msg->getU8();
  1017. double stamina = 0;
  1018. if(g_game.getFeature(Otc::GamePlayerStamina))
  1019. stamina = msg->getU16();
  1020. double baseSpeed = 0;
  1021. if(g_game.getFeature(Otc::GameSkillsBase))
  1022. baseSpeed = msg->getU16();
  1023. double regeneration = 0;
  1024. if(g_game.getFeature(Otc::GamePlayerRegenerationTime))
  1025. regeneration = msg->getU16();
  1026. double training = 0;
  1027. if(g_game.getFeature(Otc::GameOfflineTrainingTime))
  1028. training = msg->getU16();
  1029. m_localPlayer->setHealth(health, maxHealth);
  1030. m_localPlayer->setFreeCapacity(freeCapacity);
  1031. m_localPlayer->setTotalCapacity(totalCapacity);
  1032. m_localPlayer->setExperience(experience);
  1033. m_localPlayer->setLevel(level, levelPercent);
  1034. m_localPlayer->setMana(mana, maxMana);
  1035. m_localPlayer->setMagicLevel(magicLevel, magicLevelPercent);
  1036. m_localPlayer->setBaseMagicLevel(baseMagicLevel);
  1037. m_localPlayer->setStamina(stamina);
  1038. m_localPlayer->setSoul(soul);
  1039. m_localPlayer->setBaseSpeed(baseSpeed);
  1040. m_localPlayer->setRegenerationTime(regeneration);
  1041. m_localPlayer->setOfflineTrainingTime(training);
  1042. }
  1043. void ProtocolGame::parsePlayerSkills(const InputMessagePtr& msg)
  1044. {
  1045. for(int skill = 0; skill < Otc::LastSkill; skill++) {
  1046. int level;
  1047. if(g_game.getFeature(Otc::GameDoubleSkills))
  1048. level = msg->getU16();
  1049. else
  1050. level = msg->getU8();
  1051. int baseLevel;
  1052. if(g_game.getFeature(Otc::GameSkillsBase))
  1053. if(g_game.getFeature(Otc::GameBaseSkillU16))
  1054. baseLevel = msg->getU16();
  1055. else
  1056. baseLevel = msg->getU8();
  1057. else
  1058. baseLevel = level;
  1059. int levelPercent = msg->getU8();
  1060. m_localPlayer->setSkill((Otc::Skill)skill, level, levelPercent);
  1061. m_localPlayer->setBaseSkill((Otc::Skill)skill, baseLevel);
  1062. }
  1063. }
  1064. void ProtocolGame::parsePlayerState(const InputMessagePtr& msg)
  1065. {
  1066. int states;
  1067. if(g_game.getFeature(Otc::GamePlayerStateU16))
  1068. states = msg->getU16();
  1069. else
  1070. states = msg->getU8();
  1071. m_localPlayer->setStates(states);
  1072. }
  1073. void ProtocolGame::parsePlayerCancelAttack(const InputMessagePtr& msg)
  1074. {
  1075. uint seq = 0;
  1076. if(g_game.getFeature(Otc::GameAttackSeq))
  1077. seq = msg->getU32();
  1078. g_game.processAttackCancel(seq);
  1079. }
  1080. void ProtocolGame::parsePlayerModes(const InputMessagePtr& msg)
  1081. {
  1082. int fightMode = msg->getU8();
  1083. int chaseMode = msg->getU8();
  1084. bool safeMode = msg->getU8();
  1085. int pvpMode = 0;
  1086. if(g_game.getFeature(Otc::GamePVPMode))
  1087. pvpMode = msg->getU8();
  1088. g_game.processPlayerModes((Otc::FightModes)fightMode, (Otc::ChaseModes)chaseMode, safeMode, (Otc::PVPModes)pvpMode);
  1089. }
  1090. void ProtocolGame::parseSpellCooldown(const InputMessagePtr& msg)
  1091. {
  1092. int spellId = msg->getU8();
  1093. int delay = msg->getU32();
  1094. g_lua.callGlobalField("g_game", "onSpellCooldown", spellId, delay);
  1095. }
  1096. void ProtocolGame::parseSpellGroupCooldown(const InputMessagePtr& msg)
  1097. {
  1098. int groupId = msg->getU8();
  1099. int delay = msg->getU32();
  1100. g_lua.callGlobalField("g_game", "onSpellGroupCooldown", groupId, delay);
  1101. }
  1102. void ProtocolGame::parseMultiUseCooldown(const InputMessagePtr& msg)
  1103. {
  1104. int delay = msg->getU32();
  1105. g_lua.callGlobalField("g_game", "onMultiUseCooldown", delay);
  1106. }
  1107. void ProtocolGame::parseTalk(const InputMessagePtr& msg)
  1108. {
  1109. if(g_game.getFeature(Otc::GameMessageStatements))
  1110. msg->getU32(); // channel statement guid
  1111. std::string name = g_game.formatCreatureName(msg->getString());
  1112. int level = 0;
  1113. if(g_game.getFeature(Otc::GameMessageLevel))
  1114. level = msg->getU16();
  1115. Otc::MessageMode mode = Proto::translateMessageModeFromServer(msg->getU8());
  1116. int channelId = 0;
  1117. Position pos;
  1118. switch(mode) {
  1119. case Otc::MessageSay:
  1120. case Otc::MessageWhisper:
  1121. case Otc::MessageYell:
  1122. case Otc::MessageMonsterSay:
  1123. case Otc::MessageMonsterYell:
  1124. case Otc::MessageNpcTo:
  1125. case Otc::MessageNpcFrom:
  1126. case Otc::MessageBarkLow:
  1127. case Otc::MessageBarkLoud:
  1128. case Otc::MessageSpell:
  1129. pos = getPosition(msg);
  1130. break;
  1131. case Otc::MessageChannel:
  1132. case Otc::MessageChannelManagement:
  1133. case Otc::MessageChannelHighlight:
  1134. case Otc::MessageGamemasterChannel:
  1135. channelId = msg->getU16();
  1136. break;
  1137. case Otc::MessagePrivateFrom:
  1138. case Otc::MessageGamemasterBroadcast:
  1139. case Otc::MessageGamemasterPrivateFrom:
  1140. case Otc::MessageRVRAnswer:
  1141. case Otc::MessageRVRContinue:
  1142. break;
  1143. case Otc::MessageRVRChannel:
  1144. msg->getU32();
  1145. break;
  1146. default:
  1147. stdext::throw_exception(stdext::format("unknown message mode %d", mode));
  1148. break;
  1149. }
  1150. std::string text = msg->getString();
  1151. g_game.processTalk(name, level, mode, text, channelId, pos);
  1152. }
  1153. void ProtocolGame::parseChannelList(const InputMessagePtr& msg)
  1154. {
  1155. int count = msg->getU8();
  1156. std::vector<std::tuple<int, std::string> > channelList;
  1157. for(int i = 0; i < count; i++) {
  1158. int id = msg->getU16();
  1159. std::string name = msg->getString();
  1160. channelList.push_back(std::make_tuple(id, name));
  1161. }
  1162. g_game.processChannelList(channelList);
  1163. }
  1164. void ProtocolGame::parseOpenChannel(const InputMessagePtr& msg)
  1165. {
  1166. int channelId = msg->getU16();
  1167. std::string name = msg->getString();
  1168. if(g_game.getFeature(Otc::GameChannelPlayerList)) {
  1169. int joinedPlayers = msg->getU16();
  1170. for(int i=0;i<joinedPlayers;++i)
  1171. g_game.formatCreatureName(msg->getString()); // player name
  1172. int invitedPlayers = msg->getU16();
  1173. for(int i=0;i<invitedPlayers;++i)
  1174. g_game.formatCreatureName(msg->getString()); // player name
  1175. }
  1176. g_game.processOpenChannel(channelId, name);
  1177. }
  1178. void ProtocolGame::parseOpenPrivateChannel(const InputMessagePtr& msg)
  1179. {
  1180. std::string name = g_game.formatCreatureName(msg->getString());
  1181. g_game.processOpenPrivateChannel(name);
  1182. }
  1183. void ProtocolGame::parseOpenOwnPrivateChannel(const InputMessagePtr& msg)
  1184. {
  1185. int channelId = msg->getU16();
  1186. std::string name = msg->getString();
  1187. g_game.processOpenOwnPrivateChannel(channelId, name);
  1188. }
  1189. void ProtocolGame::parseCloseChannel(const InputMessagePtr& msg)
  1190. {
  1191. int channelId = msg->getU16();
  1192. g_game.processCloseChannel(channelId);
  1193. }
  1194. void ProtocolGame::parseRuleViolationChannel(const InputMessagePtr& msg)
  1195. {
  1196. int channelId = msg->getU16();
  1197. g_game.processRuleViolationChannel(channelId);
  1198. }
  1199. void ProtocolGame::parseRuleViolationRemove(const InputMessagePtr& msg)
  1200. {
  1201. std::string name = msg->getString();
  1202. g_game.processRuleViolationRemove(name);
  1203. }
  1204. void ProtocolGame::parseRuleViolationCancel(const InputMessagePtr& msg)
  1205. {
  1206. std::string name = msg->getString();
  1207. g_game.processRuleViolationCancel(name);
  1208. }
  1209. void ProtocolGame::parseRuleViolationLock(const InputMessagePtr& msg)
  1210. {
  1211. g_game.processRuleViolationLock();
  1212. }
  1213. void ProtocolGame::parseTextMessage(const InputMessagePtr& msg)
  1214. {
  1215. int code = msg->getU8();
  1216. Otc::MessageMode mode = Proto::translateMessageModeFromServer(code);
  1217. std::string text;
  1218. switch(mode) {
  1219. case Otc::MessageChannelManagement: {
  1220. int channel = msg->getU16();
  1221. text = msg->getString();
  1222. break;
  1223. }
  1224. case Otc::MessageDamageDealed:
  1225. case Otc::MessageDamageReceived:
  1226. case Otc::MessageDamageOthers: {
  1227. Position pos = getPosition(msg);
  1228. uint value[2];
  1229. int color[2];
  1230. // physical damage
  1231. value[0] = msg->getU32();
  1232. color[0] = msg->getU8();
  1233. // magic damage
  1234. value[1] = msg->getU32();
  1235. color[1] = msg->getU8();
  1236. text = msg->getString();
  1237. for(int i=0;i<2;++i) {
  1238. if(value[i] == 0)
  1239. continue;
  1240. AnimatedTextPtr animatedText = AnimatedTextPtr(new AnimatedText);
  1241. animatedText->setColor(color[i]);
  1242. animatedText->setText(stdext::to_string(value[i]));
  1243. g_map.addThing(animatedText, pos);
  1244. }
  1245. break;
  1246. }
  1247. case Otc::MessageHeal:
  1248. case Otc::MessageExp:
  1249. case Otc::MessageHealOthers:
  1250. case Otc::MessageExpOthers: {
  1251. Position pos = getPosition(msg);
  1252. uint value = msg->getU32();
  1253. int color = msg->getU8();
  1254. text = msg->getString();
  1255. AnimatedTextPtr animatedText = AnimatedTextPtr(new AnimatedText);
  1256. animatedText->setColor(color);
  1257. animatedText->setText(stdext::to_string(value));
  1258. g_map.addThing(animatedText, pos);
  1259. break;
  1260. }
  1261. case Otc::MessageInvalid:
  1262. stdext::throw_exception(stdext::format("unknown message mode %d", mode));
  1263. break;
  1264. default:
  1265. text = msg->getString();
  1266. break;
  1267. }
  1268. g_game.processTextMessage(mode, text);
  1269. }
  1270. void ProtocolGame::parseCancelWalk(const InputMessagePtr& msg)
  1271. {
  1272. Otc::Direction direction = (Otc::Direction)msg->getU8();
  1273. g_game.processWalkCancel(direction);
  1274. }
  1275. void ProtocolGame::parseWalkWait(const InputMessagePtr& msg)
  1276. {
  1277. int millis = msg->getU16();
  1278. m_localPlayer->lockWalk(millis);
  1279. }
  1280. void ProtocolGame::parseFloorChangeUp(const InputMessagePtr& msg)
  1281. {
  1282. Position pos;
  1283. if(g_game.getFeature(Otc::GameMapMovePosition))
  1284. pos = getPosition(msg);
  1285. else
  1286. pos = g_map.getCentralPosition();
  1287. AwareRange range = g_map.getAwareRange();
  1288. pos.z--;
  1289. int skip = 0;
  1290. if(pos.z == Otc::SEA_FLOOR)
  1291. for(int i = Otc::SEA_FLOOR - Otc::AWARE_UNDEGROUND_FLOOR_RANGE; i >= 0; i--)
  1292. skip = setFloorDescription(msg, pos.x - range.left, pos.y - range.top, i, range.horizontal(), range.vertical(), 8 - i, skip);
  1293. else if(pos.z > Otc::SEA_FLOOR)
  1294. skip = setFloorDescription(msg, pos.x - range.left, pos.y - range.top, pos.z - Otc::AWARE_UNDEGROUND_FLOOR_RANGE, range.horizontal(), range.vertical(), 3, skip);
  1295. pos.x++;
  1296. pos.y++;
  1297. g_map.setCentralPosition(pos);
  1298. }
  1299. void ProtocolGame::parseFloorChangeDown(const InputMessagePtr& msg)
  1300. {
  1301. Position pos;
  1302. if(g_game.getFeature(Otc::GameMapMovePosition))
  1303. pos = getPosition(msg);
  1304. else
  1305. pos = g_map.getCentralPosition();
  1306. AwareRange range = g_map.getAwareRange();
  1307. pos.z++;
  1308. int skip = 0;
  1309. if(pos.z == Otc::UNDERGROUND_FLOOR) {
  1310. int j, i;
  1311. for(i = pos.z, j = -1; i <= pos.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE; ++i, --j)
  1312. skip = setFloorDescription(msg, pos.x - range.left, pos.y - range.top, i, range.horizontal(), range.vertical(), j, skip);
  1313. }
  1314. else if(pos.z > Otc::UNDERGROUND_FLOOR && pos.z < Otc::MAX_Z-1)
  1315. skip = setFloorDescription(msg, pos.x - range.left, pos.y - range.top, pos.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE, range.horizontal(), range.vertical(), -3, skip);
  1316. pos.x--;
  1317. pos.y--;
  1318. g_map.setCentralPosition(pos);
  1319. }
  1320. void ProtocolGame::parseOpenOutfitWindow(const InputMessagePtr& msg)
  1321. {
  1322. Outfit currentOutfit = getOutfit(msg);
  1323. std::vector<std::tuple<int, std::string, int> > outfitList;
  1324. if(g_game.getFeature(Otc::GameNewOutfitProtocol)) {
  1325. int outfitCount = msg->getU8();
  1326. for(int i = 0; i < outfitCount; i++) {
  1327. int outfitId = msg->getU16();
  1328. std::string outfitName = msg->getString();
  1329. int outfitAddons = msg->getU8();
  1330. outfitList.push_back(std::make_tuple(outfitId, outfitName, outfitAddons));
  1331. }
  1332. } else {
  1333. int outfitStart, outfitEnd;
  1334. if(g_game.getFeature(Otc::GameLooktypeU16)) {
  1335. outfitStart = msg->getU16();
  1336. outfitEnd = msg->getU16();
  1337. } else {
  1338. outfitStart = msg->getU8();
  1339. outfitEnd = msg->getU8();
  1340. }
  1341. for(int i = outfitStart; i <= outfitEnd; i++)
  1342. outfitList.push_back(std::make_tuple(i, "", 0));
  1343. }
  1344. std::vector<std::tuple<int, std::string> > mountList;
  1345. if(g_game.getFeature(Otc::GamePlayerMounts)) {
  1346. int mountCount = msg->getU8();
  1347. for(int i = 0; i < mountCount; ++i) {
  1348. int mountId = msg->getU16(); // mount type
  1349. std::string mountName = msg->getString(); // mount name
  1350. mountList.push_back(std::make_tuple(mountId, mountName));
  1351. }
  1352. }
  1353. g_game.processOpenOutfitWindow(currentOutfit, outfitList, mountList);
  1354. }
  1355. void ProtocolGame::parseVipAdd(const InputMessagePtr& msg)
  1356. {
  1357. uint id, iconId = 0, status;
  1358. std::string name, desc = "";
  1359. bool notifyLogin = false;
  1360. id = msg->getU32();
  1361. name = g_game.formatCreatureName(msg->getString());
  1362. if(g_game.getFeature(Otc::GameAdditionalVipInfo)) {
  1363. desc = msg->getString();
  1364. iconId = msg->getU32();
  1365. notifyLogin = msg->getU8();
  1366. }
  1367. status = msg->getU8();
  1368. g_game.processVipAdd(id, name, status, desc, iconId, notifyLogin);
  1369. }
  1370. void ProtocolGame::parseVipState(const InputMessagePtr& msg)
  1371. {
  1372. uint id = msg->getU32();
  1373. if(g_game.getFeature(Otc::GameLoginPending)) {
  1374. uint status = msg->getU8();
  1375. g_game.processVipStateChange(id, status);
  1376. }
  1377. else {
  1378. g_game.processVipStateChange(id, 1);
  1379. }
  1380. }
  1381. void ProtocolGame::parseVipLogout(const InputMessagePtr& msg)
  1382. {
  1383. uint id = msg->getU32();
  1384. g_game.processVipStateChange(id, 0);
  1385. }
  1386. void ProtocolGame::parseTutorialHint(const InputMessagePtr& msg)
  1387. {
  1388. int id = msg->getU8();
  1389. g_game.processTutorialHint(id);
  1390. }
  1391. void ProtocolGame::parseAutomapFlag(const InputMessagePtr& msg)
  1392. {
  1393. Position pos = getPosition(msg);
  1394. int icon = msg->getU8();
  1395. std::string description = msg->getString();
  1396. bool remove = false;
  1397. if(g_game.getFeature(Otc::GameMinimapRemove))
  1398. remove = msg->getU8() != 0;
  1399. if(!remove)
  1400. g_game.processAddAutomapFlag(pos, icon, description);
  1401. else
  1402. g_game.processRemoveAutomapFlag(pos, icon, description);
  1403. }
  1404. void ProtocolGame::parseQuestLog(const InputMessagePtr& msg)
  1405. {
  1406. std::vector<std::tuple<int, std::string, bool> > questList;
  1407. int questsCount = msg->getU16();
  1408. for(int i = 0; i < questsCount; i++) {
  1409. int id = msg->getU16();
  1410. std::string name = msg->getString();
  1411. bool completed = msg->getU8();
  1412. questList.push_back(std::make_tuple(id, name, completed));
  1413. }
  1414. g_game.processQuestLog(questList);
  1415. }
  1416. void ProtocolGame::parseQuestLine(const InputMessagePtr& msg)
  1417. {
  1418. std::vector<std::tuple<std::string, std::string>> questMissions;
  1419. int questId = msg->getU16();
  1420. int missionCount = msg->getU8();
  1421. for(int i = 0; i < missionCount; i++) {
  1422. std::string missionName = msg->getString();
  1423. std::string missionDescrition = msg->getString();
  1424. questMissions.push_back(std::make_tuple(missionName, missionDescrition));
  1425. }
  1426. g_game.processQuestLine(questId, questMissions);
  1427. }
  1428. void ProtocolGame::parseChannelEvent(const InputMessagePtr& msg)
  1429. {
  1430. msg->getU16(); // channel id
  1431. g_game.formatCreatureName(msg->getString()); // player name
  1432. msg->getU8(); // event type
  1433. }
  1434. void ProtocolGame::parseItemInfo(const InputMessagePtr& msg)
  1435. {
  1436. std::vector<std::tuple<ItemPtr, std::string>> list;
  1437. int size = msg->getU8();
  1438. for(int i=0;i<size;++i) {
  1439. ItemPtr item(new Item);
  1440. item->setId(msg->getU16());
  1441. item->setCountOrSubType(msg->getU8());
  1442. std::string desc = msg->getString();
  1443. list.push_back(std::make_tuple(item, desc));
  1444. }
  1445. g_lua.callGlobalField("g_game", "onItemInfo", list);
  1446. }
  1447. void ProtocolGame::parsePlayerInventory(const InputMessagePtr& msg)
  1448. {
  1449. int size = msg->getU16();
  1450. for(int i=0;i<size;++i) {
  1451. msg->getU16(); // id
  1452. msg->getU8(); // subtype
  1453. msg->getU16(); // count
  1454. }
  1455. }
  1456. void ProtocolGame::parseModalDialog(const InputMessagePtr& msg)
  1457. {
  1458. uint32 id = msg->getU32();
  1459. std::string title = msg->getString();
  1460. std::string message = msg->getString();
  1461. int sizeButtons = msg->getU8();
  1462. std::vector<std::tuple<int, std::string> > buttonList;
  1463. for(int i = 0; i < sizeButtons; ++i) {
  1464. std::string value = msg->getString();
  1465. int id = msg->getU8();
  1466. buttonList.push_back(std::make_tuple(id, value));
  1467. }
  1468. int sizeChoices = msg->getU8();
  1469. std::vector<std::tuple<int, std::string> > choiceList;
  1470. for(int i = 0; i < sizeChoices; ++i) {
  1471. std::string value = msg->getString();
  1472. int id = msg->getU8();
  1473. choiceList.push_back(std::make_tuple(id, value));
  1474. }
  1475. int enterButton, escapeButton;
  1476. if(g_game.getClientVersion() > 970) {
  1477. escapeButton = msg->getU8();
  1478. enterButton = msg->getU8();
  1479. }
  1480. else {
  1481. enterButton = msg->getU8();
  1482. escapeButton = msg->getU8();
  1483. }
  1484. bool priority = msg->getU8() == 0x01;
  1485. g_game.processModalDialog(id, title, message, buttonList, enterButton, escapeButton, choiceList, priority);
  1486. }
  1487. void ProtocolGame::parseExtendedOpcode(const InputMessagePtr& msg)
  1488. {
  1489. int opcode = msg->getU8();
  1490. std::string buffer = msg->getString();
  1491. if(opcode == 0)
  1492. m_enableSendExtendedOpcode = true;
  1493. else if(opcode == 2)
  1494. parsePingBack(msg);
  1495. else
  1496. callLuaField("onExtendedOpcode", opcode, buffer);
  1497. }
  1498. void ProtocolGame::parseChangeMapAwareRange(const InputMessagePtr& msg)
  1499. {
  1500. int xrange = msg->getU8();
  1501. int yrange = msg->getU8();
  1502. AwareRange range;
  1503. range.left = xrange/2 - ((xrange+1) % 2);
  1504. range.right = xrange/2;
  1505. range.top = yrange/2 - ((yrange+1) % 2);
  1506. range.bottom = yrange/2;
  1507. g_map.setAwareRange(range);
  1508. g_lua.callGlobalField("g_game", "onMapChangeAwareRange", xrange, yrange);
  1509. }
  1510. void ProtocolGame::parseCreaturesMark(const InputMessagePtr& msg)
  1511. {
  1512. int len;
  1513. if(g_game.getClientVersion() >= 1035) {
  1514. len = 1;
  1515. } else {
  1516. len = msg->getU8();
  1517. }
  1518. for(int i=0; i<len; ++i) {
  1519. uint32 id = msg->getU32();
  1520. bool isPermanent = msg->getU8() != 1;
  1521. uint8 markType = msg->getU8();
  1522. CreaturePtr creature = g_map.getCreatureById(id);
  1523. if(creature) {
  1524. if(isPermanent) {
  1525. if(markType == 0xff)
  1526. creature->hideStaticSquare();
  1527. else
  1528. creature->showStaticSquare(Color::from8bit(markType));
  1529. } else
  1530. creature->addTimedSquare(markType);
  1531. } else
  1532. g_logger.traceError("could not get creature");
  1533. }
  1534. }
  1535. void ProtocolGame::parseCreatureType(const InputMessagePtr& msg)
  1536. {
  1537. uint32 id = msg->getU32();
  1538. uint8 type = msg->getU8();
  1539. }
  1540. void ProtocolGame::setMapDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height)
  1541. {
  1542. int startz, endz, zstep;
  1543. if(z > Otc::SEA_FLOOR) {
  1544. startz = z - Otc::AWARE_UNDEGROUND_FLOOR_RANGE;
  1545. endz = std::min<int>(z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE, (int)Otc::MAX_Z);
  1546. zstep = 1;
  1547. }
  1548. else {
  1549. startz = Otc::SEA_FLOOR;
  1550. endz = 0;
  1551. zstep = -1;
  1552. }
  1553. int skip = 0;
  1554. for(int nz = startz; nz != endz + zstep; nz += zstep)
  1555. skip = setFloorDescription(msg, x, y, nz, width, height, z - nz, skip);
  1556. }
  1557. int ProtocolGame::setFloorDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height, int offset, int skip)
  1558. {
  1559. for(int nx = 0; nx < width; nx++) {
  1560. for(int ny = 0; ny < height; ny++) {
  1561. Position tilePos(x + nx + offset, y + ny + offset, z);
  1562. if(skip == 0)
  1563. skip = setTileDescription(msg, tilePos);
  1564. else {
  1565. g_map.cleanTile(tilePos);
  1566. skip--;
  1567. }
  1568. }
  1569. }
  1570. return skip;
  1571. }
  1572. int ProtocolGame::setTileDescription(const InputMessagePtr& msg, Position position)
  1573. {
  1574. g_map.cleanTile(position);
  1575. bool gotEffect = false;
  1576. for(int stackPos=0;stackPos<256;stackPos++) {
  1577. if(msg->peekU16() >= 0xff00)
  1578. return msg->getU16() & 0xff;
  1579. if(g_game.getFeature(Otc::GameEnvironmentEffect) && !gotEffect) {
  1580. msg->getU16(); // environment effect
  1581. gotEffect = true;
  1582. continue;
  1583. }
  1584. if(stackPos > 10)
  1585. g_logger.traceError(stdext::format("too many things, pos=%s, stackpos=%d", stdext::to_string(position), stackPos));
  1586. ThingPtr thing = getThing(msg);
  1587. g_map.addThing(thing, position, stackPos);
  1588. }
  1589. return 0;
  1590. }
  1591. Outfit ProtocolGame::getOutfit(const InputMessagePtr& msg)
  1592. {
  1593. Outfit outfit;
  1594. int lookType;
  1595. if(g_game.getFeature(Otc::GameLooktypeU16))
  1596. lookType = msg->getU16();
  1597. else
  1598. lookType = msg->getU8();
  1599. if(lookType != 0) {
  1600. outfit.setCategory(ThingCategoryCreature);
  1601. int head = msg->getU8();
  1602. int body = msg->getU8();
  1603. int legs = msg->getU8();
  1604. int feet = msg->getU8();
  1605. int addons = 0;
  1606. if(g_game.getFeature(Otc::GamePlayerAddons))
  1607. addons = msg->getU8();
  1608. if(!g_things.isValidDatId(lookType, ThingCategoryCreature)) {
  1609. g_logger.traceError(stdext::format("invalid outfit looktype %d", lookType));
  1610. lookType = 0;
  1611. }
  1612. outfit.setId(lookType);
  1613. outfit.setHead(head);
  1614. outfit.setBody(body);
  1615. outfit.setLegs(legs);
  1616. outfit.setFeet(feet);
  1617. outfit.setAddons(addons);
  1618. }
  1619. else {
  1620. int lookTypeEx = msg->getU16();
  1621. if(lookTypeEx == 0) {
  1622. outfit.setCategory(ThingCategoryEffect);
  1623. outfit.setAuxId(13); // invisible effect id
  1624. }
  1625. else {
  1626. if(!g_things.isValidDatId(lookTypeEx, ThingCategoryItem)) {
  1627. g_logger.traceError(stdext::format("invalid outfit looktypeex %d", lookTypeEx));
  1628. lookTypeEx = 0;
  1629. }
  1630. outfit.setCategory(ThingCategoryItem);
  1631. outfit.setAuxId(lookTypeEx);
  1632. }
  1633. }
  1634. if(g_game.getFeature(Otc::GamePlayerMounts)) {
  1635. int mount = msg->getU16();
  1636. outfit.setMount(mount);
  1637. }
  1638. return outfit;
  1639. }
  1640. ThingPtr ProtocolGame::getThing(const InputMessagePtr& msg)
  1641. {
  1642. ThingPtr thing;
  1643. int id = msg->getU16();
  1644. if(id == 0)
  1645. stdext::throw_exception("invalid thing id");
  1646. else if(id == Proto::UnknownCreature || id == Proto::OutdatedCreature || id == Proto::Creature)
  1647. thing = getCreature(msg, id);
  1648. else if(id == Proto::StaticText) // otclient only
  1649. thing = getStaticText(msg, id);
  1650. else // item
  1651. thing = getItem(msg, id);
  1652. return thing;
  1653. }
  1654. ThingPtr ProtocolGame::getMappedThing(const InputMessagePtr& msg)
  1655. {
  1656. ThingPtr thing;
  1657. uint16 x = msg->getU16();
  1658. if(x != 0xffff) {
  1659. Position pos;
  1660. pos.x = x;
  1661. pos.y = msg->getU16();
  1662. pos.z = msg->getU8();
  1663. uint8 stackpos = msg->getU8();
  1664. assert(stackpos != 255);
  1665. thing = g_map.getThing(pos, stackpos);
  1666. if(!thing)
  1667. g_logger.traceError(stdext::format("no thing at pos:%s, stackpos:%d", stdext::to_string(pos), stackpos));
  1668. } else {
  1669. uint32 id = msg->getU32();
  1670. thing = g_map.getCreatureById(id);
  1671. if(!thing)
  1672. g_logger.traceError(stdext::format("no creature with id %u", id));
  1673. }
  1674. return thing;
  1675. }
  1676. CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
  1677. {
  1678. if(type == 0)
  1679. type = msg->getU16();
  1680. CreaturePtr creature;
  1681. bool known = (type != Proto::UnknownCreature);
  1682. if(type == Proto::OutdatedCreature || type == Proto::UnknownCreature) {
  1683. if(known) {
  1684. uint id = msg->getU32();
  1685. creature = g_map.getCreatureById(id);
  1686. if(!creature)
  1687. g_logger.traceError("server said that a creature is known, but it's not");
  1688. } else {
  1689. uint removeId = msg->getU32();
  1690. g_map.removeCreatureById(removeId);
  1691. uint id = msg->getU32();
  1692. int creatureType;
  1693. if(g_game.getClientVersion() >= 910)
  1694. creatureType = msg->getU8();
  1695. else {
  1696. if(id >= Proto::PlayerStartId && id < Proto::PlayerEndId)
  1697. creatureType = Proto::CreatureTypePlayer;
  1698. else if(id >= Proto::MonsterStartId && id < Proto::MonsterEndId)
  1699. creatureType = Proto::CreatureTypeMonster;
  1700. else
  1701. creatureType = Proto::CreatureTypeNpc;
  1702. }
  1703. std::string name = g_game.formatCreatureName(msg->getString());
  1704. if(id == m_localPlayer->getId())
  1705. creature = m_localPlayer;
  1706. else if(creatureType == Proto::CreatureTypePlayer) {
  1707. // fixes a bug server side bug where GameInit is not sent and local player id is unknown
  1708. if(m_localPlayer->getId() == 0 && name == m_localPlayer->getName())
  1709. creature = m_localPlayer;
  1710. else
  1711. creature = PlayerPtr(new Player);
  1712. }
  1713. else if(creatureType == Proto::CreatureTypeMonster)
  1714. creature = MonsterPtr(new Monster);
  1715. else if(creatureType == Proto::CreatureTypeNpc)
  1716. creature = NpcPtr(new Npc);
  1717. else
  1718. g_logger.traceError("creature type is invalid");
  1719. if(creature) {
  1720. creature->setId(id);
  1721. creature->setName(name);
  1722. g_map.addCreature(creature);
  1723. }
  1724. }
  1725. int healthPercent = msg->getU8();
  1726. Otc::Direction direction = (Otc::Direction)msg->getU8();
  1727. Outfit outfit = getOutfit(msg);
  1728. Light light;
  1729. light.intensity = msg->getU8();
  1730. light.color = msg->getU8();
  1731. int speed = msg->getU16();
  1732. int skull = msg->getU8();
  1733. int shield = msg->getU8();
  1734. // emblem is sent only when the creature is not known
  1735. int emblem = -1;
  1736. int icon = -1;
  1737. bool unpass = true;
  1738. uint8 mark;
  1739. if(g_game.getFeature(Otc::GameCreatureEmblems) && !known)
  1740. emblem = msg->getU8();
  1741. if(g_game.getFeature(Otc::GameThingMarks)) {
  1742. msg->getU8(); // creature type for summons
  1743. }
  1744. if(g_game.getFeature(Otc::GameCreatureIcons)) {
  1745. icon = msg->getU8();
  1746. }
  1747. if(g_game.getFeature(Otc::GameThingMarks)) {
  1748. mark = msg->getU8(); // mark
  1749. msg->getU16(); // helpers
  1750. if(creature) {
  1751. if(mark == 0xff)
  1752. creature->hideStaticSquare();
  1753. else
  1754. creature->showStaticSquare(Color::from8bit(mark));
  1755. }
  1756. }
  1757. if(g_game.getClientVersion() >= 854)
  1758. unpass = msg->getU8();
  1759. if(creature) {
  1760. creature->setHealthPercent(healthPercent);
  1761. creature->setDirection(direction);
  1762. creature->setOutfit(outfit);
  1763. creature->setSpeed(speed);
  1764. creature->setSkull(skull);
  1765. creature->setShield(shield);
  1766. creature->setPassable(!unpass);
  1767. creature->setLight(light);
  1768. if(emblem != -1)
  1769. creature->setEmblem(emblem);
  1770. if(icon != -1)
  1771. creature->setIcon(icon);
  1772. if(creature == m_localPlayer && !m_localPlayer->isKnown())
  1773. m_localPlayer->setKnown(true);
  1774. }
  1775. } else if(type == Proto::Creature) {
  1776. uint id = msg->getU32();
  1777. creature = g_map.getCreatureById(id);
  1778. if(!creature)
  1779. g_logger.traceError("invalid creature");
  1780. Otc::Direction direction = (Otc::Direction)msg->getU8();
  1781. if(creature)
  1782. creature->turn(direction);
  1783. if(g_game.getClientVersion() >= 953) {
  1784. bool unpass = msg->getU8();
  1785. if(creature)
  1786. creature->setPassable(!unpass);
  1787. }
  1788. } else {
  1789. stdext::throw_exception("invalid creature opcode");
  1790. }
  1791. return creature;
  1792. }
  1793. ItemPtr ProtocolGame::getItem(const InputMessagePtr& msg, int id)
  1794. {
  1795. if(id == 0)
  1796. id = msg->getU16();
  1797. ItemPtr item = Item::create(id);
  1798. if(item->getId() == 0)
  1799. stdext::throw_exception(stdext::format("unable to create item with invalid id %d", id));
  1800. if(g_game.getFeature(Otc::GameThingMarks)) {
  1801. msg->getU8(); // mark
  1802. }
  1803. if(item->isStackable() || item->isFluidContainer() || item->isSplash() || item->isChargeable())
  1804. item->setCountOrSubType(msg->getU8());
  1805. if(g_game.getFeature(Otc::GameItemAnimationPhase)) {
  1806. if(item->getAnimationPhases() > 1) {
  1807. // 0x00 => automatic phase
  1808. // 0xFE => random phase
  1809. // 0xFF => async phase
  1810. msg->getU8();
  1811. //item->setPhase(msg->getU8());
  1812. }
  1813. }
  1814. return item;
  1815. }
  1816. StaticTextPtr ProtocolGame::getStaticText(const InputMessagePtr& msg, int id)
  1817. {
  1818. int colorByte = msg->getU8();
  1819. Color color = Color::from8bit(colorByte);
  1820. std::string fontName = msg->getString();
  1821. std::string text = msg->getString();
  1822. StaticTextPtr staticText = StaticTextPtr(new StaticText);
  1823. staticText->setText(text);
  1824. staticText->setFont(fontName);
  1825. staticText->setColor(color);
  1826. return staticText;
  1827. }
  1828. Position ProtocolGame::getPosition(const InputMessagePtr& msg)
  1829. {
  1830. uint16 x = msg->getU16();
  1831. uint16 y = msg->getU16();
  1832. uint8 z = msg->getU8();
  1833. return Position(x, y, z);
  1834. }