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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  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 "statictext.h"
  28. #include <framework/core/eventdispatcher.h>
  29. #include <framework/ui/uimanager.h>
  30. #include <otclient/luascript/luavaluecasts.h>
  31. #include <otclient/net/protocolgame.h>
  32. Game g_game;
  33. void Game::loginWorld(const std::string& account, const std::string& password, const std::string& worldHost, int worldPort, const std::string& characterName)
  34. {
  35. m_dead = false;
  36. m_protocolGame = ProtocolGamePtr(new ProtocolGame);
  37. m_protocolGame->login(account, password, worldHost, (uint16)worldPort, characterName);
  38. }
  39. void Game::cancelLogin()
  40. {
  41. processLogout();
  42. }
  43. void Game::logout(bool force)
  44. {
  45. if(!m_protocolGame || !isOnline())
  46. return;
  47. m_protocolGame->sendLogout();
  48. if(force)
  49. processLogout();
  50. }
  51. void Game::processLoginError(const std::string& error)
  52. {
  53. g_lua.callGlobalField("Game", "onLoginError", error);
  54. }
  55. void Game::processConnectionError(const boost::system::error_code& error)
  56. {
  57. // connection errors only have meaning if we still have a protocol
  58. if(m_protocolGame) {
  59. if(error != asio::error::eof)
  60. g_lua.callGlobalField("Game", "onConnectionError", error.message());
  61. processLogout();
  62. }
  63. }
  64. void Game::processGameStart(const LocalPlayerPtr& localPlayer, int serverBeat)
  65. {
  66. m_localPlayer = localPlayer;
  67. m_serverBeat = serverBeat;
  68. // synchronize fight modes with the server
  69. m_fightMode = Otc::FightBalanced;
  70. m_chaseMode = Otc::DontChase;
  71. m_safeFight = true;
  72. m_protocolGame->sendFightTatics(m_fightMode, m_chaseMode, m_safeFight);
  73. // NOTE: the entire map description and local player informations is not known yet
  74. g_lua.callGlobalField("Game", "onGameStart");
  75. }
  76. void Game::processLogin()
  77. {
  78. if(!isOnline())
  79. return;
  80. g_lua.callGlobalField("Game", "onLogin", m_localPlayer);
  81. }
  82. void Game::processLogout()
  83. {
  84. if(isOnline()) {
  85. g_lua.callGlobalField("Game", "onLogout", m_localPlayer);
  86. m_localPlayer = nullptr;
  87. g_lua.callGlobalField("Game", "onGameEnd");
  88. }
  89. if(m_protocolGame) {
  90. m_protocolGame->disconnect();
  91. m_protocolGame = nullptr;
  92. }
  93. //g_map.save();
  94. }
  95. void Game::processDeath()
  96. {
  97. m_dead = true;
  98. m_localPlayer->stopWalk();
  99. g_lua.callGlobalField("Game","onDeath");
  100. }
  101. void Game::processPlayerStats(double health, double maxHealth,
  102. double freeCapacity, double experience,
  103. double level, double levelPercent,
  104. double mana, double maxMana,
  105. double magicLevel, double magicLevelPercent,
  106. double soul, double stamina)
  107. {
  108. if(m_localPlayer->getHealth() != health ||
  109. m_localPlayer->getMaxHealth() != maxHealth) {
  110. m_localPlayer->setStatistic(Otc::Health, health);
  111. m_localPlayer->setStatistic(Otc::MaxHealth, maxHealth);
  112. g_lua.callGlobalField("Game", "onHealthChange", health, maxHealth);
  113. // cannot walk while dying
  114. if(health == 0) {
  115. if(m_localPlayer->isPreWalking())
  116. m_localPlayer->stopWalk();
  117. m_localPlayer->lockWalk();
  118. }
  119. }
  120. if(m_localPlayer->getStatistic(Otc::FreeCapacity) != freeCapacity) {
  121. m_localPlayer->setStatistic(Otc::FreeCapacity, freeCapacity);
  122. g_lua.callGlobalField("Game", "onFreeCapacityChange", freeCapacity);
  123. }
  124. if(m_localPlayer->getStatistic(Otc::Experience) != experience) {
  125. m_localPlayer->setStatistic(Otc::Experience, experience);
  126. g_lua.callGlobalField("Game", "onExperienceChange", experience);
  127. }
  128. if(m_localPlayer->getStatistic(Otc::Level) != level ||
  129. m_localPlayer->getStatistic(Otc::LevelPercent) != levelPercent) {
  130. m_localPlayer->setStatistic(Otc::Level, level);
  131. m_localPlayer->setStatistic(Otc::LevelPercent, levelPercent);
  132. g_lua.callGlobalField("Game", "onLevelChange", level, levelPercent);
  133. }
  134. if(m_localPlayer->getStatistic(Otc::Mana) != mana ||
  135. m_localPlayer->getStatistic(Otc::MaxMana) != maxMana) {
  136. m_localPlayer->setStatistic(Otc::Mana, mana);
  137. m_localPlayer->setStatistic(Otc::MaxMana, maxMana);
  138. g_lua.callGlobalField("Game", "onManaChange", mana, maxMana);
  139. }
  140. if(m_localPlayer->getStatistic(Otc::MagicLevel) != magicLevel ||
  141. m_localPlayer->getStatistic(Otc::MagicLevelPercent) != magicLevelPercent) {
  142. m_localPlayer->setStatistic(Otc::MagicLevel, magicLevel);
  143. m_localPlayer->setStatistic(Otc::MagicLevelPercent, magicLevelPercent);
  144. g_lua.callGlobalField("Game", "onMagicLevelChange", magicLevel, magicLevelPercent);
  145. }
  146. if(m_localPlayer->getStatistic(Otc::Soul) != soul) {
  147. m_localPlayer->setStatistic(Otc::Soul, soul);
  148. g_lua.callGlobalField("Game", "onSoulChange", soul);
  149. }
  150. if(m_localPlayer->getStatistic(Otc::Stamina) != stamina) {
  151. m_localPlayer->setStatistic(Otc::Stamina, stamina);
  152. g_lua.callGlobalField("Game", "onStaminaChange", stamina);
  153. }
  154. }
  155. void Game::processTextMessage(const std::string& type, const std::string& message)
  156. {
  157. g_lua.callGlobalField("Game","onTextMessage", type, message);
  158. }
  159. void Game::processCreatureSpeak(const std::string& name, int level, Otc::SpeakType type, const std::string& message, int channelId, const Position& creaturePos)
  160. {
  161. if(creaturePos.isValid() && (type == Otc::SpeakSay || type == Otc::SpeakWhisper || type == Otc::SpeakYell || type == Otc::SpeakMonsterSay || type == Otc::SpeakMonsterYell)) {
  162. StaticTextPtr staticText = StaticTextPtr(new StaticText);
  163. staticText->addMessage(name, type, message);
  164. g_map.addThing(staticText, creaturePos);
  165. }
  166. g_lua.callGlobalField("Game", "onCreatureSpeak", name, level, type, message, channelId, creaturePos);
  167. }
  168. void Game::processContainerAddItem(int containerId, const ItemPtr& item)
  169. {
  170. if(item)
  171. item->setPosition(Position(65535, containerId + 0x40, 0));
  172. g_lua.callGlobalField("Game", "onContainerAddItem", containerId, item);
  173. }
  174. void Game::processInventoryChange(int slot, const ItemPtr& item)
  175. {
  176. if(item)
  177. item->setPosition(Position(65535, slot, 0));
  178. g_lua.callGlobalField("Game","onInventoryChange", slot, item);
  179. }
  180. void Game::processCreatureMove(const CreaturePtr& creature, const Position& oldPos, const Position& newPos)
  181. {
  182. // animate walk
  183. if(oldPos.isInRange(newPos, 1, 1))
  184. creature->walk(oldPos, newPos);
  185. }
  186. void Game::processCreatureTeleport(const CreaturePtr& creature)
  187. {
  188. // stop walking on creature teleports
  189. creature->stopWalk();
  190. if(creature == m_localPlayer)
  191. m_localPlayer->lockWalk();
  192. }
  193. void Game::processAttackCancel()
  194. {
  195. if(m_localPlayer->isAttacking())
  196. m_localPlayer->setAttackingCreature(nullptr);
  197. }
  198. void Game::processWalkCancel(Otc::Direction direction)
  199. {
  200. m_localPlayer->cancelWalk(direction);
  201. }
  202. void Game::walk(Otc::Direction direction)
  203. {
  204. if(!isOnline() || !m_localPlayer->isKnown() || isDead() || !checkBotProtection())
  205. return;
  206. if(m_localPlayer->isFollowing())
  207. cancelFollow();
  208. if(!m_localPlayer->canWalk(direction))
  209. return;
  210. // only do prewalks to walkable tiles
  211. TilePtr toTile = g_map.getTile(m_localPlayer->getPosition().translatedToDirection(direction));
  212. if(toTile && toTile->isWalkable())
  213. m_localPlayer->preWalk(direction);
  214. else
  215. m_localPlayer->lockWalk();
  216. forceWalk(direction);
  217. }
  218. void Game::forceWalk(Otc::Direction direction)
  219. {
  220. if(!isOnline() || !checkBotProtection())
  221. return;
  222. switch(direction) {
  223. case Otc::North:
  224. m_protocolGame->sendWalkNorth();
  225. break;
  226. case Otc::East:
  227. m_protocolGame->sendWalkEast();
  228. break;
  229. case Otc::South:
  230. m_protocolGame->sendWalkSouth();
  231. break;
  232. case Otc::West:
  233. m_protocolGame->sendWalkWest();
  234. break;
  235. case Otc::NorthEast:
  236. m_protocolGame->sendWalkNorthEast();
  237. break;
  238. case Otc::SouthEast:
  239. m_protocolGame->sendWalkSouthEast();
  240. break;
  241. case Otc::SouthWest:
  242. m_protocolGame->sendWalkSouthWest();
  243. break;
  244. case Otc::NorthWest:
  245. m_protocolGame->sendWalkNorthWest();
  246. break;
  247. }
  248. }
  249. void Game::turn(Otc::Direction direction)
  250. {
  251. if(!isOnline())
  252. return;
  253. switch(direction) {
  254. case Otc::North:
  255. m_protocolGame->sendTurnNorth();
  256. break;
  257. case Otc::East:
  258. m_protocolGame->sendTurnEast();
  259. break;
  260. case Otc::South:
  261. m_protocolGame->sendTurnSouth();
  262. break;
  263. case Otc::West:
  264. m_protocolGame->sendTurnWest();
  265. break;
  266. }
  267. }
  268. void Game::look(const ThingPtr& thing)
  269. {
  270. if(!isOnline() || !thing || !checkBotProtection())
  271. return;
  272. m_protocolGame->sendLookAt(thing->getPosition(), thing->getId(), thing->getStackpos());
  273. }
  274. void Game::open(const ItemPtr& item, int containerId)
  275. {
  276. if(!isOnline() || !item || !checkBotProtection())
  277. return;
  278. m_protocolGame->sendUseItem(item->getPosition(), item->getId(), item->getStackpos(), containerId);
  279. }
  280. void Game::use(const ThingPtr& thing)
  281. {
  282. if(!isOnline() || !thing || !checkBotProtection())
  283. return;
  284. Position pos = thing->getPosition();
  285. if(!pos.isValid()) // virtual item
  286. pos = Position(0xFFFF, 0, 0); // means that is a item in inventory
  287. m_localPlayer->lockWalk();
  288. m_protocolGame->sendUseItem(pos, thing->getId(), thing->getStackpos(), 0);
  289. }
  290. void Game::useInventoryItem(int itemId)
  291. {
  292. if(!isOnline() || !checkBotProtection())
  293. return;
  294. Position pos = Position(0xFFFF, 0, 0); // means that is a item in inventory
  295. m_localPlayer->lockWalk();
  296. m_protocolGame->sendUseItem(pos, itemId, 0, 0);
  297. }
  298. void Game::useWith(const ItemPtr& item, const ThingPtr& toThing)
  299. {
  300. if(!isOnline() || !item || !toThing || !checkBotProtection())
  301. return;
  302. Position pos = item->getPosition();
  303. if(!pos.isValid()) // virtual item
  304. pos = Position(0xFFFF, 0, 0); // means that is a item in inventory
  305. m_localPlayer->lockWalk();
  306. if(CreaturePtr creature = toThing->asCreature())
  307. m_protocolGame->sendUseOnCreature(pos, item->getId(), item->getStackpos(), creature->getId());
  308. else
  309. m_protocolGame->sendUseItemEx(pos, item->getId(), item->getStackpos(), toThing->getPosition(), toThing->getId(), toThing->getStackpos());
  310. }
  311. void Game::useInventoryItemWith(int itemId, const ThingPtr& toThing)
  312. {
  313. if(!isOnline() || !toThing || !checkBotProtection())
  314. return;
  315. m_localPlayer->lockWalk();
  316. Position pos = Position(0xFFFF, 0, 0); // means that is a item in inventory
  317. if(CreaturePtr creature = toThing->asCreature())
  318. m_protocolGame->sendUseOnCreature(pos, itemId, 0, creature->getId());
  319. else
  320. m_protocolGame->sendUseItemEx(pos, itemId, 0, toThing->getPosition(), toThing->getId(), toThing->getStackpos());
  321. }
  322. void Game::move(const ThingPtr& thing, const Position& toPos, int count)
  323. {
  324. if(!isOnline() || !thing || !checkBotProtection() || thing->getPosition() == toPos || count <= 0)
  325. return;
  326. m_localPlayer->lockWalk();
  327. m_protocolGame->sendThrow(thing->getPosition(), thing->getId(), thing->getStackpos(), toPos, count);
  328. }
  329. void Game::setChaseMode(Otc::ChaseModes chaseMode)
  330. {
  331. if(!isOnline() || !checkBotProtection())
  332. return;
  333. m_chaseMode = chaseMode;
  334. m_protocolGame->sendFightTatics(m_fightMode, m_chaseMode, m_safeFight);
  335. }
  336. void Game::setFightMode(Otc::FightModes fightMode)
  337. {
  338. if(!isOnline() || !checkBotProtection())
  339. return;
  340. m_fightMode = fightMode;
  341. m_protocolGame->sendFightTatics(m_fightMode, m_chaseMode, m_safeFight);
  342. }
  343. void Game::setSafeFight(bool on)
  344. {
  345. if(!isOnline() || !checkBotProtection())
  346. return;
  347. m_safeFight = on;
  348. m_protocolGame->sendFightTatics(m_fightMode, m_chaseMode, m_safeFight);
  349. }
  350. void Game::attack(const CreaturePtr& creature)
  351. {
  352. if(!isOnline() || !creature || !checkBotProtection())
  353. return;
  354. m_localPlayer->lockWalk();
  355. if(m_localPlayer->isFollowing())
  356. cancelFollow();
  357. m_localPlayer->setAttackingCreature(creature);
  358. m_protocolGame->sendAttack(creature->getId());
  359. }
  360. void Game::cancelAttack()
  361. {
  362. m_localPlayer->lockWalk();
  363. m_localPlayer->setAttackingCreature(nullptr);
  364. m_protocolGame->sendAttack(0);
  365. }
  366. void Game::follow(const CreaturePtr& creature)
  367. {
  368. if(!isOnline() || !creature || !checkBotProtection())
  369. return;
  370. if(m_localPlayer->isAttacking())
  371. cancelAttack();
  372. m_localPlayer->setFollowingCreature(creature);
  373. m_protocolGame->sendFollow(creature->getId());
  374. }
  375. void Game::cancelFollow()
  376. {
  377. if(!isOnline() || !checkBotProtection())
  378. return;
  379. m_localPlayer->setFollowingCreature(nullptr);
  380. m_protocolGame->sendFollow(0);
  381. }
  382. void Game::rotate(const ThingPtr& thing)
  383. {
  384. if(!isOnline() || !thing || !checkBotProtection())
  385. return;
  386. m_protocolGame->sendRotateItem(thing->getPosition(), thing->getId(), thing->getStackpos());
  387. }
  388. void Game::talk(const std::string& message)
  389. {
  390. talkChannel(Otc::SpeakSay, 0, message);
  391. }
  392. void Game::talkChannel(Otc::SpeakType speakType, int channelId, const std::string& message)
  393. {
  394. if(!isOnline() || !checkBotProtection())
  395. return;
  396. m_protocolGame->sendTalk(speakType, channelId, "", message);
  397. }
  398. void Game::talkPrivate(Otc::SpeakType speakType, const std::string& receiver, const std::string& message)
  399. {
  400. if(!isOnline() || !checkBotProtection())
  401. return;
  402. m_protocolGame->sendTalk(speakType, 0, receiver, message);
  403. }
  404. void Game::openPrivateChannel(const std::string& receiver)
  405. {
  406. if(!isOnline() || !checkBotProtection())
  407. return;
  408. m_protocolGame->sendOpenPrivateChannel(receiver);
  409. }
  410. void Game::requestChannels()
  411. {
  412. if(!isOnline() || !checkBotProtection())
  413. return;
  414. m_protocolGame->sendGetChannels();
  415. }
  416. void Game::joinChannel(int channelId)
  417. {
  418. if(!isOnline() || !checkBotProtection())
  419. return;
  420. m_protocolGame->sendJoinChannel(channelId);
  421. }
  422. void Game::leaveChannel(int channelId)
  423. {
  424. if(!isOnline() || !checkBotProtection())
  425. return;
  426. m_protocolGame->sendLeaveChannel(channelId);
  427. }
  428. void Game::closeNpcChannel()
  429. {
  430. if(!isOnline() || !checkBotProtection())
  431. return;
  432. m_protocolGame->sendCloseNpcChannel();
  433. }
  434. void Game::partyInvite(int creatureId)
  435. {
  436. if(!isOnline() || !checkBotProtection())
  437. return;
  438. m_protocolGame->sendInviteToParty(creatureId);
  439. }
  440. void Game::partyJoin(int creatureId)
  441. {
  442. if(!isOnline() || !checkBotProtection())
  443. return;
  444. m_protocolGame->sendJoinParty(creatureId);
  445. }
  446. void Game::partyRevokeInvitation(int creatureId)
  447. {
  448. if(!isOnline() || !checkBotProtection())
  449. return;
  450. m_protocolGame->sendRevokeInvitation(creatureId);
  451. }
  452. void Game::partyPassLeadership(int creatureId)
  453. {
  454. if(!isOnline() || !checkBotProtection())
  455. return;
  456. m_protocolGame->sendPassLeadership(creatureId);
  457. }
  458. void Game::partyLeave()
  459. {
  460. if(!isOnline() || !checkBotProtection())
  461. return;
  462. m_protocolGame->sendLeaveParty();
  463. }
  464. void Game::partyShareExperience(bool active)
  465. {
  466. if(!isOnline() || !checkBotProtection())
  467. return;
  468. m_protocolGame->sendShareExperience(active, 0);
  469. }
  470. void Game::requestOutfit()
  471. {
  472. if(!isOnline() || !checkBotProtection())
  473. return;
  474. m_protocolGame->sendGetOutfit();
  475. }
  476. void Game::setOutfit(const Outfit& outfit)
  477. {
  478. if(!isOnline() || !checkBotProtection())
  479. return;
  480. m_protocolGame->sendSetOutfit(outfit);
  481. }
  482. void Game::addVip(const std::string& name)
  483. {
  484. if(!isOnline() || name.empty() || !checkBotProtection())
  485. return;
  486. m_protocolGame->sendAddVip(name);
  487. }
  488. void Game::removeVip(int playerId)
  489. {
  490. if(!isOnline() || !checkBotProtection())
  491. return;
  492. m_protocolGame->sendRemoveVip(playerId);
  493. }
  494. bool Game::checkBotProtection()
  495. {
  496. #ifdef BOT_PROTECTION
  497. if(g_lua.isInCppCallback() && !g_ui.isOnInputEvent()) {
  498. logError("caught a lua call to a bot protected game function, the call was canceled");
  499. return false;
  500. }
  501. #endif
  502. return true;
  503. }