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

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165
  1. /*
  2. * Copyright (c) 2010-2015 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. int deathType = Otc::DeathRegular;
  500. if(g_game.getFeature(Otc::GameDeathType))
  501. deathType = msg->getU8();
  502. if(g_game.getFeature(Otc::GamePenalityOnDeath) && deathType == Otc::DeathRegular)
  503. penality = msg->getU8();
  504. g_game.processDeath(deathType, penality);
  505. }
  506. void ProtocolGame::parseMapDescription(const InputMessagePtr& msg)
  507. {
  508. Position pos = getPosition(msg);
  509. if(!m_mapKnown)
  510. m_localPlayer->setPosition(pos);
  511. g_map.setCentralPosition(pos);
  512. AwareRange range = g_map.getAwareRange();
  513. setMapDescription(msg, pos.x - range.left, pos.y - range.top, pos.z, range.horizontal(), range.vertical());
  514. if(!m_mapKnown) {
  515. g_dispatcher.addEvent([] { g_lua.callGlobalField("g_game", "onMapKnown"); });
  516. m_mapKnown = true;
  517. }
  518. g_dispatcher.addEvent([] { g_lua.callGlobalField("g_game", "onMapDescription"); });
  519. }
  520. void ProtocolGame::parseMapMoveNorth(const InputMessagePtr& msg)
  521. {
  522. Position pos;
  523. if(g_game.getFeature(Otc::GameMapMovePosition))
  524. pos = getPosition(msg);
  525. else
  526. pos = g_map.getCentralPosition();
  527. pos.y--;
  528. AwareRange range = g_map.getAwareRange();
  529. setMapDescription(msg, pos.x - range.left, pos.y - range.top, pos.z, range.horizontal(), 1);
  530. g_map.setCentralPosition(pos);
  531. }
  532. void ProtocolGame::parseMapMoveEast(const InputMessagePtr& msg)
  533. {
  534. Position pos;
  535. if(g_game.getFeature(Otc::GameMapMovePosition))
  536. pos = getPosition(msg);
  537. else
  538. pos = g_map.getCentralPosition();
  539. pos.x++;
  540. AwareRange range = g_map.getAwareRange();
  541. setMapDescription(msg, pos.x + range.right, pos.y - range.top, pos.z, 1, range.vertical());
  542. g_map.setCentralPosition(pos);
  543. }
  544. void ProtocolGame::parseMapMoveSouth(const InputMessagePtr& msg)
  545. {
  546. Position pos;
  547. if(g_game.getFeature(Otc::GameMapMovePosition))
  548. pos = getPosition(msg);
  549. else
  550. pos = g_map.getCentralPosition();
  551. pos.y++;
  552. AwareRange range = g_map.getAwareRange();
  553. setMapDescription(msg, pos.x - range.left, pos.y + range.bottom, pos.z, range.horizontal(), 1);
  554. g_map.setCentralPosition(pos);
  555. }
  556. void ProtocolGame::parseMapMoveWest(const InputMessagePtr& msg)
  557. {
  558. Position pos;
  559. if(g_game.getFeature(Otc::GameMapMovePosition))
  560. pos = getPosition(msg);
  561. else
  562. pos = g_map.getCentralPosition();
  563. pos.x--;
  564. AwareRange range = g_map.getAwareRange();
  565. setMapDescription(msg, pos.x - range.left, pos.y - range.top, pos.z, 1, range.vertical());
  566. g_map.setCentralPosition(pos);
  567. }
  568. void ProtocolGame::parseUpdateTile(const InputMessagePtr& msg)
  569. {
  570. Position tilePos = getPosition(msg);
  571. setTileDescription(msg, tilePos);
  572. }
  573. void ProtocolGame::parseTileAddThing(const InputMessagePtr& msg)
  574. {
  575. Position pos = getPosition(msg);
  576. int stackPos = -1;
  577. if(g_game.getClientVersion() >= 841)
  578. stackPos = msg->getU8();
  579. ThingPtr thing = getThing(msg);
  580. g_map.addThing(thing, pos, stackPos);
  581. }
  582. void ProtocolGame::parseTileTransformThing(const InputMessagePtr& msg)
  583. {
  584. ThingPtr thing = getMappedThing(msg);
  585. ThingPtr newThing = getThing(msg);
  586. if(!thing) {
  587. g_logger.traceError("no thing");
  588. return;
  589. }
  590. Position pos = thing->getPosition();
  591. int stackpos = thing->getStackPos();
  592. if(!g_map.removeThing(thing)) {
  593. g_logger.traceError("unable to remove thing");
  594. return;
  595. }
  596. g_map.addThing(newThing, pos, stackpos);
  597. }
  598. void ProtocolGame::parseTileRemoveThing(const InputMessagePtr& msg)
  599. {
  600. ThingPtr thing = getMappedThing(msg);
  601. if(!thing) {
  602. g_logger.traceError("no thing");
  603. return;
  604. }
  605. if(!g_map.removeThing(thing))
  606. g_logger.traceError("unable to remove thing");
  607. }
  608. void ProtocolGame::parseCreatureMove(const InputMessagePtr& msg)
  609. {
  610. ThingPtr thing = getMappedThing(msg);
  611. Position newPos = getPosition(msg);
  612. if(!thing || !thing->isCreature()) {
  613. g_logger.traceError("no creature found to move");
  614. return;
  615. }
  616. if(!g_map.removeThing(thing)) {
  617. g_logger.traceError("unable to remove creature");
  618. return;
  619. }
  620. CreaturePtr creature = thing->static_self_cast<Creature>();
  621. creature->allowAppearWalk();
  622. g_map.addThing(thing, newPos, -1);
  623. }
  624. void ProtocolGame::parseOpenContainer(const InputMessagePtr& msg)
  625. {
  626. int containerId = msg->getU8();
  627. ItemPtr containerItem = getItem(msg);
  628. std::string name = msg->getString();
  629. int capacity = msg->getU8();
  630. bool hasParent = (msg->getU8() != 0);
  631. bool isUnlocked = true;
  632. bool hasPages = false;
  633. int containerSize = 0;
  634. int firstIndex = 0;
  635. if(g_game.getFeature(Otc::GameContainerPagination)) {
  636. isUnlocked = (msg->getU8() != 0); // drag and drop
  637. hasPages = (msg->getU8() != 0); // pagination
  638. containerSize = msg->getU16(); // container size
  639. firstIndex = msg->getU16(); // first index
  640. }
  641. int itemCount = msg->getU8();
  642. std::vector<ItemPtr> items(itemCount);
  643. for(int i = 0; i < itemCount; i++)
  644. items[i] = getItem(msg);
  645. g_game.processOpenContainer(containerId, containerItem, name, capacity, hasParent, items, isUnlocked, hasPages, containerSize, firstIndex);
  646. }
  647. void ProtocolGame::parseCloseContainer(const InputMessagePtr& msg)
  648. {
  649. int containerId = msg->getU8();
  650. g_game.processCloseContainer(containerId);
  651. }
  652. void ProtocolGame::parseContainerAddItem(const InputMessagePtr& msg)
  653. {
  654. int containerId = msg->getU8();
  655. int slot = 0;
  656. if(g_game.getFeature(Otc::GameContainerPagination)) {
  657. slot = msg->getU16(); // slot
  658. }
  659. ItemPtr item = getItem(msg);
  660. g_game.processContainerAddItem(containerId, item, slot);
  661. }
  662. void ProtocolGame::parseContainerUpdateItem(const InputMessagePtr& msg)
  663. {
  664. int containerId = msg->getU8();
  665. int slot;
  666. if(g_game.getFeature(Otc::GameContainerPagination)) {
  667. slot = msg->getU16();
  668. } else {
  669. slot = msg->getU8();
  670. }
  671. ItemPtr item = getItem(msg);
  672. g_game.processContainerUpdateItem(containerId, slot, item);
  673. }
  674. void ProtocolGame::parseContainerRemoveItem(const InputMessagePtr& msg)
  675. {
  676. int containerId = msg->getU8();
  677. int slot;
  678. ItemPtr lastItem;
  679. if(g_game.getFeature(Otc::GameContainerPagination)) {
  680. slot = msg->getU16();
  681. int itemId = msg->getU16();
  682. if(itemId != 0)
  683. lastItem = getItem(msg, itemId);
  684. } else {
  685. slot = msg->getU8();
  686. }
  687. g_game.processContainerRemoveItem(containerId, slot, lastItem);
  688. }
  689. void ProtocolGame::parseAddInventoryItem(const InputMessagePtr& msg)
  690. {
  691. int slot = msg->getU8();
  692. ItemPtr item = getItem(msg);
  693. g_game.processInventoryChange(slot, item);
  694. }
  695. void ProtocolGame::parseRemoveInventoryItem(const InputMessagePtr& msg)
  696. {
  697. int slot = msg->getU8();
  698. g_game.processInventoryChange(slot, ItemPtr());
  699. }
  700. void ProtocolGame::parseOpenNpcTrade(const InputMessagePtr& msg)
  701. {
  702. std::vector<std::tuple<ItemPtr, std::string, int, int, int>> items;
  703. std::string npcName;
  704. if(g_game.getFeature(Otc::GameNameOnNpcTrade))
  705. npcName = msg->getString();
  706. int listCount;
  707. if(g_game.getClientVersion() >= 900)
  708. listCount = msg->getU16();
  709. else
  710. listCount = msg->getU8();
  711. for(int i = 0; i < listCount; ++i) {
  712. uint16 itemId = msg->getU16();
  713. uint8 count = msg->getU8();
  714. ItemPtr item = Item::create(itemId);
  715. item->setCountOrSubType(count);
  716. std::string name = msg->getString();
  717. int weight = msg->getU32();
  718. int buyPrice = msg->getU32();
  719. int sellPrice = msg->getU32();
  720. items.push_back(std::make_tuple(item, name, weight, buyPrice, sellPrice));
  721. }
  722. g_game.processOpenNpcTrade(items);
  723. }
  724. void ProtocolGame::parsePlayerGoods(const InputMessagePtr& msg)
  725. {
  726. std::vector<std::tuple<ItemPtr, int>> goods;
  727. int money;
  728. if(g_game.getClientVersion() >= 973)
  729. money = msg->getU64();
  730. else
  731. money = msg->getU32();
  732. int size = msg->getU8();
  733. for(int i = 0; i < size; i++) {
  734. int itemId = msg->getU16();
  735. int amount;
  736. if(g_game.getFeature(Otc::GameDoubleShopSellAmount))
  737. amount = msg->getU16();
  738. else
  739. amount = msg->getU8();
  740. goods.push_back(std::make_tuple(Item::create(itemId), amount));
  741. }
  742. g_game.processPlayerGoods(money, goods);
  743. }
  744. void ProtocolGame::parseCloseNpcTrade(const InputMessagePtr&)
  745. {
  746. g_game.processCloseNpcTrade();
  747. }
  748. void ProtocolGame::parseOwnTrade(const InputMessagePtr& msg)
  749. {
  750. std::string name = g_game.formatCreatureName(msg->getString());
  751. int count = msg->getU8();
  752. std::vector<ItemPtr> items(count);
  753. for(int i = 0; i < count; i++)
  754. items[i] = getItem(msg);
  755. g_game.processOwnTrade(name, items);
  756. }
  757. void ProtocolGame::parseCounterTrade(const InputMessagePtr& msg)
  758. {
  759. std::string name = g_game.formatCreatureName(msg->getString());
  760. int count = msg->getU8();
  761. std::vector<ItemPtr> items(count);
  762. for(int i = 0; i < count; i++)
  763. items[i] = getItem(msg);
  764. g_game.processCounterTrade(name, items);
  765. }
  766. void ProtocolGame::parseCloseTrade(const InputMessagePtr&)
  767. {
  768. g_game.processCloseTrade();
  769. }
  770. void ProtocolGame::parseWorldLight(const InputMessagePtr& msg)
  771. {
  772. Light light;
  773. light.intensity = msg->getU8();
  774. light.color = msg->getU8();
  775. g_map.setLight(light);
  776. }
  777. void ProtocolGame::parseMagicEffect(const InputMessagePtr& msg)
  778. {
  779. Position pos = getPosition(msg);
  780. int effectId;
  781. if(g_game.getFeature(Otc::GameMagicEffectU16))
  782. effectId = msg->getU16();
  783. else
  784. effectId = msg->getU8();
  785. if(!g_things.isValidDatId(effectId, ThingCategoryEffect)) {
  786. g_logger.traceError(stdext::format("invalid effect id %d", effectId));
  787. return;
  788. }
  789. EffectPtr effect = EffectPtr(new Effect());
  790. effect->setId(effectId);
  791. g_map.addThing(effect, pos);
  792. }
  793. void ProtocolGame::parseAnimatedText(const InputMessagePtr& msg)
  794. {
  795. Position position = getPosition(msg);
  796. int color = msg->getU8();
  797. std::string text = msg->getString();
  798. AnimatedTextPtr animatedText = AnimatedTextPtr(new AnimatedText);
  799. animatedText->setColor(color);
  800. animatedText->setText(text);
  801. g_map.addThing(animatedText, position);
  802. }
  803. void ProtocolGame::parseDistanceMissile(const InputMessagePtr& msg)
  804. {
  805. Position fromPos = getPosition(msg);
  806. Position toPos = getPosition(msg);
  807. int shotId = msg->getU8();
  808. if(!g_things.isValidDatId(shotId, ThingCategoryMissile)) {
  809. g_logger.traceError(stdext::format("invalid missile id %d", shotId));
  810. return;
  811. }
  812. MissilePtr missile = MissilePtr(new Missile());
  813. missile->setId(shotId);
  814. missile->setPath(fromPos, toPos);
  815. g_map.addThing(missile, fromPos);
  816. }
  817. void ProtocolGame::parseCreatureMark(const InputMessagePtr& msg)
  818. {
  819. uint id = msg->getU32();
  820. int color = msg->getU8();
  821. CreaturePtr creature = g_map.getCreatureById(id);
  822. if(creature)
  823. creature->addTimedSquare(color);
  824. else
  825. g_logger.traceError("could not get creature");
  826. }
  827. void ProtocolGame::parseTrappers(const InputMessagePtr& msg)
  828. {
  829. int numTrappers = msg->getU8();
  830. if(numTrappers > 8)
  831. g_logger.traceError("too many trappers");
  832. for(int i=0;i<numTrappers;++i) {
  833. uint id = msg->getU32();
  834. CreaturePtr creature = g_map.getCreatureById(id);
  835. if(creature) {
  836. //TODO: set creature as trapper
  837. } else
  838. g_logger.traceError("could not get creature");
  839. }
  840. }
  841. void ProtocolGame::parseCreatureHealth(const InputMessagePtr& msg)
  842. {
  843. uint id = msg->getU32();
  844. int healthPercent = msg->getU8();
  845. CreaturePtr creature = g_map.getCreatureById(id);
  846. if(creature)
  847. creature->setHealthPercent(healthPercent);
  848. // some servers has a bug in get spectators and sends unknown creatures updates
  849. // so this code is disabled
  850. /*
  851. else
  852. g_logger.traceError("could not get creature");
  853. */
  854. }
  855. void ProtocolGame::parseCreatureLight(const InputMessagePtr& msg)
  856. {
  857. uint id = msg->getU32();
  858. Light light;
  859. light.intensity = msg->getU8();
  860. light.color = msg->getU8();
  861. CreaturePtr creature = g_map.getCreatureById(id);
  862. if(creature)
  863. creature->setLight(light);
  864. else
  865. g_logger.traceError("could not get creature");
  866. }
  867. void ProtocolGame::parseCreatureOutfit(const InputMessagePtr& msg)
  868. {
  869. uint id = msg->getU32();
  870. Outfit outfit = getOutfit(msg);
  871. CreaturePtr creature = g_map.getCreatureById(id);
  872. if(creature)
  873. creature->setOutfit(outfit);
  874. else
  875. g_logger.traceError("could not get creature");
  876. }
  877. void ProtocolGame::parseCreatureSpeed(const InputMessagePtr& msg)
  878. {
  879. uint id = msg->getU32();
  880. int baseSpeed = -1;
  881. if(g_game.getClientVersion() >= 1059)
  882. baseSpeed = msg->getU16();
  883. int speed = msg->getU16();
  884. CreaturePtr creature = g_map.getCreatureById(id);
  885. if(creature) {
  886. creature->setSpeed(speed);
  887. if(baseSpeed != -1)
  888. creature->setBaseSpeed(baseSpeed);
  889. }
  890. // some servers has a bug in get spectators and sends unknown creatures updates
  891. // so this code is disabled
  892. /*
  893. else
  894. g_logger.traceError("could not get creature");
  895. */
  896. }
  897. void ProtocolGame::parseCreatureSkulls(const InputMessagePtr& msg)
  898. {
  899. uint id = msg->getU32();
  900. int skull = msg->getU8();
  901. CreaturePtr creature = g_map.getCreatureById(id);
  902. if(creature)
  903. creature->setSkull(skull);
  904. else
  905. g_logger.traceError("could not get creature");
  906. }
  907. void ProtocolGame::parseCreatureShields(const InputMessagePtr& msg)
  908. {
  909. uint id = msg->getU32();
  910. int shield = msg->getU8();
  911. CreaturePtr creature = g_map.getCreatureById(id);
  912. if(creature)
  913. creature->setShield(shield);
  914. else
  915. g_logger.traceError("could not get creature");
  916. }
  917. void ProtocolGame::parseCreatureUnpass(const InputMessagePtr& msg)
  918. {
  919. uint id = msg->getU32();
  920. bool unpass = msg->getU8();
  921. CreaturePtr creature = g_map.getCreatureById(id);
  922. if(creature)
  923. creature->setPassable(!unpass);
  924. else
  925. g_logger.traceError("could not get creature");
  926. }
  927. void ProtocolGame::parseEditText(const InputMessagePtr& msg)
  928. {
  929. uint id = msg->getU32();
  930. int itemId;
  931. if(g_game.getClientVersion() >= 1010) {
  932. // TODO: processEditText with ItemPtr as parameter
  933. ItemPtr item = getItem(msg);
  934. itemId = item->getId();
  935. } else
  936. itemId = msg->getU16();
  937. int maxLength = msg->getU16();
  938. std::string text = msg->getString();
  939. std::string writer = msg->getString();
  940. std::string date = "";
  941. if(g_game.getFeature(Otc::GameWritableDate))
  942. date = msg->getString();
  943. g_game.processEditText(id, itemId, maxLength, text, writer, date);
  944. }
  945. void ProtocolGame::parseEditList(const InputMessagePtr& msg)
  946. {
  947. int doorId = msg->getU8();
  948. uint id = msg->getU32();
  949. const std::string& text = msg->getString();
  950. g_game.processEditList(id, doorId, text);
  951. }
  952. void ProtocolGame::parsePremiumTrigger(const InputMessagePtr& msg)
  953. {
  954. int triggerCount = msg->getU8();
  955. std::vector<int> triggers;
  956. for(int i=0;i<triggerCount;++i) {
  957. triggers.push_back(msg->getU8());
  958. }
  959. bool something = msg->getU8() == 1;
  960. }
  961. void ProtocolGame::parsePlayerInfo(const InputMessagePtr& msg)
  962. {
  963. bool premium = msg->getU8(); // premium
  964. int vocation = msg->getU8(); // vocation
  965. if(g_game.getFeature(Otc::GamePremiumExpiration))
  966. int premiumEx = msg->getU32(); // premium expiration used for premium advertisement
  967. int spellCount = msg->getU16();
  968. std::vector<int> spells;
  969. for(int i=0;i<spellCount;++i)
  970. spells.push_back(msg->getU8()); // spell id
  971. m_localPlayer->setPremium(premium);
  972. m_localPlayer->setVocation(vocation);
  973. m_localPlayer->setSpells(spells);
  974. }
  975. void ProtocolGame::parsePlayerStats(const InputMessagePtr& msg)
  976. {
  977. double health;
  978. double maxHealth;
  979. if(g_game.getFeature(Otc::GameDoubleHealth)) {
  980. health = msg->getU32();
  981. maxHealth = msg->getU32();
  982. } else {
  983. health = msg->getU16();
  984. maxHealth = msg->getU16();
  985. }
  986. double freeCapacity;
  987. if(g_game.getFeature(Otc::GameDoubleFreeCapacity))
  988. freeCapacity = msg->getU32() / 100.0;
  989. else
  990. freeCapacity = msg->getU16() / 100.0;
  991. double totalCapacity = 0;
  992. if(g_game.getFeature(Otc::GameTotalCapacity))
  993. totalCapacity = msg->getU32() / 100.0;
  994. double experience;
  995. if(g_game.getFeature(Otc::GameDoubleExperience))
  996. experience = msg->getU64();
  997. else
  998. experience = msg->getU32();
  999. double level = msg->getU16();
  1000. double levelPercent = msg->getU8();
  1001. if(g_game.getFeature(Otc::GameExperienceBonus))
  1002. double experienceBonus = msg->getDouble();
  1003. double mana;
  1004. double maxMana;
  1005. if(g_game.getFeature(Otc::GameDoubleHealth)) {
  1006. mana = msg->getU32();
  1007. maxMana = msg->getU32();
  1008. } else {
  1009. mana = msg->getU16();
  1010. maxMana = msg->getU16();
  1011. }
  1012. double magicLevel = msg->getU8();
  1013. double baseMagicLevel;
  1014. if(g_game.getFeature(Otc::GameSkillsBase))
  1015. baseMagicLevel = msg->getU8();
  1016. else
  1017. baseMagicLevel = magicLevel;
  1018. double magicLevelPercent = msg->getU8();
  1019. double soul = msg->getU8();
  1020. double stamina = 0;
  1021. if(g_game.getFeature(Otc::GamePlayerStamina))
  1022. stamina = msg->getU16();
  1023. double baseSpeed = 0;
  1024. if(g_game.getFeature(Otc::GameSkillsBase))
  1025. baseSpeed = msg->getU16();
  1026. double regeneration = 0;
  1027. if(g_game.getFeature(Otc::GamePlayerRegenerationTime))
  1028. regeneration = msg->getU16();
  1029. double training = 0;
  1030. if(g_game.getFeature(Otc::GameOfflineTrainingTime))
  1031. training = msg->getU16();
  1032. m_localPlayer->setHealth(health, maxHealth);
  1033. m_localPlayer->setFreeCapacity(freeCapacity);
  1034. m_localPlayer->setTotalCapacity(totalCapacity);
  1035. m_localPlayer->setExperience(experience);
  1036. m_localPlayer->setLevel(level, levelPercent);
  1037. m_localPlayer->setMana(mana, maxMana);
  1038. m_localPlayer->setMagicLevel(magicLevel, magicLevelPercent);
  1039. m_localPlayer->setBaseMagicLevel(baseMagicLevel);
  1040. m_localPlayer->setStamina(stamina);
  1041. m_localPlayer->setSoul(soul);
  1042. m_localPlayer->setBaseSpeed(baseSpeed);
  1043. m_localPlayer->setRegenerationTime(regeneration);
  1044. m_localPlayer->setOfflineTrainingTime(training);
  1045. }
  1046. void ProtocolGame::parsePlayerSkills(const InputMessagePtr& msg)
  1047. {
  1048. for(int skill = 0; skill < Otc::LastSkill; skill++) {
  1049. int level;
  1050. if(g_game.getFeature(Otc::GameDoubleSkills))
  1051. level = msg->getU16();
  1052. else
  1053. level = msg->getU8();
  1054. int baseLevel;
  1055. if(g_game.getFeature(Otc::GameSkillsBase))
  1056. if(g_game.getFeature(Otc::GameBaseSkillU16))
  1057. baseLevel = msg->getU16();
  1058. else
  1059. baseLevel = msg->getU8();
  1060. else
  1061. baseLevel = level;
  1062. int levelPercent = msg->getU8();
  1063. m_localPlayer->setSkill((Otc::Skill)skill, level, levelPercent);
  1064. m_localPlayer->setBaseSkill((Otc::Skill)skill, baseLevel);
  1065. }
  1066. }
  1067. void ProtocolGame::parsePlayerState(const InputMessagePtr& msg)
  1068. {
  1069. int states;
  1070. if(g_game.getFeature(Otc::GamePlayerStateU16))
  1071. states = msg->getU16();
  1072. else
  1073. states = msg->getU8();
  1074. m_localPlayer->setStates(states);
  1075. }
  1076. void ProtocolGame::parsePlayerCancelAttack(const InputMessagePtr& msg)
  1077. {
  1078. uint seq = 0;
  1079. if(g_game.getFeature(Otc::GameAttackSeq))
  1080. seq = msg->getU32();
  1081. g_game.processAttackCancel(seq);
  1082. }
  1083. void ProtocolGame::parsePlayerModes(const InputMessagePtr& msg)
  1084. {
  1085. int fightMode = msg->getU8();
  1086. int chaseMode = msg->getU8();
  1087. bool safeMode = msg->getU8();
  1088. int pvpMode = 0;
  1089. if(g_game.getFeature(Otc::GamePVPMode))
  1090. pvpMode = msg->getU8();
  1091. g_game.processPlayerModes((Otc::FightModes)fightMode, (Otc::ChaseModes)chaseMode, safeMode, (Otc::PVPModes)pvpMode);
  1092. }
  1093. void ProtocolGame::parseSpellCooldown(const InputMessagePtr& msg)
  1094. {
  1095. int spellId = msg->getU8();
  1096. int delay = msg->getU32();
  1097. g_lua.callGlobalField("g_game", "onSpellCooldown", spellId, delay);
  1098. }
  1099. void ProtocolGame::parseSpellGroupCooldown(const InputMessagePtr& msg)
  1100. {
  1101. int groupId = msg->getU8();
  1102. int delay = msg->getU32();
  1103. g_lua.callGlobalField("g_game", "onSpellGroupCooldown", groupId, delay);
  1104. }
  1105. void ProtocolGame::parseMultiUseCooldown(const InputMessagePtr& msg)
  1106. {
  1107. int delay = msg->getU32();
  1108. g_lua.callGlobalField("g_game", "onMultiUseCooldown", delay);
  1109. }
  1110. void ProtocolGame::parseTalk(const InputMessagePtr& msg)
  1111. {
  1112. if(g_game.getFeature(Otc::GameMessageStatements))
  1113. msg->getU32(); // channel statement guid
  1114. std::string name = g_game.formatCreatureName(msg->getString());
  1115. int level = 0;
  1116. if(g_game.getFeature(Otc::GameMessageLevel))
  1117. level = msg->getU16();
  1118. Otc::MessageMode mode = Proto::translateMessageModeFromServer(msg->getU8());
  1119. int channelId = 0;
  1120. Position pos;
  1121. switch(mode) {
  1122. case Otc::MessageSay:
  1123. case Otc::MessageWhisper:
  1124. case Otc::MessageYell:
  1125. case Otc::MessageMonsterSay:
  1126. case Otc::MessageMonsterYell:
  1127. case Otc::MessageNpcTo:
  1128. case Otc::MessageNpcFrom:
  1129. case Otc::MessageBarkLow:
  1130. case Otc::MessageBarkLoud:
  1131. case Otc::MessageSpell:
  1132. pos = getPosition(msg);
  1133. break;
  1134. case Otc::MessageChannel:
  1135. case Otc::MessageChannelManagement:
  1136. case Otc::MessageChannelHighlight:
  1137. case Otc::MessageGamemasterChannel:
  1138. channelId = msg->getU16();
  1139. break;
  1140. case Otc::MessagePrivateFrom:
  1141. case Otc::MessageGamemasterBroadcast:
  1142. case Otc::MessageGamemasterPrivateFrom:
  1143. case Otc::MessageRVRAnswer:
  1144. case Otc::MessageRVRContinue:
  1145. break;
  1146. case Otc::MessageRVRChannel:
  1147. msg->getU32();
  1148. break;
  1149. default:
  1150. stdext::throw_exception(stdext::format("unknown message mode %d", mode));
  1151. break;
  1152. }
  1153. std::string text = msg->getString();
  1154. g_game.processTalk(name, level, mode, text, channelId, pos);
  1155. }
  1156. void ProtocolGame::parseChannelList(const InputMessagePtr& msg)
  1157. {
  1158. int count = msg->getU8();
  1159. std::vector<std::tuple<int, std::string> > channelList;
  1160. for(int i = 0; i < count; i++) {
  1161. int id = msg->getU16();
  1162. std::string name = msg->getString();
  1163. channelList.push_back(std::make_tuple(id, name));
  1164. }
  1165. g_game.processChannelList(channelList);
  1166. }
  1167. void ProtocolGame::parseOpenChannel(const InputMessagePtr& msg)
  1168. {
  1169. int channelId = msg->getU16();
  1170. std::string name = msg->getString();
  1171. if(g_game.getFeature(Otc::GameChannelPlayerList)) {
  1172. int joinedPlayers = msg->getU16();
  1173. for(int i=0;i<joinedPlayers;++i)
  1174. g_game.formatCreatureName(msg->getString()); // player name
  1175. int invitedPlayers = msg->getU16();
  1176. for(int i=0;i<invitedPlayers;++i)
  1177. g_game.formatCreatureName(msg->getString()); // player name
  1178. }
  1179. g_game.processOpenChannel(channelId, name);
  1180. }
  1181. void ProtocolGame::parseOpenPrivateChannel(const InputMessagePtr& msg)
  1182. {
  1183. std::string name = g_game.formatCreatureName(msg->getString());
  1184. g_game.processOpenPrivateChannel(name);
  1185. }
  1186. void ProtocolGame::parseOpenOwnPrivateChannel(const InputMessagePtr& msg)
  1187. {
  1188. int channelId = msg->getU16();
  1189. std::string name = msg->getString();
  1190. g_game.processOpenOwnPrivateChannel(channelId, name);
  1191. }
  1192. void ProtocolGame::parseCloseChannel(const InputMessagePtr& msg)
  1193. {
  1194. int channelId = msg->getU16();
  1195. g_game.processCloseChannel(channelId);
  1196. }
  1197. void ProtocolGame::parseRuleViolationChannel(const InputMessagePtr& msg)
  1198. {
  1199. int channelId = msg->getU16();
  1200. g_game.processRuleViolationChannel(channelId);
  1201. }
  1202. void ProtocolGame::parseRuleViolationRemove(const InputMessagePtr& msg)
  1203. {
  1204. std::string name = msg->getString();
  1205. g_game.processRuleViolationRemove(name);
  1206. }
  1207. void ProtocolGame::parseRuleViolationCancel(const InputMessagePtr& msg)
  1208. {
  1209. std::string name = msg->getString();
  1210. g_game.processRuleViolationCancel(name);
  1211. }
  1212. void ProtocolGame::parseRuleViolationLock(const InputMessagePtr& msg)
  1213. {
  1214. g_game.processRuleViolationLock();
  1215. }
  1216. void ProtocolGame::parseTextMessage(const InputMessagePtr& msg)
  1217. {
  1218. int code = msg->getU8();
  1219. Otc::MessageMode mode = Proto::translateMessageModeFromServer(code);
  1220. std::string text;
  1221. switch(mode) {
  1222. case Otc::MessageChannelManagement: {
  1223. int channel = msg->getU16();
  1224. text = msg->getString();
  1225. break;
  1226. }
  1227. case Otc::MessageDamageDealed:
  1228. case Otc::MessageDamageReceived:
  1229. case Otc::MessageDamageOthers: {
  1230. Position pos = getPosition(msg);
  1231. uint value[2];
  1232. int color[2];
  1233. // physical damage
  1234. value[0] = msg->getU32();
  1235. color[0] = msg->getU8();
  1236. // magic damage
  1237. value[1] = msg->getU32();
  1238. color[1] = msg->getU8();
  1239. text = msg->getString();
  1240. for(int i=0;i<2;++i) {
  1241. if(value[i] == 0)
  1242. continue;
  1243. AnimatedTextPtr animatedText = AnimatedTextPtr(new AnimatedText);
  1244. animatedText->setColor(color[i]);
  1245. animatedText->setText(stdext::to_string(value[i]));
  1246. g_map.addThing(animatedText, pos);
  1247. }
  1248. break;
  1249. }
  1250. case Otc::MessageHeal:
  1251. case Otc::MessageExp:
  1252. case Otc::MessageHealOthers:
  1253. case Otc::MessageExpOthers: {
  1254. Position pos = getPosition(msg);
  1255. uint value = msg->getU32();
  1256. int color = msg->getU8();
  1257. text = msg->getString();
  1258. AnimatedTextPtr animatedText = AnimatedTextPtr(new AnimatedText);
  1259. animatedText->setColor(color);
  1260. animatedText->setText(stdext::to_string(value));
  1261. g_map.addThing(animatedText, pos);
  1262. break;
  1263. }
  1264. case Otc::MessageInvalid:
  1265. stdext::throw_exception(stdext::format("unknown message mode %d", mode));
  1266. break;
  1267. default:
  1268. text = msg->getString();
  1269. break;
  1270. }
  1271. g_game.processTextMessage(mode, text);
  1272. }
  1273. void ProtocolGame::parseCancelWalk(const InputMessagePtr& msg)
  1274. {
  1275. Otc::Direction direction = (Otc::Direction)msg->getU8();
  1276. g_game.processWalkCancel(direction);
  1277. }
  1278. void ProtocolGame::parseWalkWait(const InputMessagePtr& msg)
  1279. {
  1280. int millis = msg->getU16();
  1281. m_localPlayer->lockWalk(millis);
  1282. }
  1283. void ProtocolGame::parseFloorChangeUp(const InputMessagePtr& msg)
  1284. {
  1285. Position pos;
  1286. if(g_game.getFeature(Otc::GameMapMovePosition))
  1287. pos = getPosition(msg);
  1288. else
  1289. pos = g_map.getCentralPosition();
  1290. AwareRange range = g_map.getAwareRange();
  1291. pos.z--;
  1292. int skip = 0;
  1293. if(pos.z == Otc::SEA_FLOOR)
  1294. for(int i = Otc::SEA_FLOOR - Otc::AWARE_UNDEGROUND_FLOOR_RANGE; i >= 0; i--)
  1295. skip = setFloorDescription(msg, pos.x - range.left, pos.y - range.top, i, range.horizontal(), range.vertical(), 8 - i, skip);
  1296. else if(pos.z > Otc::SEA_FLOOR)
  1297. skip = setFloorDescription(msg, pos.x - range.left, pos.y - range.top, pos.z - Otc::AWARE_UNDEGROUND_FLOOR_RANGE, range.horizontal(), range.vertical(), 3, skip);
  1298. pos.x++;
  1299. pos.y++;
  1300. g_map.setCentralPosition(pos);
  1301. }
  1302. void ProtocolGame::parseFloorChangeDown(const InputMessagePtr& msg)
  1303. {
  1304. Position pos;
  1305. if(g_game.getFeature(Otc::GameMapMovePosition))
  1306. pos = getPosition(msg);
  1307. else
  1308. pos = g_map.getCentralPosition();
  1309. AwareRange range = g_map.getAwareRange();
  1310. pos.z++;
  1311. int skip = 0;
  1312. if(pos.z == Otc::UNDERGROUND_FLOOR) {
  1313. int j, i;
  1314. for(i = pos.z, j = -1; i <= pos.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE; ++i, --j)
  1315. skip = setFloorDescription(msg, pos.x - range.left, pos.y - range.top, i, range.horizontal(), range.vertical(), j, skip);
  1316. }
  1317. else if(pos.z > Otc::UNDERGROUND_FLOOR && pos.z < Otc::MAX_Z-1)
  1318. skip = setFloorDescription(msg, pos.x - range.left, pos.y - range.top, pos.z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE, range.horizontal(), range.vertical(), -3, skip);
  1319. pos.x--;
  1320. pos.y--;
  1321. g_map.setCentralPosition(pos);
  1322. }
  1323. void ProtocolGame::parseOpenOutfitWindow(const InputMessagePtr& msg)
  1324. {
  1325. Outfit currentOutfit = getOutfit(msg);
  1326. std::vector<std::tuple<int, std::string, int> > outfitList;
  1327. if(g_game.getFeature(Otc::GameNewOutfitProtocol)) {
  1328. int outfitCount = msg->getU8();
  1329. for(int i = 0; i < outfitCount; i++) {
  1330. int outfitId = msg->getU16();
  1331. std::string outfitName = msg->getString();
  1332. int outfitAddons = msg->getU8();
  1333. outfitList.push_back(std::make_tuple(outfitId, outfitName, outfitAddons));
  1334. }
  1335. } else {
  1336. int outfitStart, outfitEnd;
  1337. if(g_game.getFeature(Otc::GameLooktypeU16)) {
  1338. outfitStart = msg->getU16();
  1339. outfitEnd = msg->getU16();
  1340. } else {
  1341. outfitStart = msg->getU8();
  1342. outfitEnd = msg->getU8();
  1343. }
  1344. for(int i = outfitStart; i <= outfitEnd; i++)
  1345. outfitList.push_back(std::make_tuple(i, "", 0));
  1346. }
  1347. std::vector<std::tuple<int, std::string> > mountList;
  1348. if(g_game.getFeature(Otc::GamePlayerMounts)) {
  1349. int mountCount = msg->getU8();
  1350. for(int i = 0; i < mountCount; ++i) {
  1351. int mountId = msg->getU16(); // mount type
  1352. std::string mountName = msg->getString(); // mount name
  1353. mountList.push_back(std::make_tuple(mountId, mountName));
  1354. }
  1355. }
  1356. g_game.processOpenOutfitWindow(currentOutfit, outfitList, mountList);
  1357. }
  1358. void ProtocolGame::parseVipAdd(const InputMessagePtr& msg)
  1359. {
  1360. uint id, iconId = 0, status;
  1361. std::string name, desc = "";
  1362. bool notifyLogin = false;
  1363. id = msg->getU32();
  1364. name = g_game.formatCreatureName(msg->getString());
  1365. if(g_game.getFeature(Otc::GameAdditionalVipInfo)) {
  1366. desc = msg->getString();
  1367. iconId = msg->getU32();
  1368. notifyLogin = msg->getU8();
  1369. }
  1370. status = msg->getU8();
  1371. g_game.processVipAdd(id, name, status, desc, iconId, notifyLogin);
  1372. }
  1373. void ProtocolGame::parseVipState(const InputMessagePtr& msg)
  1374. {
  1375. uint id = msg->getU32();
  1376. if(g_game.getFeature(Otc::GameLoginPending)) {
  1377. uint status = msg->getU8();
  1378. g_game.processVipStateChange(id, status);
  1379. }
  1380. else {
  1381. g_game.processVipStateChange(id, 1);
  1382. }
  1383. }
  1384. void ProtocolGame::parseVipLogout(const InputMessagePtr& msg)
  1385. {
  1386. uint id = msg->getU32();
  1387. g_game.processVipStateChange(id, 0);
  1388. }
  1389. void ProtocolGame::parseTutorialHint(const InputMessagePtr& msg)
  1390. {
  1391. int id = msg->getU8();
  1392. g_game.processTutorialHint(id);
  1393. }
  1394. void ProtocolGame::parseAutomapFlag(const InputMessagePtr& msg)
  1395. {
  1396. Position pos = getPosition(msg);
  1397. int icon = msg->getU8();
  1398. std::string description = msg->getString();
  1399. bool remove = false;
  1400. if(g_game.getFeature(Otc::GameMinimapRemove))
  1401. remove = msg->getU8() != 0;
  1402. if(!remove)
  1403. g_game.processAddAutomapFlag(pos, icon, description);
  1404. else
  1405. g_game.processRemoveAutomapFlag(pos, icon, description);
  1406. }
  1407. void ProtocolGame::parseQuestLog(const InputMessagePtr& msg)
  1408. {
  1409. std::vector<std::tuple<int, std::string, bool> > questList;
  1410. int questsCount = msg->getU16();
  1411. for(int i = 0; i < questsCount; i++) {
  1412. int id = msg->getU16();
  1413. std::string name = msg->getString();
  1414. bool completed = msg->getU8();
  1415. questList.push_back(std::make_tuple(id, name, completed));
  1416. }
  1417. g_game.processQuestLog(questList);
  1418. }
  1419. void ProtocolGame::parseQuestLine(const InputMessagePtr& msg)
  1420. {
  1421. std::vector<std::tuple<std::string, std::string>> questMissions;
  1422. int questId = msg->getU16();
  1423. int missionCount = msg->getU8();
  1424. for(int i = 0; i < missionCount; i++) {
  1425. std::string missionName = msg->getString();
  1426. std::string missionDescrition = msg->getString();
  1427. questMissions.push_back(std::make_tuple(missionName, missionDescrition));
  1428. }
  1429. g_game.processQuestLine(questId, questMissions);
  1430. }
  1431. void ProtocolGame::parseChannelEvent(const InputMessagePtr& msg)
  1432. {
  1433. msg->getU16(); // channel id
  1434. g_game.formatCreatureName(msg->getString()); // player name
  1435. msg->getU8(); // event type
  1436. }
  1437. void ProtocolGame::parseItemInfo(const InputMessagePtr& msg)
  1438. {
  1439. std::vector<std::tuple<ItemPtr, std::string>> list;
  1440. int size = msg->getU8();
  1441. for(int i=0;i<size;++i) {
  1442. ItemPtr item(new Item);
  1443. item->setId(msg->getU16());
  1444. item->setCountOrSubType(msg->getU8());
  1445. std::string desc = msg->getString();
  1446. list.push_back(std::make_tuple(item, desc));
  1447. }
  1448. g_lua.callGlobalField("g_game", "onItemInfo", list);
  1449. }
  1450. void ProtocolGame::parsePlayerInventory(const InputMessagePtr& msg)
  1451. {
  1452. int size = msg->getU16();
  1453. for(int i=0;i<size;++i) {
  1454. msg->getU16(); // id
  1455. msg->getU8(); // subtype
  1456. msg->getU16(); // count
  1457. }
  1458. }
  1459. void ProtocolGame::parseModalDialog(const InputMessagePtr& msg)
  1460. {
  1461. uint32 id = msg->getU32();
  1462. std::string title = msg->getString();
  1463. std::string message = msg->getString();
  1464. int sizeButtons = msg->getU8();
  1465. std::vector<std::tuple<int, std::string> > buttonList;
  1466. for(int i = 0; i < sizeButtons; ++i) {
  1467. std::string value = msg->getString();
  1468. int id = msg->getU8();
  1469. buttonList.push_back(std::make_tuple(id, value));
  1470. }
  1471. int sizeChoices = msg->getU8();
  1472. std::vector<std::tuple<int, std::string> > choiceList;
  1473. for(int i = 0; i < sizeChoices; ++i) {
  1474. std::string value = msg->getString();
  1475. int id = msg->getU8();
  1476. choiceList.push_back(std::make_tuple(id, value));
  1477. }
  1478. int enterButton, escapeButton;
  1479. if(g_game.getClientVersion() > 970) {
  1480. escapeButton = msg->getU8();
  1481. enterButton = msg->getU8();
  1482. }
  1483. else {
  1484. enterButton = msg->getU8();
  1485. escapeButton = msg->getU8();
  1486. }
  1487. bool priority = msg->getU8() == 0x01;
  1488. g_game.processModalDialog(id, title, message, buttonList, enterButton, escapeButton, choiceList, priority);
  1489. }
  1490. void ProtocolGame::parseExtendedOpcode(const InputMessagePtr& msg)
  1491. {
  1492. int opcode = msg->getU8();
  1493. std::string buffer = msg->getString();
  1494. if(opcode == 0)
  1495. m_enableSendExtendedOpcode = true;
  1496. else if(opcode == 2)
  1497. parsePingBack(msg);
  1498. else
  1499. callLuaField("onExtendedOpcode", opcode, buffer);
  1500. }
  1501. void ProtocolGame::parseChangeMapAwareRange(const InputMessagePtr& msg)
  1502. {
  1503. int xrange = msg->getU8();
  1504. int yrange = msg->getU8();
  1505. AwareRange range;
  1506. range.left = xrange/2 - ((xrange+1) % 2);
  1507. range.right = xrange/2;
  1508. range.top = yrange/2 - ((yrange+1) % 2);
  1509. range.bottom = yrange/2;
  1510. g_map.setAwareRange(range);
  1511. g_lua.callGlobalField("g_game", "onMapChangeAwareRange", xrange, yrange);
  1512. }
  1513. void ProtocolGame::parseCreaturesMark(const InputMessagePtr& msg)
  1514. {
  1515. int len;
  1516. if(g_game.getClientVersion() >= 1035) {
  1517. len = 1;
  1518. } else {
  1519. len = msg->getU8();
  1520. }
  1521. for(int i=0; i<len; ++i) {
  1522. uint32 id = msg->getU32();
  1523. bool isPermanent = msg->getU8() != 1;
  1524. uint8 markType = msg->getU8();
  1525. CreaturePtr creature = g_map.getCreatureById(id);
  1526. if(creature) {
  1527. if(isPermanent) {
  1528. if(markType == 0xff)
  1529. creature->hideStaticSquare();
  1530. else
  1531. creature->showStaticSquare(Color::from8bit(markType));
  1532. } else
  1533. creature->addTimedSquare(markType);
  1534. } else
  1535. g_logger.traceError("could not get creature");
  1536. }
  1537. }
  1538. void ProtocolGame::parseCreatureType(const InputMessagePtr& msg)
  1539. {
  1540. uint32 id = msg->getU32();
  1541. uint8 type = msg->getU8();
  1542. }
  1543. void ProtocolGame::setMapDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height)
  1544. {
  1545. int startz, endz, zstep;
  1546. if(z > Otc::SEA_FLOOR) {
  1547. startz = z - Otc::AWARE_UNDEGROUND_FLOOR_RANGE;
  1548. endz = std::min<int>(z + Otc::AWARE_UNDEGROUND_FLOOR_RANGE, (int)Otc::MAX_Z);
  1549. zstep = 1;
  1550. }
  1551. else {
  1552. startz = Otc::SEA_FLOOR;
  1553. endz = 0;
  1554. zstep = -1;
  1555. }
  1556. int skip = 0;
  1557. for(int nz = startz; nz != endz + zstep; nz += zstep)
  1558. skip = setFloorDescription(msg, x, y, nz, width, height, z - nz, skip);
  1559. }
  1560. int ProtocolGame::setFloorDescription(const InputMessagePtr& msg, int x, int y, int z, int width, int height, int offset, int skip)
  1561. {
  1562. for(int nx = 0; nx < width; nx++) {
  1563. for(int ny = 0; ny < height; ny++) {
  1564. Position tilePos(x + nx + offset, y + ny + offset, z);
  1565. if(skip == 0)
  1566. skip = setTileDescription(msg, tilePos);
  1567. else {
  1568. g_map.cleanTile(tilePos);
  1569. skip--;
  1570. }
  1571. }
  1572. }
  1573. return skip;
  1574. }
  1575. int ProtocolGame::setTileDescription(const InputMessagePtr& msg, Position position)
  1576. {
  1577. g_map.cleanTile(position);
  1578. bool gotEffect = false;
  1579. for(int stackPos=0;stackPos<256;stackPos++) {
  1580. if(msg->peekU16() >= 0xff00)
  1581. return msg->getU16() & 0xff;
  1582. if(g_game.getFeature(Otc::GameEnvironmentEffect) && !gotEffect) {
  1583. msg->getU16(); // environment effect
  1584. gotEffect = true;
  1585. continue;
  1586. }
  1587. if(stackPos > 10)
  1588. g_logger.traceError(stdext::format("too many things, pos=%s, stackpos=%d", stdext::to_string(position), stackPos));
  1589. ThingPtr thing = getThing(msg);
  1590. g_map.addThing(thing, position, stackPos);
  1591. }
  1592. return 0;
  1593. }
  1594. Outfit ProtocolGame::getOutfit(const InputMessagePtr& msg)
  1595. {
  1596. Outfit outfit;
  1597. int lookType;
  1598. if(g_game.getFeature(Otc::GameLooktypeU16))
  1599. lookType = msg->getU16();
  1600. else
  1601. lookType = msg->getU8();
  1602. if(lookType != 0) {
  1603. outfit.setCategory(ThingCategoryCreature);
  1604. int head = msg->getU8();
  1605. int body = msg->getU8();
  1606. int legs = msg->getU8();
  1607. int feet = msg->getU8();
  1608. int addons = 0;
  1609. if(g_game.getFeature(Otc::GamePlayerAddons))
  1610. addons = msg->getU8();
  1611. if(!g_things.isValidDatId(lookType, ThingCategoryCreature)) {
  1612. g_logger.traceError(stdext::format("invalid outfit looktype %d", lookType));
  1613. lookType = 0;
  1614. }
  1615. outfit.setId(lookType);
  1616. outfit.setHead(head);
  1617. outfit.setBody(body);
  1618. outfit.setLegs(legs);
  1619. outfit.setFeet(feet);
  1620. outfit.setAddons(addons);
  1621. }
  1622. else {
  1623. int lookTypeEx = msg->getU16();
  1624. if(lookTypeEx == 0) {
  1625. outfit.setCategory(ThingCategoryEffect);
  1626. outfit.setAuxId(13); // invisible effect id
  1627. }
  1628. else {
  1629. if(!g_things.isValidDatId(lookTypeEx, ThingCategoryItem)) {
  1630. g_logger.traceError(stdext::format("invalid outfit looktypeex %d", lookTypeEx));
  1631. lookTypeEx = 0;
  1632. }
  1633. outfit.setCategory(ThingCategoryItem);
  1634. outfit.setAuxId(lookTypeEx);
  1635. }
  1636. }
  1637. if(g_game.getFeature(Otc::GamePlayerMounts)) {
  1638. int mount = msg->getU16();
  1639. outfit.setMount(mount);
  1640. }
  1641. return outfit;
  1642. }
  1643. ThingPtr ProtocolGame::getThing(const InputMessagePtr& msg)
  1644. {
  1645. ThingPtr thing;
  1646. int id = msg->getU16();
  1647. if(id == 0)
  1648. stdext::throw_exception("invalid thing id");
  1649. else if(id == Proto::UnknownCreature || id == Proto::OutdatedCreature || id == Proto::Creature)
  1650. thing = getCreature(msg, id);
  1651. else if(id == Proto::StaticText) // otclient only
  1652. thing = getStaticText(msg, id);
  1653. else // item
  1654. thing = getItem(msg, id);
  1655. return thing;
  1656. }
  1657. ThingPtr ProtocolGame::getMappedThing(const InputMessagePtr& msg)
  1658. {
  1659. ThingPtr thing;
  1660. uint16 x = msg->getU16();
  1661. if(x != 0xffff) {
  1662. Position pos;
  1663. pos.x = x;
  1664. pos.y = msg->getU16();
  1665. pos.z = msg->getU8();
  1666. uint8 stackpos = msg->getU8();
  1667. assert(stackpos != 255);
  1668. thing = g_map.getThing(pos, stackpos);
  1669. if(!thing)
  1670. g_logger.traceError(stdext::format("no thing at pos:%s, stackpos:%d", stdext::to_string(pos), stackpos));
  1671. } else {
  1672. uint32 id = msg->getU32();
  1673. thing = g_map.getCreatureById(id);
  1674. if(!thing)
  1675. g_logger.traceError(stdext::format("no creature with id %u", id));
  1676. }
  1677. return thing;
  1678. }
  1679. CreaturePtr ProtocolGame::getCreature(const InputMessagePtr& msg, int type)
  1680. {
  1681. if(type == 0)
  1682. type = msg->getU16();
  1683. CreaturePtr creature;
  1684. bool known = (type != Proto::UnknownCreature);
  1685. if(type == Proto::OutdatedCreature || type == Proto::UnknownCreature) {
  1686. if(known) {
  1687. uint id = msg->getU32();
  1688. creature = g_map.getCreatureById(id);
  1689. if(!creature)
  1690. g_logger.traceError("server said that a creature is known, but it's not");
  1691. } else {
  1692. uint removeId = msg->getU32();
  1693. g_map.removeCreatureById(removeId);
  1694. uint id = msg->getU32();
  1695. int creatureType;
  1696. if(g_game.getClientVersion() >= 910)
  1697. creatureType = msg->getU8();
  1698. else {
  1699. if(id >= Proto::PlayerStartId && id < Proto::PlayerEndId)
  1700. creatureType = Proto::CreatureTypePlayer;
  1701. else if(id >= Proto::MonsterStartId && id < Proto::MonsterEndId)
  1702. creatureType = Proto::CreatureTypeMonster;
  1703. else
  1704. creatureType = Proto::CreatureTypeNpc;
  1705. }
  1706. std::string name = g_game.formatCreatureName(msg->getString());
  1707. if(id == m_localPlayer->getId())
  1708. creature = m_localPlayer;
  1709. else if(creatureType == Proto::CreatureTypePlayer) {
  1710. // fixes a bug server side bug where GameInit is not sent and local player id is unknown
  1711. if(m_localPlayer->getId() == 0 && name == m_localPlayer->getName())
  1712. creature = m_localPlayer;
  1713. else
  1714. creature = PlayerPtr(new Player);
  1715. }
  1716. else if(creatureType == Proto::CreatureTypeMonster)
  1717. creature = MonsterPtr(new Monster);
  1718. else if(creatureType == Proto::CreatureTypeNpc)
  1719. creature = NpcPtr(new Npc);
  1720. else
  1721. g_logger.traceError("creature type is invalid");
  1722. if(creature) {
  1723. creature->setId(id);
  1724. creature->setName(name);
  1725. g_map.addCreature(creature);
  1726. }
  1727. }
  1728. int healthPercent = msg->getU8();
  1729. Otc::Direction direction = (Otc::Direction)msg->getU8();
  1730. Outfit outfit = getOutfit(msg);
  1731. Light light;
  1732. light.intensity = msg->getU8();
  1733. light.color = msg->getU8();
  1734. int speed = msg->getU16();
  1735. int skull = msg->getU8();
  1736. int shield = msg->getU8();
  1737. // emblem is sent only when the creature is not known
  1738. int emblem = -1;
  1739. int icon = -1;
  1740. bool unpass = true;
  1741. uint8 mark;
  1742. if(g_game.getFeature(Otc::GameCreatureEmblems) && !known)
  1743. emblem = msg->getU8();
  1744. if(g_game.getFeature(Otc::GameThingMarks)) {
  1745. msg->getU8(); // creature type for summons
  1746. }
  1747. if(g_game.getFeature(Otc::GameCreatureIcons)) {
  1748. icon = msg->getU8();
  1749. }
  1750. if(g_game.getFeature(Otc::GameThingMarks)) {
  1751. mark = msg->getU8(); // mark
  1752. msg->getU16(); // helpers
  1753. if(creature) {
  1754. if(mark == 0xff)
  1755. creature->hideStaticSquare();
  1756. else
  1757. creature->showStaticSquare(Color::from8bit(mark));
  1758. }
  1759. }
  1760. if(g_game.getClientVersion() >= 854)
  1761. unpass = msg->getU8();
  1762. if(creature) {
  1763. creature->setHealthPercent(healthPercent);
  1764. creature->setDirection(direction);
  1765. creature->setOutfit(outfit);
  1766. creature->setSpeed(speed);
  1767. creature->setSkull(skull);
  1768. creature->setShield(shield);
  1769. creature->setPassable(!unpass);
  1770. creature->setLight(light);
  1771. if(emblem != -1)
  1772. creature->setEmblem(emblem);
  1773. if(icon != -1)
  1774. creature->setIcon(icon);
  1775. if(creature == m_localPlayer && !m_localPlayer->isKnown())
  1776. m_localPlayer->setKnown(true);
  1777. }
  1778. } else if(type == Proto::Creature) {
  1779. uint id = msg->getU32();
  1780. creature = g_map.getCreatureById(id);
  1781. if(!creature)
  1782. g_logger.traceError("invalid creature");
  1783. Otc::Direction direction = (Otc::Direction)msg->getU8();
  1784. if(creature)
  1785. creature->turn(direction);
  1786. if(g_game.getClientVersion() >= 953) {
  1787. bool unpass = msg->getU8();
  1788. if(creature)
  1789. creature->setPassable(!unpass);
  1790. }
  1791. } else {
  1792. stdext::throw_exception("invalid creature opcode");
  1793. }
  1794. return creature;
  1795. }
  1796. ItemPtr ProtocolGame::getItem(const InputMessagePtr& msg, int id)
  1797. {
  1798. if(id == 0)
  1799. id = msg->getU16();
  1800. ItemPtr item = Item::create(id);
  1801. if(item->getId() == 0)
  1802. stdext::throw_exception(stdext::format("unable to create item with invalid id %d", id));
  1803. if(g_game.getFeature(Otc::GameThingMarks)) {
  1804. msg->getU8(); // mark
  1805. }
  1806. if(item->isStackable() || item->isFluidContainer() || item->isSplash() || item->isChargeable())
  1807. item->setCountOrSubType(msg->getU8());
  1808. if(g_game.getFeature(Otc::GameItemAnimationPhase)) {
  1809. if(item->getAnimationPhases() > 1) {
  1810. // 0x00 => automatic phase
  1811. // 0xFE => random phase
  1812. // 0xFF => async phase
  1813. msg->getU8();
  1814. //item->setPhase(msg->getU8());
  1815. }
  1816. }
  1817. return item;
  1818. }
  1819. StaticTextPtr ProtocolGame::getStaticText(const InputMessagePtr& msg, int id)
  1820. {
  1821. int colorByte = msg->getU8();
  1822. Color color = Color::from8bit(colorByte);
  1823. std::string fontName = msg->getString();
  1824. std::string text = msg->getString();
  1825. StaticTextPtr staticText = StaticTextPtr(new StaticText);
  1826. staticText->setText(text);
  1827. staticText->setFont(fontName);
  1828. staticText->setColor(color);
  1829. return staticText;
  1830. }
  1831. Position ProtocolGame::getPosition(const InputMessagePtr& msg)
  1832. {
  1833. uint16 x = msg->getU16();
  1834. uint16 y = msg->getU16();
  1835. uint8 z = msg->getU8();
  1836. return Position(x, y, z);
  1837. }