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.

game.cpp 35KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332
  1. /*
  2. * Copyright (c) 2010-2012 OTClient <https://github.com/edubart/otclient>
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. * THE SOFTWARE.
  21. */
  22. #include "game.h"
  23. #include "localplayer.h"
  24. #include "map.h"
  25. #include "tile.h"
  26. #include "creature.h"
  27. #include "container.h"
  28. #include "statictext.h"
  29. #include <framework/core/eventdispatcher.h>
  30. #include <framework/ui/uimanager.h>
  31. #include <framework/core/application.h>
  32. #include "luavaluecasts.h"
  33. #include "protocolgame.h"
  34. #include "protocolcodes.h"
  35. Game g_game;
  36. Game::Game()
  37. {
  38. resetGameStates();
  39. m_protocolVersion = 0;
  40. m_clientVersion = 0;
  41. }
  42. void Game::terminate()
  43. {
  44. resetGameStates();
  45. m_protocolGame = nullptr;
  46. }
  47. void Game::resetGameStates()
  48. {
  49. m_online = false;
  50. m_denyBotCall = false;
  51. m_dead = false;
  52. m_serverBeat = 50;
  53. m_seq = 0;
  54. m_ping = -1;
  55. m_canReportBugs = false;
  56. m_fightMode = Otc::FightBalanced;
  57. m_chaseMode = Otc::DontChase;
  58. m_safeFight = true;
  59. m_followingCreature = nullptr;
  60. m_attackingCreature = nullptr;
  61. m_localPlayer = nullptr;
  62. for(auto& it : m_containers) {
  63. const ContainerPtr& container = it.second;
  64. if(container)
  65. container->onClose();
  66. }
  67. if(m_pingEvent) {
  68. m_pingEvent->cancel();
  69. m_pingEvent = nullptr;
  70. }
  71. if(m_walkEvent) {
  72. m_walkEvent->cancel();
  73. m_walkEvent = nullptr;
  74. }
  75. m_containers.clear();
  76. m_vips.clear();
  77. m_gmActions.clear();
  78. }
  79. void Game::processConnectionError(const boost::system::error_code& ec)
  80. {
  81. // connection errors only have meaning if we still have a protocol
  82. if(m_protocolGame) {
  83. // eof = end of file, a clean disconnect
  84. if(ec != asio::error::eof)
  85. g_lua.callGlobalField("g_game", "onConnectionError", ec.message(), ec.value());
  86. processDisconnect();
  87. }
  88. }
  89. void Game::processDisconnect()
  90. {
  91. if(isOnline())
  92. processGameEnd();
  93. if(m_protocolGame) {
  94. m_protocolGame->disconnect();
  95. m_protocolGame = nullptr;
  96. }
  97. }
  98. void Game::processLoginError(const std::string& error)
  99. {
  100. g_lua.callGlobalField("g_game", "onLoginError", error);
  101. }
  102. void Game::processLoginAdvice(const std::string& message)
  103. {
  104. g_lua.callGlobalField("g_game", "onLoginAdvice", message);
  105. }
  106. void Game::processLoginWait(const std::string& message, int time)
  107. {
  108. g_lua.callGlobalField("g_game", "onLoginWait", message, time);
  109. }
  110. void Game::processPendingGame()
  111. {
  112. m_localPlayer->setPendingGame(true);
  113. g_lua.callGlobalField("g_game", "onPendingGame");
  114. }
  115. void Game::processEnterGame()
  116. {
  117. m_localPlayer->setPendingGame(false);
  118. g_lua.callGlobalField("g_game", "onEnterGame");
  119. }
  120. void Game::processGameStart()
  121. {
  122. m_online = true;
  123. // synchronize fight modes with the server
  124. m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight);
  125. // NOTE: the entire map description and local player information is not known yet (bot call is allowed here)
  126. enableBotCall();
  127. g_lua.callGlobalField("g_game", "onGameStart");
  128. disableBotCall();
  129. if(g_game.getFeature(Otc::GameClientPing)) {
  130. m_protocolGame->sendPing();
  131. m_pingEvent = g_dispatcher.cycleEvent([this] {
  132. if(m_protocolGame && m_protocolGame->isConnected()) {
  133. enableBotCall();
  134. m_protocolGame->sendPing();
  135. disableBotCall();
  136. }
  137. }, 2000);
  138. }
  139. }
  140. void Game::processGameEnd()
  141. {
  142. g_lua.callGlobalField("g_game", "onGameEnd");
  143. // reset game state
  144. resetGameStates();
  145. m_worldName = "";
  146. m_characterName = "";
  147. // clean map creatures
  148. g_map.cleanDynamicThings();
  149. }
  150. void Game::processDeath(int penality)
  151. {
  152. m_dead = true;
  153. m_localPlayer->stopWalk();
  154. g_lua.callGlobalField("g_game", "onDeath", penality);
  155. }
  156. void Game::processGMActions(const std::vector<uint8>& actions)
  157. {
  158. m_gmActions = actions;
  159. g_lua.callGlobalField("g_game", "onGMActions", actions);
  160. }
  161. void Game::processPing()
  162. {
  163. g_lua.callGlobalField("g_game", "onPing");
  164. }
  165. void Game::processPingBack(int elapsed)
  166. {
  167. m_ping = elapsed;
  168. g_lua.callGlobalField("g_game", "onPingBack", elapsed);
  169. }
  170. void Game::processTextMessage(Otc::MessageMode mode, const std::string& text)
  171. {
  172. g_lua.callGlobalField("g_game", "onTextMessage", mode, text);
  173. }
  174. void Game::processTalk(const std::string& name, int level, Otc::MessageMode mode, const std::string& text, int channelId, const Position& pos)
  175. {
  176. g_lua.callGlobalField("g_game", "onTalk", name, level, mode, text, channelId, pos);
  177. }
  178. void Game::processOpenContainer(int containerId, const ItemPtr& containerItem, const std::string& name, int capacity, bool hasParent, const std::vector<ItemPtr>& items)
  179. {
  180. ContainerPtr previousContainer = getContainer(containerId);
  181. ContainerPtr container = ContainerPtr(new Container(containerId, capacity, name, containerItem, hasParent));
  182. m_containers[containerId] = container;
  183. container->onAddItems(items);
  184. // we might want to close a container here
  185. enableBotCall();
  186. container->onOpen(previousContainer);
  187. disableBotCall();
  188. if(previousContainer)
  189. previousContainer->onClose();
  190. }
  191. void Game::processCloseContainer(int containerId)
  192. {
  193. ContainerPtr container = getContainer(containerId);
  194. if(!container) {
  195. g_logger.traceError("container not found");
  196. return;
  197. }
  198. m_containers[containerId] = nullptr;
  199. container->onClose();
  200. }
  201. void Game::processContainerAddItem(int containerId, const ItemPtr& item)
  202. {
  203. ContainerPtr container = getContainer(containerId);
  204. if(!container) {
  205. g_logger.traceError("container not found");
  206. return;
  207. }
  208. container->onAddItem(item);
  209. }
  210. void Game::processContainerUpdateItem(int containerId, int slot, const ItemPtr& item)
  211. {
  212. ContainerPtr container = getContainer(containerId);
  213. if(!container) {
  214. g_logger.traceError("container not found");
  215. return;
  216. }
  217. container->onUpdateItem(slot, item);
  218. }
  219. void Game::processContainerRemoveItem(int containerId, int slot)
  220. {
  221. ContainerPtr container = getContainer(containerId);
  222. if(!container) {
  223. g_logger.traceError("container not found");
  224. return;
  225. }
  226. container->onRemoveItem(slot);
  227. }
  228. void Game::processInventoryChange(int slot, const ItemPtr& item)
  229. {
  230. if(item)
  231. item->setPosition(Position(65535, slot, 0));
  232. m_localPlayer->setInventoryItem((Otc::InventorySlot)slot, item);
  233. }
  234. void Game::processChannelList(const std::vector<std::tuple<int, std::string> >& channelList)
  235. {
  236. g_lua.callGlobalField("g_game", "onChannelList", channelList);
  237. }
  238. void Game::processOpenChannel(int channelId, const std::string& name)
  239. {
  240. g_lua.callGlobalField("g_game", "onOpenChannel", channelId, name);
  241. }
  242. void Game::processOpenPrivateChannel(const std::string& name)
  243. {
  244. g_lua.callGlobalField("g_game", "onOpenPrivateChannel", name);
  245. }
  246. void Game::processOpenOwnPrivateChannel(int channelId, const std::string& name)
  247. {
  248. g_lua.callGlobalField("g_game", "onOpenOwnPrivateChannel", channelId, name);
  249. }
  250. void Game::processCloseChannel(int channelId)
  251. {
  252. g_lua.callGlobalField("g_game", "onCloseChannel", channelId);
  253. }
  254. void Game::processRuleViolationChannel(int channelId)
  255. {
  256. g_lua.callGlobalField("g_game", "onRuleViolationChannel", channelId);
  257. }
  258. void Game::processRuleViolationRemove(const std::string& name)
  259. {
  260. g_lua.callGlobalField("g_game", "onRuleViolationRemove", name);
  261. }
  262. void Game::processRuleViolationCancel(const std::string& name)
  263. {
  264. g_lua.callGlobalField("g_game", "onRuleViolationCancel", name);
  265. }
  266. void Game::processRuleViolationLock()
  267. {
  268. g_lua.callGlobalField("g_game", "onRuleViolationLock");
  269. }
  270. void Game::processVipAdd(uint id, const std::string& name, uint status)
  271. {
  272. m_vips[id] = Vip(name, status);
  273. g_lua.callGlobalField("g_game", "onAddVip", id, name, status);
  274. }
  275. void Game::processVipStateChange(uint id, uint status)
  276. {
  277. std::get<1>(m_vips[id]) = status;
  278. g_lua.callGlobalField("g_game", "onVipStateChange", id, status);
  279. }
  280. void Game::processTutorialHint(int id)
  281. {
  282. g_lua.callGlobalField("g_game", "onTutorialHint", id);
  283. }
  284. void Game::processAutomapFlag(const Position& pos, int icon, const std::string& message)
  285. {
  286. g_lua.callGlobalField("g_game", "onAutomapFlag", pos, icon, message);
  287. }
  288. void Game::processOpenOutfitWindow(const Outfit& currentOufit, const std::vector<std::tuple<int, std::string, int> >& outfitList,
  289. const std::vector<std::tuple<int, std::string> >& mountList)
  290. {
  291. // create virtual creature outfit
  292. CreaturePtr virtualOutfitCreature = CreaturePtr(new Creature);
  293. virtualOutfitCreature->setDirection(Otc::South);
  294. Outfit outfit = currentOufit;
  295. outfit.setMount(0);
  296. virtualOutfitCreature->setOutfit(outfit);
  297. // creature virtual mount outfit
  298. CreaturePtr virtualMountCreature = nullptr;
  299. if(getFeature(Otc::GamePlayerMounts))
  300. {
  301. virtualMountCreature = CreaturePtr(new Creature);
  302. virtualMountCreature->setDirection(Otc::South);
  303. Outfit mountOutfit;
  304. mountOutfit.setId(0);
  305. int mount = currentOufit.getMount();
  306. if(mount > 0)
  307. mountOutfit.setId(mount);
  308. virtualMountCreature->setOutfit(mountOutfit);
  309. }
  310. g_lua.callGlobalField("g_game", "onOpenOutfitWindow", virtualOutfitCreature, outfitList, virtualMountCreature, mountList);
  311. }
  312. void Game::processOpenNpcTrade(const std::vector<std::tuple<ItemPtr, std::string, int, int, int> >& items)
  313. {
  314. g_lua.callGlobalField("g_game", "onOpenNpcTrade", items);
  315. }
  316. void Game::processPlayerGoods(int money, const std::vector<std::tuple<ItemPtr, int> >& goods)
  317. {
  318. g_lua.callGlobalField("g_game", "onPlayerGoods", money, goods);
  319. }
  320. void Game::processCloseNpcTrade()
  321. {
  322. g_lua.callGlobalField("g_game", "onCloseNpcTrade");
  323. }
  324. void Game::processOwnTrade(const std::string& name, const std::vector<ItemPtr>& items)
  325. {
  326. g_lua.callGlobalField("g_game", "onOwnTrade", name, items);
  327. }
  328. void Game::processCounterTrade(const std::string& name, const std::vector<ItemPtr>& items)
  329. {
  330. g_lua.callGlobalField("g_game", "onCounterTrade", name, items);
  331. }
  332. void Game::processCloseTrade()
  333. {
  334. g_lua.callGlobalField("g_game", "onCloseTrade");
  335. }
  336. void Game::processEditText(uint id, int itemId, int maxLength, const std::string& text, const std::string& writter, const std::string& date)
  337. {
  338. g_lua.callGlobalField("g_game", "onEditText", id, itemId, maxLength, text, writter, date);
  339. }
  340. void Game::processEditList(uint id, int doorId, const std::string& text)
  341. {
  342. g_lua.callGlobalField("g_game", "onEditList", id, doorId, text);
  343. }
  344. void Game::processQuestLog(const std::vector<std::tuple<int, std::string, bool> >& questList)
  345. {
  346. g_lua.callGlobalField("g_game", "onQuestLog", questList);
  347. }
  348. void Game::processQuestLine(int questId, const std::vector<std::tuple<std::string, std::string> >& questMissions)
  349. {
  350. g_lua.callGlobalField("g_game", "onQuestLine", questId, questMissions);
  351. }
  352. void Game::processModalDialog(uint32 id, std::string title, std::string message, int enterId, std::string enterText, int escapeId, std::string escapeText, std::vector<std::tuple<int, std::string> > choiceList)
  353. {
  354. g_lua.callGlobalField("g_game", "onModalDialog", id, title, message, enterId, enterText, escapeId, escapeText, choiceList);
  355. }
  356. void Game::processAttackCancel(uint seq)
  357. {
  358. if(isAttacking() && (seq == 0 || m_seq == seq))
  359. cancelAttack();
  360. }
  361. void Game::processWalkCancel(Otc::Direction direction)
  362. {
  363. if(m_localPlayer->isAutoWalking())
  364. m_protocolGame->sendStop();
  365. m_localPlayer->cancelWalk(direction);
  366. }
  367. void Game::loginWorld(const std::string& account, const std::string& password, const std::string& worldName, const std::string& worldHost, int worldPort, const std::string& characterName)
  368. {
  369. if(m_protocolGame || isOnline())
  370. stdext::throw_exception("Unable to login into a world while already online or logging.");
  371. if(m_protocolVersion == 0)
  372. stdext::throw_exception("Must set a valid game protocol version before logging.");
  373. // reset the new game state
  374. resetGameStates();
  375. m_localPlayer = LocalPlayerPtr(new LocalPlayer);
  376. m_localPlayer->setName(characterName);
  377. m_protocolGame = ProtocolGamePtr(new ProtocolGame);
  378. m_protocolGame->login(account, password, worldHost, (uint16)worldPort, characterName);
  379. m_characterName = characterName;
  380. m_worldName = worldName;
  381. }
  382. void Game::cancelLogin()
  383. {
  384. // send logout even if the game has not started yet, to make sure that the player doesn't stay logged there
  385. if(m_protocolGame)
  386. m_protocolGame->sendLogout();
  387. processDisconnect();
  388. }
  389. void Game::forceLogout()
  390. {
  391. if(!isOnline())
  392. return;
  393. m_protocolGame->sendLogout();
  394. processDisconnect();
  395. }
  396. void Game::safeLogout()
  397. {
  398. if(!isOnline())
  399. return;
  400. m_protocolGame->sendLogout();
  401. }
  402. bool Game::walk(Otc::Direction direction)
  403. {
  404. if(!canPerformGameAction())
  405. return false;
  406. // must cancel follow before any new walk
  407. if(isFollowing())
  408. cancelFollow();
  409. // must cancel auto walking and wait next try
  410. if(m_localPlayer->isAutoWalking()) {
  411. m_protocolGame->sendStop();
  412. return false;
  413. }
  414. // check we can walk and add new walk event if false
  415. if(!m_localPlayer->canWalk(direction)) {
  416. if(m_lastWalkDir != direction) {
  417. // must add a new walk event
  418. float ticks = m_localPlayer->getStepTicksLeft();
  419. if(ticks < 0)
  420. ticks = 0;
  421. if(m_walkEvent) {
  422. m_walkEvent->cancel();
  423. m_walkEvent = nullptr;
  424. }
  425. m_walkEvent = g_dispatcher.scheduleEvent([=] { walk(direction); }, ticks);
  426. }
  427. return false;
  428. }
  429. Position toPos = m_localPlayer->getPosition().translatedToDirection(direction);
  430. TilePtr toTile = g_map.getTile(toPos);
  431. // only do prewalks to walkable tiles (like grounds and not walls)
  432. if(toTile && toTile->isWalkable())
  433. m_localPlayer->preWalk(direction);
  434. // check walk to another floor (e.g: when above 3 parcels)
  435. else {
  436. // check if can walk to a lower floor
  437. auto canChangeFloorDown = [&]() -> bool {
  438. Position pos = toPos;
  439. if(!pos.down())
  440. return false;
  441. TilePtr toTile = g_map.getTile(pos);
  442. if(toTile && toTile->hasElevation(3))
  443. return true;
  444. return false;
  445. };
  446. // check if can walk to a higher floor
  447. auto canChangeFloorUp = [&]() -> bool {
  448. TilePtr fromTile = m_localPlayer->getTile();
  449. if(!fromTile || !fromTile->hasElevation(3))
  450. return false;
  451. Position pos = toPos;
  452. if(!pos.up())
  453. return false;
  454. TilePtr toTile = g_map.getTile(pos);
  455. if(!toTile || !toTile->isWalkable())
  456. return false;
  457. return true;
  458. };
  459. if(canChangeFloorDown() || canChangeFloorUp() ||
  460. (!toTile || toTile->isEmpty())) {
  461. m_localPlayer->lockWalk();
  462. } else
  463. return false;
  464. }
  465. g_lua.callGlobalField("g_game", "onWalk", direction);
  466. forceWalk(direction);
  467. m_lastWalkDir = direction;
  468. return true;
  469. }
  470. void Game::autoWalk(std::vector<Otc::Direction> dirs)
  471. {
  472. if(!canPerformGameAction())
  473. return;
  474. // protocol limits walk path up to 255 directions
  475. if(dirs.size() > 127) {
  476. g_logger.error("Auto walk path too great, the maximum number of directions is 127");
  477. return;
  478. }
  479. if(dirs.size() == 0)
  480. return;
  481. // must cancel follow before any new walk
  482. if(isFollowing())
  483. cancelFollow();
  484. auto it = dirs.begin();
  485. Otc::Direction direction = *it;
  486. if(m_localPlayer->canWalk(direction)) {
  487. TilePtr toTile = g_map.getTile(m_localPlayer->getPosition().translatedToDirection(direction));
  488. if(toTile && toTile->isWalkable() && !m_localPlayer->isAutoWalking())
  489. {
  490. m_localPlayer->preWalk(direction);
  491. forceWalk(direction);
  492. dirs.erase(it);
  493. }
  494. }
  495. g_lua.callGlobalField("g_game", "onAutoWalk", dirs);
  496. m_protocolGame->sendAutoWalk(dirs);
  497. }
  498. void Game::forceWalk(Otc::Direction direction)
  499. {
  500. if(!canPerformGameAction())
  501. return;
  502. switch(direction) {
  503. case Otc::North:
  504. m_protocolGame->sendWalkNorth();
  505. break;
  506. case Otc::East:
  507. m_protocolGame->sendWalkEast();
  508. break;
  509. case Otc::South:
  510. m_protocolGame->sendWalkSouth();
  511. break;
  512. case Otc::West:
  513. m_protocolGame->sendWalkWest();
  514. break;
  515. case Otc::NorthEast:
  516. m_protocolGame->sendWalkNorthEast();
  517. break;
  518. case Otc::SouthEast:
  519. m_protocolGame->sendWalkSouthEast();
  520. break;
  521. case Otc::SouthWest:
  522. m_protocolGame->sendWalkSouthWest();
  523. break;
  524. case Otc::NorthWest:
  525. m_protocolGame->sendWalkNorthWest();
  526. break;
  527. default:
  528. break;
  529. }
  530. g_lua.callGlobalField("g_game", "onForceWalk", direction);
  531. }
  532. void Game::turn(Otc::Direction direction)
  533. {
  534. if(!canPerformGameAction())
  535. return;
  536. switch(direction) {
  537. case Otc::North:
  538. m_protocolGame->sendTurnNorth();
  539. break;
  540. case Otc::East:
  541. m_protocolGame->sendTurnEast();
  542. break;
  543. case Otc::South:
  544. m_protocolGame->sendTurnSouth();
  545. break;
  546. case Otc::West:
  547. m_protocolGame->sendTurnWest();
  548. break;
  549. default:
  550. break;
  551. }
  552. }
  553. void Game::stop()
  554. {
  555. if(!canPerformGameAction())
  556. return;
  557. if(isFollowing())
  558. cancelFollow();
  559. m_protocolGame->sendStop();
  560. }
  561. void Game::look(const ThingPtr& thing)
  562. {
  563. if(!canPerformGameAction() || !thing)
  564. return;
  565. if(thing->isCreature() && m_protocolVersion >= 961)
  566. m_protocolGame->sendLookCreature(thing->getId());
  567. else
  568. m_protocolGame->sendLook(thing->getPosition(), thing->getId(), thing->getStackpos());
  569. }
  570. void Game::move(const ThingPtr& thing, const Position& toPos, int count)
  571. {
  572. if(count <= 0)
  573. count = 1;
  574. if(!canPerformGameAction() || !thing || thing->getPosition() == toPos)
  575. return;
  576. uint id = thing->getId();
  577. if(thing->isCreature()) {
  578. CreaturePtr creature = thing->static_self_cast<Creature>();
  579. id = Proto::Creature;
  580. }
  581. m_protocolGame->sendMove(thing->getPosition(), id, thing->getStackpos(), toPos, count);
  582. }
  583. void Game::moveToParentContainer(const ThingPtr& thing, int count)
  584. {
  585. if(!canPerformGameAction() || !thing || count <= 0)
  586. return;
  587. Position position = thing->getPosition();
  588. move(thing, Position(position.x, position.y, 254), count);
  589. }
  590. void Game::rotate(const ThingPtr& thing)
  591. {
  592. if(!canPerformGameAction() || !thing)
  593. return;
  594. m_protocolGame->sendRotateItem(thing->getPosition(), thing->getId(), thing->getStackpos());
  595. }
  596. void Game::use(const ThingPtr& thing)
  597. {
  598. if(!canPerformGameAction() || !thing)
  599. return;
  600. Position pos = thing->getPosition();
  601. if(!pos.isValid()) // virtual item
  602. pos = Position(0xFFFF, 0, 0); // means that is a item in inventory
  603. // some itens, e.g. parcel, are not set as containers but they are.
  604. // always try to use these items in free container slots.
  605. m_protocolGame->sendUseItem(pos, thing->getId(), thing->getStackpos(), findEmptyContainerId());
  606. }
  607. void Game::useInventoryItem(int itemId)
  608. {
  609. if(!canPerformGameAction() || !g_things.isValidDatId(itemId, ThingCategoryItem))
  610. return;
  611. Position pos = Position(0xFFFF, 0, 0); // means that is a item in inventory
  612. m_protocolGame->sendUseItem(pos, itemId, 0, 0);
  613. }
  614. void Game::useWith(const ItemPtr& item, const ThingPtr& toThing)
  615. {
  616. if(!canPerformGameAction() || !item || !toThing)
  617. return;
  618. Position pos = item->getPosition();
  619. if(!pos.isValid()) // virtual item
  620. pos = Position(0xFFFF, 0, 0); // means that is a item in inventory
  621. if(toThing->isCreature() && g_game.getProtocolVersion() >= 860)
  622. m_protocolGame->sendUseOnCreature(pos, item->getId(), item->getStackpos(), toThing->getId());
  623. else
  624. m_protocolGame->sendUseItemWith(pos, item->getId(), item->getStackpos(), toThing->getPosition(), toThing->getId(), toThing->getStackpos());
  625. }
  626. void Game::useInventoryItemWith(int itemId, const ThingPtr& toThing)
  627. {
  628. if(!canPerformGameAction() || !toThing)
  629. return;
  630. Position pos = Position(0xFFFF, 0, 0); // means that is a item in inventory
  631. if(toThing->isCreature())
  632. m_protocolGame->sendUseOnCreature(pos, itemId, 0, toThing->getId());
  633. else
  634. m_protocolGame->sendUseItemWith(pos, itemId, 0, toThing->getPosition(), toThing->getId(), toThing->getStackpos());
  635. }
  636. void Game::open(const ItemPtr& item, const ContainerPtr& previousContainer)
  637. {
  638. if(!canPerformGameAction() || !item)
  639. return;
  640. int id = 0;
  641. if(!previousContainer)
  642. id = findEmptyContainerId();
  643. else
  644. id = previousContainer->getId();
  645. m_protocolGame->sendUseItem(item->getPosition(), item->getId(), item->getStackpos(), id);
  646. }
  647. void Game::openParent(const ContainerPtr& container)
  648. {
  649. if(!canPerformGameAction() || !container)
  650. return;
  651. m_protocolGame->sendUpContainer(container->getId());
  652. }
  653. void Game::close(const ContainerPtr& container)
  654. {
  655. if(!canPerformGameAction() || !container)
  656. return;
  657. m_protocolGame->sendCloseContainer(container->getId());
  658. }
  659. void Game::refreshContainer(const ContainerPtr& container)
  660. {
  661. if(!canPerformGameAction())
  662. return;
  663. m_protocolGame->sendRefreshContainer(container->getId());
  664. }
  665. void Game::attack(CreaturePtr creature)
  666. {
  667. if(!canPerformGameAction() || creature == m_localPlayer)
  668. return;
  669. // cancel when attacking again
  670. if(creature && creature == m_attackingCreature)
  671. creature = nullptr;
  672. if(creature && isFollowing())
  673. cancelFollow();
  674. setAttackingCreature(creature);
  675. if(m_protocolVersion >= 963) {
  676. if(creature)
  677. m_seq = creature->getId();
  678. } else
  679. m_seq++;
  680. m_protocolGame->sendAttack(creature ? creature->getId() : 0, m_seq);
  681. }
  682. void Game::follow(CreaturePtr creature)
  683. {
  684. if(!canPerformGameAction() || creature == m_localPlayer)
  685. return;
  686. // cancel when following again
  687. if(creature && creature == m_followingCreature)
  688. creature = nullptr;
  689. if(creature && isAttacking())
  690. cancelAttack();
  691. setFollowingCreature(creature);
  692. if(m_protocolVersion >= 963) {
  693. if(creature)
  694. m_seq = creature->getId();
  695. } else
  696. m_seq++;
  697. m_protocolGame->sendFollow(creature ? creature->getId() : 0, m_seq);
  698. }
  699. void Game::cancelAttackAndFollow()
  700. {
  701. if(!canPerformGameAction())
  702. return;
  703. m_protocolGame->sendCancelAttackAndFollow();
  704. }
  705. void Game::talk(const std::string& message)
  706. {
  707. if(!canPerformGameAction() || message.empty())
  708. return;
  709. talkChannel(Otc::MessageSay, 0, message);
  710. }
  711. void Game::talkChannel(Otc::MessageMode mode, int channelId, const std::string& message)
  712. {
  713. if(!canPerformGameAction() || message.empty())
  714. return;
  715. m_protocolGame->sendTalk(mode, channelId, "", message);
  716. }
  717. void Game::talkPrivate(Otc::MessageMode mode, const std::string& receiver, const std::string& message)
  718. {
  719. if(!canPerformGameAction() || receiver.empty() || message.empty())
  720. return;
  721. m_protocolGame->sendTalk(mode, 0, receiver, message);
  722. }
  723. void Game::openPrivateChannel(const std::string& receiver)
  724. {
  725. if(!canPerformGameAction() || receiver.empty())
  726. return;
  727. m_protocolGame->sendOpenPrivateChannel(receiver);
  728. }
  729. void Game::requestChannels()
  730. {
  731. if(!canPerformGameAction())
  732. return;
  733. m_protocolGame->sendRequestChannels();
  734. }
  735. void Game::joinChannel(int channelId)
  736. {
  737. if(!canPerformGameAction())
  738. return;
  739. m_protocolGame->sendJoinChannel(channelId);
  740. }
  741. void Game::leaveChannel(int channelId)
  742. {
  743. if(!canPerformGameAction())
  744. return;
  745. m_protocolGame->sendLeaveChannel(channelId);
  746. }
  747. void Game::closeNpcChannel()
  748. {
  749. if(!canPerformGameAction())
  750. return;
  751. m_protocolGame->sendCloseNpcChannel();
  752. }
  753. void Game::openOwnChannel()
  754. {
  755. if(!canPerformGameAction())
  756. return;
  757. m_protocolGame->sendOpenOwnChannel();
  758. }
  759. void Game::inviteToOwnChannel(const std::string& name)
  760. {
  761. if(!canPerformGameAction() || name.empty())
  762. return;
  763. m_protocolGame->sendInviteToOwnChannel(name);
  764. }
  765. void Game::excludeFromOwnChannel(const std::string& name)
  766. {
  767. if(!canPerformGameAction() || name.empty())
  768. return;
  769. m_protocolGame->sendExcludeFromOwnChannel(name);
  770. }
  771. void Game::partyInvite(int creatureId)
  772. {
  773. if(!canPerformGameAction())
  774. return;
  775. m_protocolGame->sendInviteToParty(creatureId);
  776. }
  777. void Game::partyJoin(int creatureId)
  778. {
  779. if(!canPerformGameAction())
  780. return;
  781. m_protocolGame->sendJoinParty(creatureId);
  782. }
  783. void Game::partyRevokeInvitation(int creatureId)
  784. {
  785. if(!canPerformGameAction())
  786. return;
  787. m_protocolGame->sendRevokeInvitation(creatureId);
  788. }
  789. void Game::partyPassLeadership(int creatureId)
  790. {
  791. if(!canPerformGameAction())
  792. return;
  793. m_protocolGame->sendPassLeadership(creatureId);
  794. }
  795. void Game::partyLeave()
  796. {
  797. if(!canPerformGameAction())
  798. return;
  799. m_protocolGame->sendLeaveParty();
  800. }
  801. void Game::partyShareExperience(bool active)
  802. {
  803. if(!canPerformGameAction())
  804. return;
  805. m_protocolGame->sendShareExperience(active);
  806. }
  807. void Game::requestOutfit()
  808. {
  809. if(!canPerformGameAction())
  810. return;
  811. m_protocolGame->sendRequestOutfit();
  812. }
  813. void Game::changeOutfit(const Outfit& outfit)
  814. {
  815. if(!canPerformGameAction())
  816. return;
  817. m_protocolGame->sendChangeOutfit(outfit);
  818. }
  819. void Game::addVip(const std::string& name)
  820. {
  821. if(!canPerformGameAction() || name.empty())
  822. return;
  823. m_protocolGame->sendAddVip(name);
  824. }
  825. void Game::removeVip(int playerId)
  826. {
  827. if(!canPerformGameAction())
  828. return;
  829. m_protocolGame->sendRemoveVip(playerId);
  830. }
  831. void Game::setChaseMode(Otc::ChaseModes chaseMode)
  832. {
  833. if(!canPerformGameAction())
  834. return;
  835. if(m_chaseMode == chaseMode)
  836. return;
  837. m_chaseMode = chaseMode;
  838. m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight);
  839. g_lua.callGlobalField("g_game", "onChaseModeChange", chaseMode);
  840. }
  841. void Game::setFightMode(Otc::FightModes fightMode)
  842. {
  843. if(!canPerformGameAction())
  844. return;
  845. if(m_fightMode == fightMode)
  846. return;
  847. m_fightMode = fightMode;
  848. m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight);
  849. g_lua.callGlobalField("g_game", "onFightModeChange", fightMode);
  850. }
  851. void Game::setSafeFight(bool on)
  852. {
  853. if(!canPerformGameAction())
  854. return;
  855. if(m_safeFight == on)
  856. return;
  857. m_safeFight = on;
  858. m_protocolGame->sendChangeFightModes(m_fightMode, m_chaseMode, m_safeFight);
  859. g_lua.callGlobalField("g_game", "onSafeFightChange", on);
  860. }
  861. void Game::inspectNpcTrade(const ItemPtr& item)
  862. {
  863. if(!canPerformGameAction() || !item)
  864. return;
  865. m_protocolGame->sendInspectNpcTrade(item->getId(), item->getCount());
  866. }
  867. void Game::buyItem(const ItemPtr& item, int amount, bool ignoreCapacity, bool buyWithBackpack)
  868. {
  869. if(!canPerformGameAction() || !item)
  870. return;
  871. m_protocolGame->sendBuyItem(item->getId(), item->getCountOrSubType(), amount, ignoreCapacity, buyWithBackpack);
  872. }
  873. void Game::sellItem(const ItemPtr& item, int amount, bool ignoreEquipped)
  874. {
  875. if(!canPerformGameAction() || !item)
  876. return;
  877. m_protocolGame->sendSellItem(item->getId(), item->getSubType(), amount, ignoreEquipped);
  878. }
  879. void Game::closeNpcTrade()
  880. {
  881. if(!canPerformGameAction())
  882. return;
  883. m_protocolGame->sendCloseNpcTrade();
  884. }
  885. void Game::requestTrade(const ItemPtr& item, const CreaturePtr& creature)
  886. {
  887. if(!canPerformGameAction() || !item || !creature)
  888. return;
  889. m_protocolGame->sendRequestTrade(item->getPosition(), item->getId(), item->getStackpos(), creature->getId());
  890. }
  891. void Game::inspectTrade(bool counterOffer, int index)
  892. {
  893. if(!canPerformGameAction())
  894. return;
  895. m_protocolGame->sendInspectTrade(counterOffer, index);
  896. }
  897. void Game::acceptTrade()
  898. {
  899. if(!canPerformGameAction())
  900. return;
  901. m_protocolGame->sendAcceptTrade();
  902. }
  903. void Game::rejectTrade()
  904. {
  905. if(!canPerformGameAction())
  906. return;
  907. m_protocolGame->sendRejectTrade();
  908. }
  909. void Game::editText(uint id, const std::string& text)
  910. {
  911. if(!canPerformGameAction())
  912. return;
  913. m_protocolGame->sendEditText(id, text);
  914. }
  915. void Game::editList(uint id, int doorId, const std::string& text)
  916. {
  917. if(!canPerformGameAction())
  918. return;
  919. m_protocolGame->sendEditList(id, doorId, text);
  920. }
  921. void Game::reportBug(const std::string& comment)
  922. {
  923. if(!canPerformGameAction())
  924. return;
  925. m_protocolGame->sendBugReport(comment);
  926. }
  927. void Game::reportRuleViolation(const std::string& target, int reason, int action, const std::string& comment, const std::string& statement, int statementId, bool ipBanishment)
  928. {
  929. if(!canPerformGameAction())
  930. return;
  931. m_protocolGame->sendRuleViolation(target, reason, action, comment, statement, statementId, ipBanishment);
  932. }
  933. void Game::debugReport(const std::string& a, const std::string& b, const std::string& c, const std::string& d)
  934. {
  935. m_protocolGame->sendDebugReport(a, b, c, d);
  936. }
  937. void Game::requestQuestLog()
  938. {
  939. if(!canPerformGameAction())
  940. return;
  941. m_protocolGame->sendRequestQuestLog();
  942. }
  943. void Game::requestQuestLine(int questId)
  944. {
  945. if(!canPerformGameAction())
  946. return;
  947. m_protocolGame->sendRequestQuestLine(questId);
  948. }
  949. void Game::equipItem(const ItemPtr& item)
  950. {
  951. if(!canPerformGameAction())
  952. return;
  953. m_protocolGame->sendEquipItem(item->getId(), item->getCountOrSubType());
  954. }
  955. void Game::mount(bool mount)
  956. {
  957. if(!canPerformGameAction())
  958. return;
  959. m_protocolGame->sendMountStatus(mount);
  960. }
  961. void Game::requestItemInfo(const ItemPtr& item, int index)
  962. {
  963. if(!canPerformGameAction())
  964. return;
  965. m_protocolGame->sendRequestItemInfo(item->getId(), item->getSubType(), index);
  966. }
  967. void Game::answerModalDialog(int dialog, int button, int choice)
  968. {
  969. if(!canPerformGameAction())
  970. return;
  971. m_protocolGame->sendAnswerModalDialog(dialog, button, choice);
  972. }
  973. void Game::ping()
  974. {
  975. if(!m_protocolGame || !m_protocolGame->isConnected())
  976. return;
  977. m_denyBotCall = false;
  978. m_protocolGame->sendPing();
  979. m_denyBotCall = true;
  980. }
  981. bool Game::checkBotProtection()
  982. {
  983. #ifdef BOT_PROTECTION
  984. // accepts calls comming from a stacktrace containing only C++ functions,
  985. // if the stacktrace contains a lua function, then only accept if the engine is processing an input event
  986. if(m_denyBotCall && g_lua.isInCppCallback() && !g_app.isOnInputEvent()) {
  987. g_logger.error(g_lua.traceback("caught a lua call to a bot protected game function, the call was cancelled"));
  988. return false;
  989. }
  990. #endif
  991. return true;
  992. }
  993. bool Game::canPerformGameAction()
  994. {
  995. // we can only perform game actions if we meet these conditions:
  996. // - the game is online
  997. // - the local player exists
  998. // - the local player is not dead
  999. // - we have a game protocol
  1000. // - the game protocol is connected
  1001. // - its not a bot action
  1002. return m_online && m_localPlayer && !m_dead && m_protocolGame && m_protocolGame->isConnected() && checkBotProtection();
  1003. }
  1004. void Game::setProtocolVersion(int version)
  1005. {
  1006. if(m_protocolVersion == version)
  1007. return;
  1008. if(isOnline())
  1009. stdext::throw_exception("Unable to change protocol version while online");
  1010. if(version != 0 && (version < 810 || version > 973))
  1011. stdext::throw_exception(stdext::format("Protocol version %d not supported", version));
  1012. m_features.reset();
  1013. enableFeature(Otc::GameFormatCreatureName);
  1014. if(version <= 854) {
  1015. enableFeature(Otc::GameChargeableItems);
  1016. }
  1017. if(version >= 854) {
  1018. enableFeature(Otc::GameProtocolChecksum);
  1019. enableFeature(Otc::GameAccountNames);
  1020. enableFeature(Otc::GameChallangeOnLogin);
  1021. enableFeature(Otc::GameDoubleFreeCapacity);
  1022. enableFeature(Otc::GameCreatureEmblems);
  1023. }
  1024. if(version >= 862) {
  1025. enableFeature(Otc::GamePenalityOnDeath);
  1026. }
  1027. if(version >= 870) {
  1028. enableFeature(Otc::GameDoubleExperience);
  1029. enableFeature(Otc::GamePlayerMounts);
  1030. enableFeature(Otc::GameSpellList);
  1031. }
  1032. if(version >= 910) {
  1033. enableFeature(Otc::GameNameOnNpcTrade);
  1034. enableFeature(Otc::GameTotalCapacity);
  1035. enableFeature(Otc::GameSkillsBase);
  1036. enableFeature(Otc::GamePlayerRegenerationTime);
  1037. enableFeature(Otc::GameChannelPlayerList);
  1038. enableFeature(Otc::GameEnvironmentEffect);
  1039. enableFeature(Otc::GameItemAnimationPhase);
  1040. }
  1041. if(version >= 940) {
  1042. enableFeature(Otc::GamePlayerMarket);
  1043. }
  1044. if(version >= 953) {
  1045. enableFeature(Otc::GamePurseSlot);
  1046. enableFeature(Otc::GameClientPing);
  1047. }
  1048. if(version >= 960) {
  1049. enableFeature(Otc::GameSpritesU32);
  1050. enableFeature(Otc::GameOfflineTrainingTime);
  1051. }
  1052. if(version >= 973) {
  1053. enableFeature(Otc::GameLoginPending);
  1054. enableFeature(Otc::GameNewSpeedLaw);
  1055. }
  1056. m_protocolVersion = version;
  1057. Proto::buildMessageModesMap(version);
  1058. g_lua.callGlobalField("g_game", "onProtocolVersionChange", version);
  1059. }
  1060. void Game::setClientVersion(int version)
  1061. {
  1062. if(m_clientVersion == version)
  1063. return;
  1064. if(isOnline())
  1065. stdext::throw_exception("Unable to change client version while online");
  1066. if(version != 0 && (version < 810 || version > 981))
  1067. stdext::throw_exception(stdext::format("Client version %d not supported", version));
  1068. m_clientVersion = version;
  1069. g_lua.callGlobalField("g_game", "onClientVersionChange", version);
  1070. }
  1071. void Game::setAttackingCreature(const CreaturePtr& creature)
  1072. {
  1073. CreaturePtr oldCreature = m_attackingCreature;
  1074. m_attackingCreature = creature;
  1075. g_lua.callGlobalField("g_game", "onAttackingCreatureChange", creature, oldCreature);
  1076. }
  1077. void Game::setFollowingCreature(const CreaturePtr& creature)
  1078. {
  1079. CreaturePtr oldCreature = m_followingCreature;
  1080. m_followingCreature = creature;
  1081. g_lua.callGlobalField("g_game", "onFollowingCreatureChange", creature, oldCreature);
  1082. }
  1083. std::string Game::formatCreatureName(const std::string& name)
  1084. {
  1085. std::string formatedName = name;
  1086. if(getFeature(Otc::GameFormatCreatureName) && name.length() > 0)
  1087. formatedName[0] = stdext::upchar(formatedName[0]);
  1088. return formatedName;
  1089. }
  1090. int Game::findEmptyContainerId()
  1091. {
  1092. int id = 0;
  1093. while(m_containers[id] != nullptr)
  1094. id++;
  1095. return id;
  1096. }