Advertisement
Guest User

Untitled

a guest
Nov 7th, 2012
295
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 167.95 KB | None | 0 0
  1. //////////////////////////////////////////////////////////////////////
  2. // OpenTibia - an opensource roleplaying game
  3. //////////////////////////////////////////////////////////////////////
  4. // class representing the gamestate
  5. //////////////////////////////////////////////////////////////////////
  6. // This program is free software; you can redistribute it and/or
  7. // modify it under the terms of the GNU General Public License
  8. // as published by the Free Software Foundation; either version 2
  9. // of the License, or (at your option) any later version.
  10. //
  11. // This program is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU General Public License
  17. // along with this program; if not, write to the Free Software Foundation,
  18. // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19. //////////////////////////////////////////////////////////////////////
  20. #include "otpch.h"
  21.  
  22. #include "definitions.h"
  23.  
  24. #include <string>
  25. #include <map>
  26. #include <fstream>
  27.  
  28. #include <boost/config.hpp>
  29. #include <boost/bind.hpp>
  30.  
  31. #include "otsystem.h"
  32. #include "tasks.h"
  33. #include "items.h"
  34. #include "commands.h"
  35. #include "creature.h"
  36. #include "player.h"
  37. #include "monster.h"
  38. #include "game.h"
  39. #include "tile.h"
  40. #include "house.h"
  41. #include "actions.h"
  42. #include "combat.h"
  43. #include "iologindata.h"
  44. #include "iomarket.h"
  45. #include "chat.h"
  46. #include "luascript.h"
  47. #include "talkaction.h"
  48. #include "spells.h"
  49. #include "configmanager.h"
  50. #include "ban.h"
  51. #include "raids.h"
  52. #include "database.h"
  53. #include "server.h"
  54. #include "ioguild.h"
  55. #include "quests.h"
  56. #include "globalevent.h"
  57. #include "mounts.h"
  58.  
  59. extern ConfigManager g_config;
  60. extern Actions* g_actions;
  61. extern Commands commands;
  62. extern Chat g_chat;
  63. extern TalkActions* g_talkActions;
  64. extern Spells* g_spells;
  65. extern Vocations g_vocations;
  66. extern GlobalEvents* g_globalEvents;
  67.  
  68. Game::Game()
  69. {
  70. gameState = GAME_STATE_NORMAL;
  71. worldType = WORLD_TYPE_PVP;
  72.  
  73. checkLightEvent = 0;
  74. checkCreatureEvent = 0;
  75. checkDecayEvent = 0;
  76.  
  77. map = NULL;
  78. lastStageLevel = 0;
  79. lastPlayersRecord = 0;
  80. useLastStageLevel = false;
  81. stagesEnabled = false;
  82. stateTime = OTSYS_TIME();
  83. for(int16_t i = 0; i < 3; i++)
  84. serverSaveMessage[i] = false;
  85.  
  86. OTSYS_THREAD_LOCKVARINIT(AutoID::autoIDLock);
  87.  
  88. #ifdef __EXCEPTION_TRACER__
  89. OTSYS_THREAD_LOCKVARINIT(maploadlock);
  90. #endif
  91.  
  92. lastBucket = 0;
  93.  
  94. //(1440 minutes/day)/(3600 seconds/day)*10 seconds event interval
  95. int32_t dayCycle = 3600;
  96. lightHourDelta = 1440 * 10 / dayCycle;
  97. lightHour = SUNRISE + (SUNSET - SUNRISE) / 2;
  98. lightLevel = LIGHT_LEVEL_DAY;
  99. lightState = LIGHT_STATE_DAY;
  100. }
  101.  
  102. Game::~Game()
  103. {
  104. blacklist.clear();
  105. whitelist.clear();
  106.  
  107. delete map;
  108.  
  109. g_scheduler.stopEvent(checkLightEvent);
  110. g_scheduler.stopEvent(checkCreatureEvent);
  111. g_scheduler.stopEvent(checkDecayEvent);
  112. }
  113.  
  114. void Game::start(ServiceManager* servicer)
  115. {
  116. services = servicer;
  117.  
  118. checkLightEvent = g_scheduler.addEvent(createSchedulerTask(EVENT_LIGHTINTERVAL,
  119. boost::bind(&Game::checkLight, this)));
  120.  
  121. checkCreatureLastIndex = 0;
  122. checkCreatureEvent = g_scheduler.addEvent(createSchedulerTask(EVENT_CREATURE_THINK_INTERVAL,
  123. boost::bind(&Game::checkCreatures, this)));
  124.  
  125. checkDecayEvent = g_scheduler.addEvent(createSchedulerTask(EVENT_DECAYINTERVAL,
  126. boost::bind(&Game::checkDecay, this)));
  127. }
  128.  
  129. GameState_t Game::getGameState() const
  130. {
  131. return gameState;
  132. }
  133.  
  134. void Game::setWorldType(WorldType_t type)
  135. {
  136. worldType = type;
  137. }
  138.  
  139. void Game::setGameState(GameState_t newState)
  140. {
  141. if(gameState == GAME_STATE_SHUTDOWN)
  142. return; //this cannot be stopped
  143.  
  144. if(gameState != newState)
  145. {
  146. gameState = newState;
  147.  
  148. switch(newState)
  149. {
  150. case GAME_STATE_INIT:
  151. {
  152. Spawns::getInstance()->startup();
  153.  
  154. Raids::getInstance()->loadFromXml();
  155. Raids::getInstance()->startup();
  156.  
  157. Quests::getInstance()->loadFromXml();
  158.  
  159. Mounts::getInstance()->loadFromXml();
  160.  
  161. loadStatuslist();
  162. loadMotd();
  163. loadPlayersRecord();
  164.  
  165. loadGameState();
  166. g_globalEvents->startup();
  167. break;
  168. }
  169.  
  170. case GAME_STATE_SHUTDOWN:
  171. {
  172. g_globalEvents->execute(GLOBALEVENT_SHUTDOWN);
  173. //kick all players that are still online
  174. AutoList<Player>::listiterator it = Player::listPlayer.list.begin();
  175. while(it != Player::listPlayer.list.end())
  176. {
  177. (*it).second->kickPlayer(true);
  178. it = Player::listPlayer.list.begin();
  179. }
  180.  
  181. saveGameState();
  182.  
  183. g_dispatcher.addTask(
  184. createTask(boost::bind(&Game::shutdown, this)));
  185.  
  186. g_scheduler.stop();
  187. g_dispatcher.stop();
  188. break;
  189. }
  190.  
  191. case GAME_STATE_CLOSED:
  192. {
  193. /* kick all players without the CanAlwaysLogin flag */
  194. AutoList<Player>::listiterator it = Player::listPlayer.list.begin();
  195. while(it != Player::listPlayer.list.end())
  196. {
  197. if(!(*it).second->hasFlag(PlayerFlag_CanAlwaysLogin))
  198. {
  199. (*it).second->kickPlayer(true);
  200. it = Player::listPlayer.list.begin();
  201. }
  202. else
  203. ++it;
  204. }
  205.  
  206. Houses::getInstance().payHouses();
  207. saveGameState();
  208. break;
  209. }
  210.  
  211. default:
  212. break;
  213. }
  214. }
  215. }
  216.  
  217. void Game::saveGameState()
  218. {
  219. if(gameState == GAME_STATE_NORMAL)
  220. setGameState(GAME_STATE_MAINTAIN);
  221.  
  222. stateTime = 0;
  223. std::cout << "Saving server..." << std::endl;
  224. IOLoginData* ioLoginData = IOLoginData::getInstance();
  225. for(AutoList<Player>::listiterator it = Player::listPlayer.list.begin(); it != Player::listPlayer.list.end(); ++it)
  226. {
  227. (*it).second->loginPosition = (*it).second->getPosition();
  228. ioLoginData->savePlayer((*it).second, false);
  229. }
  230.  
  231. map->saveMap();
  232. ScriptEnvironment::saveGameState();
  233. stateTime = OTSYS_TIME() + STATE_TIME;
  234.  
  235. if(gameState == GAME_STATE_MAINTAIN)
  236. setGameState(GAME_STATE_NORMAL);
  237. }
  238.  
  239. void Game::loadGameState()
  240. {
  241. ScriptEnvironment::loadGameState();
  242. }
  243.  
  244. int32_t Game::loadMap(std::string filename)
  245. {
  246. if(!map)
  247. map = new Map;
  248.  
  249. maxPlayers = g_config.getNumber(ConfigManager::MAX_PLAYERS);
  250. inFightTicks = g_config.getNumber(ConfigManager::PZ_LOCKED);
  251. Player::maxMessageBuffer = g_config.getNumber(ConfigManager::MAX_MESSAGEBUFFER);
  252. Monster::despawnRange = g_config.getNumber(ConfigManager::DEFAULT_DESPAWNRANGE);
  253. Monster::despawnRadius = g_config.getNumber(ConfigManager::DEFAULT_DESPAWNRADIUS);
  254. return map->loadMap("data/world/" + filename + ".otbm");
  255. }
  256.  
  257. void Game::refreshMap()
  258. {
  259. Tile* tile;
  260. Item* item;
  261.  
  262. for(Map::TileMap::iterator it = map->refreshTileMap.begin(); it != map->refreshTileMap.end(); ++it)
  263. {
  264. tile = it->first;
  265.  
  266. if(TileItemVector* items = tile->getItemList())
  267. {
  268. //remove garbage
  269. int32_t downItemSize = tile->getDownItemCount();
  270. for(int32_t i = downItemSize - 1; i >= 0; --i)
  271. {
  272. item = items->at(i);
  273. if(item)
  274. {
  275. #ifndef __DEBUG__
  276. internalRemoveItem(item);
  277. #else
  278. ReturnValue ret = internalRemoveItem(item);
  279. if(ret != RET_NOERROR)
  280. std::cout << "Could not refresh item: " << item->getID() << "pos: " << tile->getPosition() << std::endl;
  281. #endif
  282. }
  283. }
  284. }
  285.  
  286. cleanup();
  287.  
  288. //restore to original state
  289. TileItemVector list = it->second.list;
  290. for(ItemVector::reverse_iterator it = list.rbegin(); it != list.rend(); ++it)
  291. {
  292. Item* item = (*it)->clone();
  293. ReturnValue ret = internalAddItem(tile, item, INDEX_WHEREEVER, FLAG_NOLIMIT);
  294. if(ret == RET_NOERROR)
  295. {
  296. if(item->getUniqueId() != 0)
  297. ScriptEnvironment::addUniqueThing(item);
  298.  
  299. startDecay(item);
  300. }
  301. else
  302. {
  303. std::cout << "Could not refresh item: " << item->getID() << "pos: " << tile->getPosition() << std::endl;
  304. delete item;
  305. }
  306. }
  307. }
  308. }
  309.  
  310. Cylinder* Game::internalGetCylinder(Player* player, const Position& pos)
  311. {
  312. if(pos.x != 0xFFFF)
  313. return getTile(pos.x, pos.y, pos.z);
  314. else
  315. {
  316. //container
  317. if(pos.y & 0x40)
  318. {
  319. uint8_t from_cid = pos.y & 0x0F;
  320. return player->getContainer(from_cid);
  321. }
  322. //inventory
  323. else
  324. return player;
  325. }
  326. }
  327.  
  328. Thing* Game::internalGetThing(Player* player, const Position& pos, int32_t index, uint32_t spriteId /*= 0*/, stackPosType_t type /*= STACKPOS_NORMAL*/)
  329. {
  330. if(pos.x != 0xFFFF)
  331. {
  332. Tile* tile = getTile(pos.x, pos.y, pos.z);
  333. if(tile)
  334. {
  335. /*look at*/
  336. if(type == STACKPOS_LOOK)
  337. return tile->getTopVisibleThing(player);
  338.  
  339. Thing* thing = NULL;
  340. /*for move operations*/
  341. if(type == STACKPOS_MOVE)
  342. {
  343. Item* item = tile->getTopDownItem();
  344. if(item && !item->isNotMoveable())
  345. thing = item;
  346. else
  347. thing = tile->getTopVisibleCreature(player);
  348. }
  349. else if(type == STACKPOS_USEITEM)
  350. {
  351. //First check items with topOrder 2 (ladders, signs, splashes)
  352. Item* item = tile->getItemByTopOrder(2);
  353. if(item && g_actions->hasAction(item))
  354. thing = item;
  355. else
  356. {
  357. //then down items
  358. thing = tile->getTopDownItem();
  359. if(thing == NULL)
  360. thing = tile->getTopTopItem(); //then last we check items with topOrder 3 (doors etc)
  361.  
  362. if(thing == NULL)
  363. thing = tile->ground;
  364. }
  365. }
  366. else if(type == STACKPOS_USE)
  367. thing = tile->getTopDownItem();
  368. else
  369. thing = tile->__getThing(index);
  370.  
  371. if(player)
  372. {
  373. //do extra checks here if the thing is accessable
  374. if(thing && thing->getItem())
  375. {
  376. if(tile->hasProperty(ISVERTICAL))
  377. {
  378. if(player->getPosition().x + 1 == tile->getPosition().x)
  379. thing = NULL;
  380. }
  381. else if(tile->hasProperty(ISHORIZONTAL))
  382. {
  383. if(player->getPosition().y + 1 == tile->getPosition().y)
  384. thing = NULL;
  385. }
  386. }
  387. }
  388. return thing;
  389. }
  390. }
  391. else
  392. {
  393. //container
  394. if(pos.y & 0x40)
  395. {
  396. uint8_t fromCid = pos.y & 0x0F;
  397. uint8_t slot = pos.z;
  398.  
  399. Container* parentcontainer = player->getContainer(fromCid);
  400. if(!parentcontainer)
  401. return NULL;
  402.  
  403. return parentcontainer->getItem(slot);
  404. }
  405. else if(pos.y == 0 && pos.z == 0)
  406. {
  407. const ItemType& it = Item::items.getItemIdByClientId(spriteId);
  408. if(it.id == 0)
  409. return NULL;
  410.  
  411. int32_t subType = -1;
  412. if(it.isFluidContainer() && index < int32_t(sizeof(reverseFluidMap) / sizeof(int8_t)))
  413. subType = reverseFluidMap[index];
  414.  
  415. return findItemOfType(player, it.id, true, subType);
  416. }
  417. //inventory
  418. else
  419. {
  420. slots_t slot = (slots_t)static_cast<unsigned char>(pos.y);
  421. return player->getInventoryItem(slot);
  422. }
  423. }
  424. return NULL;
  425. }
  426.  
  427. void Game::internalGetPosition(Item* item, Position& pos, uint8_t& stackpos)
  428. {
  429. pos.x = 0;
  430. pos.y = 0;
  431. pos.z = 0;
  432. stackpos = 0;
  433.  
  434. Cylinder* topParent = item->getTopParent();
  435. if(topParent)
  436. {
  437. if(Player* player = dynamic_cast<Player*>(topParent))
  438. {
  439. pos.x = 0xFFFF;
  440.  
  441. Container* container = dynamic_cast<Container*>(item->getParent());
  442. if(container)
  443. {
  444. pos.y = ((uint16_t) ((uint16_t)0x40) | ((uint16_t)player->getContainerID(container)) );
  445. pos.z = container->__getIndexOfThing(item);
  446. stackpos = pos.z;
  447. }
  448. else
  449. {
  450. pos.y = player->__getIndexOfThing(item);
  451. stackpos = pos.y;
  452. }
  453. }
  454. else if(Tile* tile = topParent->getTile())
  455. {
  456. pos = tile->getPosition();
  457. stackpos = tile->__getIndexOfThing(item);
  458. }
  459. }
  460. }
  461.  
  462. void Game::setTile(Tile* newTile)
  463. {
  464. return map->setTile(newTile->getPosition(), newTile);
  465. }
  466.  
  467. Tile* Game::getTile(int32_t x, int32_t y, int32_t z)
  468. {
  469. return map->getTile(x, y, z);
  470. }
  471.  
  472. Tile* Game::getTile(const Position& pos)
  473. {
  474. return map->getTile(pos);
  475. }
  476.  
  477. QTreeLeafNode* Game::getLeaf(uint32_t x, uint32_t y)
  478. {
  479. return map->getLeaf(x, y);
  480. }
  481.  
  482. Creature* Game::getCreatureByID(uint32_t id)
  483. {
  484. if(id == 0)
  485. return NULL;
  486.  
  487. AutoList<Creature>::listiterator it = listCreature.list.find(id);
  488. if(it != listCreature.list.end())
  489. {
  490. if(!(*it).second->isRemoved())
  491. return (*it).second;
  492. }
  493. return NULL; //just in case the player doesnt exist
  494. }
  495.  
  496. Player* Game::getPlayerByID(uint32_t id)
  497. {
  498. if(id == 0)
  499. return NULL;
  500.  
  501. AutoList<Player>::listiterator it = Player::listPlayer.list.find(id);
  502. if(it != Player::listPlayer.list.end())
  503. {
  504. if(!(*it).second->isRemoved())
  505. return (*it).second;
  506. }
  507. return NULL; //just in case the player doesnt exist
  508. }
  509.  
  510. Creature* Game::getCreatureByName(const std::string& s)
  511. {
  512. if(s.empty())
  513. return NULL;
  514.  
  515. std::string txt1 = asUpperCaseString(s);
  516. for(AutoList<Creature>::listiterator it = listCreature.list.begin(); it != listCreature.list.end(); ++it)
  517. {
  518. if(!(*it).second->isRemoved())
  519. {
  520. std::string txt2 = asUpperCaseString((*it).second->getName());
  521. if(txt1 == txt2)
  522. return it->second;
  523. }
  524. }
  525. return NULL; //just in case the creature doesnt exist
  526. }
  527.  
  528. Player* Game::getPlayerByName(const std::string& s)
  529. {
  530. if(s.empty())
  531. return NULL;
  532.  
  533. std::string txt1 = asUpperCaseString(s);
  534. for(AutoList<Player>::listiterator it = Player::listPlayer.list.begin(); it != Player::listPlayer.list.end(); ++it)
  535. {
  536. if(!(*it).second->isRemoved())
  537. {
  538. std::string txt2 = asUpperCaseString((*it).second->getName());
  539. if(txt1 == txt2)
  540. return it->second;
  541. }
  542. }
  543. return NULL; //just in case the player doesnt exist
  544. }
  545.  
  546. Player* Game::getPlayerByGUID(const uint32_t& guid)
  547. {
  548. if(guid == 0)
  549. return NULL;
  550.  
  551. for(AutoList<Player>::listiterator it = Player::listPlayer.list.begin(); it != Player::listPlayer.list.end(); ++it)
  552. {
  553. Player* player = (*it).second;
  554. if(!player->isRemoved())
  555. {
  556. if(guid == player->getGUID())
  557. return player;
  558. }
  559. }
  560. return NULL;
  561. }
  562.  
  563. ReturnValue Game::getPlayerByNameWildcard(const std::string& s, Player*& player)
  564. {
  565. player = NULL;
  566.  
  567. if(s.empty())
  568. return RET_PLAYERWITHTHISNAMEISNOTONLINE;
  569.  
  570. if((*s.rbegin()) != '~')
  571. {
  572. player = getPlayerByName(s);
  573. if(!player)
  574. return RET_PLAYERWITHTHISNAMEISNOTONLINE;
  575.  
  576. return RET_NOERROR;
  577. }
  578.  
  579. Player* lastFound = NULL;
  580. std::string txt1 = asUpperCaseString(s.substr(0, s.length() - 1));
  581. for(AutoList<Player>::listiterator it = Player::listPlayer.list.begin(); it != Player::listPlayer.list.end(); ++it)
  582. {
  583. if(!(*it).second->isRemoved())
  584. {
  585. std::string txt2 = asUpperCaseString((*it).second->getName());
  586. if(txt2.substr(0, txt1.length()) == txt1)
  587. {
  588. if(lastFound == NULL)
  589. lastFound = (*it).second;
  590. else
  591. return RET_NAMEISTOOAMBIGIOUS;
  592. }
  593. }
  594. }
  595.  
  596. if(lastFound != NULL)
  597. {
  598. player = lastFound;
  599. return RET_NOERROR;
  600. }
  601. return RET_PLAYERWITHTHISNAMEISNOTONLINE;
  602. }
  603.  
  604. Player* Game::getPlayerByAccount(uint32_t acc)
  605. {
  606. for(AutoList<Player>::listiterator it = Player::listPlayer.list.begin(); it != Player::listPlayer.list.end(); ++it)
  607. {
  608. if(!it->second->isRemoved())
  609. {
  610. if(it->second->getAccount() == acc)
  611. return it->second;
  612. }
  613. }
  614. return NULL;
  615. }
  616.  
  617. PlayerVector Game::getPlayersByAccount(uint32_t acc)
  618. {
  619. PlayerVector players;
  620. for(AutoList<Player>::listiterator it = Player::listPlayer.list.begin(); it != Player::listPlayer.list.end(); ++it)
  621. {
  622. if(!it->second->isRemoved())
  623. {
  624. if(it->second->getAccount() == acc)
  625. players.push_back(it->second);
  626. }
  627. }
  628. return players;
  629. }
  630.  
  631. PlayerVector Game::getPlayersByIP(uint32_t ipadress, uint32_t mask)
  632. {
  633. PlayerVector players;
  634. for(AutoList<Player>::listiterator it = Player::listPlayer.list.begin(); it != Player::listPlayer.list.end(); ++it)
  635. {
  636. if(!it->second->isRemoved())
  637. {
  638. if((it->second->getIP() & mask) == (ipadress & mask))
  639. players.push_back(it->second);
  640. }
  641. }
  642. return players;
  643. }
  644.  
  645. bool Game::internalPlaceCreature(Creature* creature, const Position& pos, bool extendedPos /*=false*/, bool forced /*= false*/)
  646. {
  647. if(creature->getParent() != NULL)
  648. return false;
  649.  
  650. if(!map->placeCreature(pos, creature, extendedPos, forced))
  651. return false;
  652.  
  653. creature->useThing2();
  654. creature->setID();
  655. listCreature.addList(creature);
  656. creature->addList();
  657. return true;
  658. }
  659.  
  660. bool Game::placeCreature(Creature* creature, const Position& pos, bool extendedPos /*=false*/, bool forced /*= false*/)
  661. {
  662. if(!internalPlaceCreature(creature, pos, extendedPos, forced))
  663. return false;
  664.  
  665. SpectatorVec list;
  666. SpectatorVec::iterator it;
  667. getSpectators(list, creature->getPosition(), false, true);
  668.  
  669. Player* tmpPlayer = NULL;
  670. for(it = list.begin(); it != list.end(); ++it)
  671. {
  672. if((tmpPlayer = (*it)->getPlayer()))
  673. tmpPlayer->sendCreatureAppear(creature, creature->getPosition(), true);
  674. }
  675.  
  676. for(it = list.begin(); it != list.end(); ++it)
  677. (*it)->onCreatureAppear(creature, true);
  678.  
  679. Cylinder* creatureParent = creature->getParent();
  680. int32_t newIndex = creatureParent->__getIndexOfThing(creature);
  681. creatureParent->postAddNotification(creature, NULL, newIndex);
  682.  
  683. Player* player = creature->getPlayer();
  684. if(player)
  685. {
  686. int32_t offlineTime;
  687. if(player->getLastLogout() != 0)
  688. offlineTime = time(NULL) - player->getLastLogout();
  689. else
  690. offlineTime = 0;
  691.  
  692. Condition* conditionMuted = player->getCondition(CONDITION_MUTED, CONDITIONID_DEFAULT);
  693. if(conditionMuted && conditionMuted->getTicks() > 0)
  694. {
  695. conditionMuted->setTicks(conditionMuted->getTicks() - (offlineTime * 1000));
  696. if(conditionMuted->getTicks() <= 0)
  697. player->removeCondition(conditionMuted);
  698. else
  699. player->addCondition(conditionMuted->clone());
  700. }
  701.  
  702. Condition* conditionTrade = player->getCondition(CONDITION_ADVERTISINGTICKS, CONDITIONID_DEFAULT);
  703. if(conditionTrade && conditionTrade->getTicks() > 0)
  704. {
  705. conditionTrade->setTicks(conditionTrade->getTicks() - (offlineTime * 1000));
  706. if(conditionTrade->getTicks() <= 0)
  707. player->removeCondition(conditionTrade);
  708. else
  709. player->addCondition(conditionTrade->clone());
  710. }
  711.  
  712. Condition* conditionYell = player->getCondition(CONDITION_YELLTICKS, CONDITIONID_DEFAULT);
  713. if(conditionYell && conditionYell->getTicks() > 0)
  714. {
  715. conditionYell->setTicks(conditionYell->getTicks() - (offlineTime * 1000));
  716. if(conditionYell->getTicks() <= 0)
  717. player->removeCondition(conditionYell);
  718. else
  719. player->addCondition(conditionYell->clone());
  720. }
  721.  
  722. int32_t offlineTrainingSkill = player->getOfflineTrainingSkill();
  723. if(offlineTrainingSkill == -1)
  724. {
  725. uint16_t oldMinutes = player->getOfflineTrainingTime() / 60 / 1000;
  726. player->addOfflineTrainingTime(offlineTime * 1000);
  727.  
  728. uint16_t newMinutes = player->getOfflineTrainingTime() / 60 / 1000;
  729. if(oldMinutes != newMinutes)
  730. player->sendStats();
  731. }
  732.  
  733. if(player->isPremium())
  734. {
  735. int32_t value;
  736. player->getStorageValue(STORAGEVALUE_PROMOTION, value);
  737. if(player->isPromoted() && value != 1)
  738. player->addStorageValue(STORAGEVALUE_PROMOTION, 1);
  739. else if(!player->isPromoted() && value == 1)
  740. player->setVocation(g_vocations.getPromotedVocation(player->getVocationId()));
  741. }
  742. else if(player->isPromoted())
  743. player->setVocation(player->vocation->getFromVocation());
  744. }
  745.  
  746. addCreatureCheck(creature);
  747. creature->onPlacedCreature();
  748. return true;
  749. }
  750.  
  751. bool Game::removeCreature(Creature* creature, bool isLogout /*= true*/)
  752. {
  753. if(creature->isRemoved())
  754. return false;
  755.  
  756. #ifdef __DEBUG__
  757. std::cout << "removing creature " << std::endl;
  758. #endif
  759.  
  760. Tile* tile = creature->getTile();
  761.  
  762. SpectatorVec list;
  763. SpectatorVec::iterator it;
  764. getSpectators(list, tile->getPosition(), false, true);
  765.  
  766. Player* player = NULL;
  767. std::vector<uint32_t> oldStackPosVector;
  768. for(it = list.begin(); it != list.end(); ++it)
  769. {
  770. if((player = (*it)->getPlayer()))
  771. {
  772. if(!creature->isInGhostMode() || player->isAccessPlayer())
  773. oldStackPosVector.push_back(tile->getClientIndexOfThing(player, creature));
  774. }
  775. }
  776.  
  777. int32_t index = tile->__getIndexOfThing(creature);
  778. if(!map->removeCreature(creature))
  779. return false;
  780.  
  781. //send to client
  782. uint32_t i = 0;
  783. for(it = list.begin(); it != list.end(); ++it)
  784. {
  785. if((player = (*it)->getPlayer()))
  786. {
  787. if(!creature->isInGhostMode() || player->isAccessPlayer())
  788. {
  789. player->sendCreatureDisappear(creature, oldStackPosVector[i], isLogout);
  790. ++i;
  791. }
  792. }
  793. }
  794.  
  795. //event method
  796. for(it = list.begin(); it != list.end(); ++it)
  797. (*it)->onCreatureDisappear(creature, index, isLogout);
  798.  
  799. creature->getParent()->postRemoveNotification(creature, NULL, index, true);
  800.  
  801. listCreature.removeList(creature->getID());
  802. creature->removeList();
  803. creature->setRemoved();
  804. FreeThing(creature);
  805.  
  806. removeCreatureCheck(creature);
  807.  
  808. for(std::list<Creature*>::iterator cit = creature->summons.begin(); cit != creature->summons.end(); ++cit)
  809. {
  810. (*cit)->setLossSkill(false);
  811. removeCreature(*cit);
  812. }
  813.  
  814. creature->onRemovedCreature();
  815. return true;
  816. }
  817.  
  818. bool Game::playerMoveThing(uint32_t playerId, const Position& fromPos,
  819. uint16_t spriteId, uint8_t fromStackPos, const Position& toPos, uint8_t count)
  820. {
  821. Player* player = getPlayerByID(playerId);
  822. if(!player || player->isRemoved())
  823. return false;
  824.  
  825. uint8_t fromIndex = 0;
  826. if(fromPos.x == 0xFFFF)
  827. {
  828. if(fromPos.y & 0x40)
  829. fromIndex = static_cast<uint8_t>(fromPos.z);
  830. else
  831. fromIndex = static_cast<uint8_t>(fromPos.y);
  832. }
  833. else
  834. fromIndex = fromStackPos;
  835.  
  836. Thing* thing = internalGetThing(player, fromPos, fromIndex, spriteId, STACKPOS_MOVE);
  837.  
  838. Cylinder* toCylinder = internalGetCylinder(player, toPos);
  839.  
  840. if(!thing || !toCylinder)
  841. {
  842. player->sendCancelMessage(RET_NOTPOSSIBLE);
  843. return false;
  844. }
  845.  
  846. if(Creature* movingCreature = thing->getCreature())
  847. {
  848. if(Position::areInRange<1,1,0>(movingCreature->getPosition(), player->getPosition()))
  849. {
  850. SchedulerTask* task = createSchedulerTask(1000,
  851. boost::bind(&Game::playerMoveCreature, this, player->getID(),
  852. movingCreature->getID(), movingCreature->getPosition(), toCylinder->getPosition()));
  853. player->setNextActionTask(task);
  854. }
  855. else
  856. playerMoveCreature(playerId, movingCreature->getID(), movingCreature->getPosition(), toCylinder->getPosition());
  857. }
  858. else if(thing->getItem())
  859. playerMoveItem(playerId, fromPos, spriteId, fromStackPos, toPos, count);
  860.  
  861. return true;
  862. }
  863.  
  864. bool Game::playerMoveCreature(uint32_t playerId, uint32_t movingCreatureId,
  865. const Position& movingCreatureOrigPos, const Position& toPos)
  866. {
  867. Player* player = getPlayerByID(playerId);
  868. if(!player || player->isRemoved())
  869. return false;
  870.  
  871. if(!player->canDoAction())
  872. {
  873. uint32_t delay = player->getNextActionTime();
  874. SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerMoveCreature,
  875. this, playerId, movingCreatureId, movingCreatureOrigPos, toPos));
  876. player->setNextActionTask(task);
  877. return false;
  878. }
  879.  
  880. player->setNextActionTask(NULL);
  881.  
  882. Creature* movingCreature = getCreatureByID(movingCreatureId);
  883. if(!movingCreature || movingCreature->isRemoved())
  884. return false;
  885.  
  886. if(movingCreature->getPlayer())
  887. {
  888. if(movingCreature->getPlayer()->getNoMove())
  889. return false;
  890. }
  891.  
  892. if(!Position::areInRange<1,1,0>(movingCreatureOrigPos, player->getPosition()))
  893. {
  894. //need to walk to the creature first before moving it
  895. std::list<Direction> listDir;
  896. if(getPathToEx(player, movingCreatureOrigPos, listDir, 0, 1, true, true))
  897. {
  898. g_dispatcher.addTask(createTask(boost::bind(&Game::playerAutoWalk,
  899. this, player->getID(), listDir)));
  900. SchedulerTask* task = createSchedulerTask(1500, boost::bind(&Game::playerMoveCreature, this,
  901. playerId, movingCreatureId, movingCreatureOrigPos, toPos));
  902. player->setNextWalkActionTask(task);
  903. return true;
  904. }
  905. else
  906. {
  907. player->sendCancelMessage(RET_THEREISNOWAY);
  908. return false;
  909. }
  910. }
  911.  
  912. Tile* toTile = getTile(toPos);
  913. const Position& movingCreaturePos = movingCreature->getPosition();
  914.  
  915. if(!toTile)
  916. {
  917. player->sendCancelMessage(RET_NOTPOSSIBLE);
  918. return false;
  919. }
  920.  
  921. if((!movingCreature->isPushable() && !player->hasFlag(PlayerFlag_CanPushAllCreatures)) ||
  922. (movingCreature->isInGhostMode() && !player->isAccessPlayer()))
  923. {
  924. player->sendCancelMessage(RET_NOTMOVEABLE);
  925. return false;
  926. }
  927.  
  928. //check throw distance
  929. if((std::abs(movingCreaturePos.x - toPos.x) > movingCreature->getThrowRange()) || (std::abs(movingCreaturePos.y - toPos.y) > movingCreature->getThrowRange()) || (std::abs(movingCreaturePos.z - toPos.z) * 4 > movingCreature->getThrowRange()))
  930. {
  931. player->sendCancelMessage(RET_DESTINATIONOUTOFREACH);
  932. return false;
  933. }
  934.  
  935. if(player != movingCreature)
  936. {
  937. bool toTileIsSafe = false;
  938. if(toTile->hasFlag(TILESTATE_NOPVPZONE) || toTile->hasFlag(TILESTATE_PROTECTIONZONE))
  939. toTileIsSafe = true;
  940.  
  941. if(toTile->hasProperty(BLOCKPATH))
  942. {
  943. player->sendCancelMessage(RET_NOTENOUGHROOM);
  944. return false;
  945. }
  946. else if((movingCreature->getZone() == ZONE_PROTECTION || movingCreature->getZone() == ZONE_NOPVP)
  947. && !toTileIsSafe)
  948. {
  949. player->sendCancelMessage(RET_NOTPOSSIBLE);
  950. return false;
  951. }
  952. else if(movingCreature->getNpc() && !Spawns::getInstance()->isInZone(movingCreature->masterPos, movingCreature->masterRadius, toPos))
  953. {
  954. player->sendCancelMessage(RET_NOTENOUGHROOM);
  955. return false;
  956. }
  957. }
  958.  
  959. ReturnValue ret = internalMoveCreature(movingCreature, movingCreature->getTile(), toTile);
  960. if(ret != RET_NOERROR)
  961. {
  962. player->sendCancelMessage(ret);
  963. return false;
  964. }
  965. return true;
  966. }
  967.  
  968. ReturnValue Game::internalMoveCreature(Creature* creature, Direction direction, uint32_t flags /*= 0*/)
  969. {
  970. Cylinder* fromTile = creature->getTile();
  971. Cylinder* toTile = NULL;
  972.  
  973. creature->setLastPosition(creature->getPosition());
  974. const Position& currentPos = creature->getPosition();
  975. Position destPos = currentPos;
  976. bool diagonalMovement;
  977. switch(direction)
  978. {
  979. case NORTHWEST:
  980. case NORTHEAST:
  981. case SOUTHWEST:
  982. case SOUTHEAST:
  983. diagonalMovement = true;
  984. break;
  985.  
  986. default:
  987. diagonalMovement = false;
  988. break;
  989. }
  990.  
  991. destPos = getNextPosition(direction, destPos);
  992. if(creature->getPlayer() && !diagonalMovement)
  993. {
  994. //try go up
  995. if(currentPos.z != 8 && creature->getTile()->hasHeight(3))
  996. {
  997. Tile* tmpTile = getTile(currentPos.x, currentPos.y, currentPos.z - 1);
  998. if(tmpTile == NULL || (tmpTile->ground == NULL && !tmpTile->hasProperty(BLOCKSOLID)))
  999. {
  1000. tmpTile = getTile(destPos.x, destPos.y, destPos.z - 1);
  1001. if(tmpTile && tmpTile->ground && !tmpTile->hasProperty(BLOCKSOLID))
  1002. {
  1003. flags = flags | FLAG_IGNOREBLOCKITEM | FLAG_IGNOREBLOCKCREATURE;
  1004. if(!tmpTile->floorChange())
  1005. destPos.z--;
  1006. }
  1007. }
  1008. }
  1009. else
  1010. {
  1011. //try go down
  1012. Tile* tmpTile = getTile(destPos);
  1013. if(currentPos.z != 7 && (tmpTile == NULL || (tmpTile->ground == NULL && !tmpTile->hasProperty(BLOCKSOLID))))
  1014. {
  1015. tmpTile = getTile(destPos.x, destPos.y, destPos.z + 1);
  1016. if(tmpTile && tmpTile->hasHeight(3))
  1017. {
  1018. flags = flags | FLAG_IGNOREBLOCKITEM | FLAG_IGNOREBLOCKCREATURE;
  1019. destPos.z++;
  1020. }
  1021. }
  1022. }
  1023. }
  1024.  
  1025. toTile = getTile(destPos);
  1026. ReturnValue ret = RET_NOTPOSSIBLE;
  1027. if(toTile != NULL)
  1028. ret = internalMoveCreature(creature, fromTile, toTile, flags);
  1029.  
  1030. return ret;
  1031. }
  1032.  
  1033. ReturnValue Game::internalMoveCreature(Creature* creature, Cylinder* fromCylinder, Cylinder* toCylinder, uint32_t flags /*= 0*/)
  1034. {
  1035. //check if we can move the creature to the destination
  1036. ReturnValue ret = toCylinder->__queryAdd(0, creature, 1, flags);
  1037. if(ret != RET_NOERROR)
  1038. return ret;
  1039.  
  1040. fromCylinder->getTile()->moveCreature(creature, toCylinder);
  1041.  
  1042. int32_t index = 0;
  1043. Item* toItem = NULL;
  1044. Cylinder* subCylinder = NULL;
  1045.  
  1046. uint32_t n = 0;
  1047. while((subCylinder = toCylinder->__queryDestination(index, creature, &toItem, flags)) != toCylinder)
  1048. {
  1049. toCylinder->getTile()->moveCreature(creature, subCylinder);
  1050.  
  1051. if(creature->getParent() != subCylinder)
  1052. {
  1053. //could happen if a script move the creature
  1054. break;
  1055. }
  1056.  
  1057. toCylinder = subCylinder;
  1058. flags = 0;
  1059.  
  1060. //to prevent infinite loop
  1061. if(++n >= MAP_MAX_LAYERS)
  1062. break;
  1063. }
  1064. return RET_NOERROR;
  1065. }
  1066.  
  1067. bool Game::playerMoveItem(uint32_t playerId, const Position& fromPos,
  1068. uint16_t spriteId, uint8_t fromStackPos, const Position& toPos, uint8_t count)
  1069. {
  1070. Player* player = getPlayerByID(playerId);
  1071. if(!player || player->isRemoved())
  1072. return false;
  1073.  
  1074. if(!player->canDoAction())
  1075. {
  1076. uint32_t delay = player->getNextActionTime();
  1077. SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerMoveItem, this,
  1078. playerId, fromPos, spriteId, fromStackPos, toPos, count));
  1079. player->setNextActionTask(task);
  1080. return false;
  1081. }
  1082.  
  1083. player->setNextActionTask(NULL);
  1084.  
  1085. Cylinder* fromCylinder = internalGetCylinder(player, fromPos);
  1086. uint8_t fromIndex = 0;
  1087.  
  1088. if(fromPos.x == 0xFFFF)
  1089. {
  1090. if(fromPos.y & 0x40)
  1091. fromIndex = static_cast<uint8_t>(fromPos.z);
  1092. else
  1093. fromIndex = static_cast<uint8_t>(fromPos.y);
  1094. }
  1095. else
  1096. fromIndex = fromStackPos;
  1097.  
  1098. Thing* thing = internalGetThing(player, fromPos, fromIndex, spriteId, STACKPOS_MOVE);
  1099. if(!thing || !thing->getItem())
  1100. {
  1101. player->sendCancelMessage(RET_NOTPOSSIBLE);
  1102. return false;
  1103. }
  1104.  
  1105. Item* item = thing->getItem();
  1106.  
  1107. Cylinder* toCylinder = internalGetCylinder(player, toPos);
  1108. uint8_t toIndex = 0;
  1109.  
  1110. if(toPos.x == 0xFFFF)
  1111. {
  1112. if(toPos.y & 0x40)
  1113. toIndex = static_cast<uint8_t>(toPos.z);
  1114. else
  1115. toIndex = static_cast<uint8_t>(toPos.y);
  1116. }
  1117.  
  1118. if(fromCylinder == NULL || toCylinder == NULL || item == NULL || item->getClientID() != spriteId)
  1119. {
  1120. player->sendCancelMessage(RET_NOTPOSSIBLE);
  1121. return false;
  1122. }
  1123.  
  1124. if(!item->isPushable() || item->getUniqueId() != 0)
  1125. {
  1126. player->sendCancelMessage(RET_NOTMOVEABLE);
  1127. return false;
  1128. }
  1129.  
  1130. const Position& playerPos = player->getPosition();
  1131. const Position& mapFromPos = fromCylinder->getTile()->getPosition();
  1132.  
  1133. const Tile* toCylinderTile = toCylinder->getTile();
  1134. const Position& mapToPos = toCylinderTile->getPosition();
  1135.  
  1136. if(playerPos.z > mapFromPos.z)
  1137. {
  1138. player->sendCancelMessage(RET_FIRSTGOUPSTAIRS);
  1139. return false;
  1140. }
  1141.  
  1142. if(playerPos.z < mapFromPos.z)
  1143. {
  1144. player->sendCancelMessage(RET_FIRSTGODOWNSTAIRS);
  1145. return false;
  1146. }
  1147.  
  1148. if(!Position::areInRange<1,1,0>(playerPos, mapFromPos))
  1149. {
  1150. //need to walk to the item first before using it
  1151. std::list<Direction> listDir;
  1152. if(getPathToEx(player, item->getPosition(), listDir, 0, 1, true, true))
  1153. {
  1154. g_dispatcher.addTask(createTask(boost::bind(&Game::playerAutoWalk,
  1155. this, player->getID(), listDir)));
  1156.  
  1157. SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerMoveItem, this,
  1158. playerId, fromPos, spriteId, fromStackPos, toPos, count));
  1159. player->setNextWalkActionTask(task);
  1160. return true;
  1161. }
  1162. else
  1163. {
  1164. player->sendCancelMessage(RET_THEREISNOWAY);
  1165. return false;
  1166. }
  1167. }
  1168.  
  1169. //hangable item specific code
  1170. if(item->isHangable() && toCylinderTile->hasProperty(SUPPORTHANGABLE))
  1171. {
  1172. //destination supports hangable objects so need to move there first
  1173. if(toCylinderTile->hasProperty(ISVERTICAL))
  1174. {
  1175. if(player->getPosition().x + 1 == mapToPos.x)
  1176. {
  1177. player->sendCancelMessage(RET_NOTPOSSIBLE);
  1178. return false;
  1179. }
  1180. }
  1181. else if(toCylinderTile->hasProperty(ISHORIZONTAL))
  1182. {
  1183. if(player->getPosition().y + 1 == mapToPos.y)
  1184. {
  1185. player->sendCancelMessage(RET_NOTPOSSIBLE);
  1186. return false;
  1187. }
  1188. }
  1189.  
  1190. if(!Position::areInRange<1,1,0>(playerPos, mapToPos))
  1191. {
  1192. Position walkPos = mapToPos;
  1193. if(toCylinderTile->hasProperty(ISVERTICAL))
  1194. walkPos.x -= -1;
  1195.  
  1196. if(toCylinderTile->hasProperty(ISHORIZONTAL))
  1197. walkPos.y -= -1;
  1198.  
  1199. Position itemPos = fromPos;
  1200. uint8_t itemStackPos = fromStackPos;
  1201.  
  1202. if(fromPos.x != 0xFFFF && Position::areInRange<1,1,0>(mapFromPos, player->getPosition())
  1203. && !Position::areInRange<1,1,0>(mapFromPos, walkPos))
  1204. {
  1205. //need to pickup the item first
  1206. Item* moveItem = NULL;
  1207.  
  1208. ReturnValue ret = internalMoveItem(fromCylinder, player, INDEX_WHEREEVER, item, count, &moveItem);
  1209. if(ret != RET_NOERROR)
  1210. {
  1211. player->sendCancelMessage(ret);
  1212. return false;
  1213. }
  1214.  
  1215. //changing the position since its now in the inventory of the player
  1216. internalGetPosition(moveItem, itemPos, itemStackPos);
  1217. }
  1218.  
  1219. std::list<Direction> listDir;
  1220. if(map->getPathTo(player, walkPos, listDir))
  1221. {
  1222. g_dispatcher.addTask(createTask(boost::bind(&Game::playerAutoWalk,
  1223. this, player->getID(), listDir)));
  1224.  
  1225. SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerMoveItem, this,
  1226. playerId, itemPos, spriteId, itemStackPos, toPos, count));
  1227. player->setNextWalkActionTask(task);
  1228. return true;
  1229. }
  1230. else
  1231. {
  1232. player->sendCancelMessage(RET_THEREISNOWAY);
  1233. return false;
  1234. }
  1235. }
  1236. }
  1237.  
  1238. if((std::abs(playerPos.x - mapToPos.x) > item->getThrowRange()) ||
  1239. (std::abs(playerPos.y - mapToPos.y) > item->getThrowRange()) ||
  1240. (std::abs(mapFromPos.z - mapToPos.z) * 4 > item->getThrowRange()))
  1241. {
  1242. player->sendCancelMessage(RET_DESTINATIONOUTOFREACH);
  1243. return false;
  1244. }
  1245.  
  1246. if(!canThrowObjectTo(mapFromPos, mapToPos))
  1247. {
  1248. player->sendCancelMessage(RET_CANNOTTHROW);
  1249. return false;
  1250. }
  1251.  
  1252. ReturnValue ret = internalMoveItem(fromCylinder, toCylinder, toIndex, item, count, NULL, 0, player);
  1253. if(ret != RET_NOERROR)
  1254. {
  1255. player->sendCancelMessage(ret);
  1256. return false;
  1257. }
  1258. return true;
  1259. }
  1260.  
  1261. ReturnValue Game::internalMoveItem(Cylinder* fromCylinder, Cylinder* toCylinder, int32_t index,
  1262. Item* item, uint32_t count, Item** _moveItem, uint32_t flags /*= 0*/, Creature* actor/* = NULL*/)
  1263. {
  1264. if(!toCylinder)
  1265. return RET_NOTPOSSIBLE;
  1266.  
  1267. Item* toItem = NULL;
  1268.  
  1269. Cylinder* subCylinder;
  1270. int floorN = 0;
  1271. while((subCylinder = toCylinder->__queryDestination(index, item, &toItem, flags)) != toCylinder)
  1272. {
  1273. toCylinder = subCylinder;
  1274. flags = 0;
  1275.  
  1276. //to prevent infinite loop
  1277. if(++floorN >= MAP_MAX_LAYERS)
  1278. break;
  1279. }
  1280.  
  1281. //destination is the same as the source?
  1282. if(item == toItem)
  1283. return RET_NOERROR; //silently ignore move
  1284.  
  1285. //check if we can add this item
  1286. ReturnValue ret = toCylinder->__queryAdd(index, item, count, flags, actor);
  1287. if(ret == RET_NEEDEXCHANGE)
  1288. {
  1289. //check if we can add it to source cylinder
  1290. int32_t fromIndex = fromCylinder->__getIndexOfThing(item);
  1291.  
  1292. ret = fromCylinder->__queryAdd(fromIndex, toItem, toItem->getItemCount(), 0);
  1293. if(ret == RET_NOERROR)
  1294. {
  1295. //check how much we can move
  1296. uint32_t maxExchangeQueryCount = 0;
  1297. ReturnValue retExchangeMaxCount = fromCylinder->__queryMaxCount(INDEX_WHEREEVER, toItem, toItem->getItemCount(), maxExchangeQueryCount, 0);
  1298. if(retExchangeMaxCount != RET_NOERROR && maxExchangeQueryCount == 0)
  1299. return retExchangeMaxCount;
  1300.  
  1301. if(toCylinder->__queryRemove(toItem, toItem->getItemCount(), flags) == RET_NOERROR)
  1302. {
  1303. int32_t oldToItemIndex = toCylinder->__getIndexOfThing(toItem);
  1304. toCylinder->__removeThing(toItem, toItem->getItemCount());
  1305. fromCylinder->__addThing(toItem);
  1306.  
  1307. if(oldToItemIndex != -1)
  1308. toCylinder->postRemoveNotification(toItem, fromCylinder, oldToItemIndex, true);
  1309.  
  1310. int32_t newToItemIndex = fromCylinder->__getIndexOfThing(toItem);
  1311. if(newToItemIndex != -1)
  1312. fromCylinder->postAddNotification(toItem, toCylinder, newToItemIndex);
  1313.  
  1314. ret = toCylinder->__queryAdd(index, item, count, flags);
  1315. toItem = NULL;
  1316. }
  1317. }
  1318. }
  1319.  
  1320. if(ret != RET_NOERROR)
  1321. return ret;
  1322.  
  1323. //check how much we can move
  1324. uint32_t maxQueryCount = 0;
  1325. ReturnValue retMaxCount = toCylinder->__queryMaxCount(index, item, count, maxQueryCount, flags);
  1326.  
  1327. if(retMaxCount != RET_NOERROR && maxQueryCount == 0)
  1328. return retMaxCount;
  1329.  
  1330. uint32_t m = 0;
  1331.  
  1332. if(item->isStackable())
  1333. m = std::min((uint32_t)count, maxQueryCount);
  1334. else
  1335. m = maxQueryCount;
  1336.  
  1337. Item* moveItem = item;
  1338.  
  1339. //check if we can remove this item
  1340. ret = fromCylinder->__queryRemove(item, m, flags);
  1341. if(ret != RET_NOERROR)
  1342. return ret;
  1343.  
  1344. //remove the item
  1345. int32_t itemIndex = fromCylinder->__getIndexOfThing(item);
  1346. Item* updateItem = NULL;
  1347. fromCylinder->__removeThing(item, m);
  1348. bool isCompleteRemoval = item->isRemoved();
  1349.  
  1350. //update item(s)
  1351. if(item->isStackable())
  1352. {
  1353. uint32_t n;
  1354. if(toItem && toItem->getID() == item->getID())
  1355. {
  1356. n = std::min((uint32_t)100 - toItem->getItemCount(), m);
  1357. toCylinder->__updateThing(toItem, toItem->getID(), toItem->getItemCount() + n);
  1358. updateItem = toItem;
  1359. }
  1360. else
  1361. n = 0;
  1362.  
  1363. int32_t count = m - n;
  1364. if(count > 0)
  1365. moveItem = Item::CreateItem(item->getID(), count);
  1366. else
  1367. moveItem = NULL;
  1368.  
  1369. if(item->isRemoved())
  1370. FreeThing(item);
  1371. }
  1372.  
  1373. //add item
  1374. if(moveItem /*m - n > 0*/)
  1375. toCylinder->__addThing(index, moveItem);
  1376.  
  1377. if(itemIndex != -1)
  1378. fromCylinder->postRemoveNotification(item, toCylinder, itemIndex, isCompleteRemoval);
  1379.  
  1380. if(moveItem)
  1381. {
  1382. int32_t moveItemIndex = toCylinder->__getIndexOfThing(moveItem);
  1383. if(moveItemIndex != -1)
  1384. toCylinder->postAddNotification(moveItem, fromCylinder, moveItemIndex);
  1385. }
  1386.  
  1387. if(updateItem)
  1388. {
  1389. int32_t updateItemIndex = toCylinder->__getIndexOfThing(updateItem);
  1390. if(updateItemIndex != -1)
  1391. toCylinder->postAddNotification(updateItem, fromCylinder, updateItemIndex);
  1392. }
  1393.  
  1394. if(_moveItem)
  1395. {
  1396. if(moveItem)
  1397. *_moveItem = moveItem;
  1398. else
  1399. *_moveItem = item;
  1400. }
  1401.  
  1402. //we could not move all, inform the player
  1403. if(item->isStackable() && maxQueryCount < count)
  1404. return retMaxCount;
  1405.  
  1406. return ret;
  1407. }
  1408.  
  1409. ReturnValue Game::internalAddItem(Cylinder* toCylinder, Item* item, int32_t index /*= INDEX_WHEREEVER*/,
  1410. uint32_t flags/* = 0*/, bool test/* = false*/)
  1411. {
  1412. uint32_t remainderCount = 0;
  1413. return internalAddItem(toCylinder, item, index, flags, test, remainderCount);
  1414. }
  1415.  
  1416. ReturnValue Game::internalAddItem(Cylinder* toCylinder, Item* item, int32_t index,
  1417. uint32_t flags, bool test, uint32_t& remainderCount)
  1418. {
  1419. remainderCount = 0;
  1420. if(toCylinder == NULL || item == NULL)
  1421. return RET_NOTPOSSIBLE;
  1422.  
  1423. Cylinder* destCylinder = toCylinder;
  1424. Item* toItem = NULL;
  1425. toCylinder = toCylinder->__queryDestination(index, item, &toItem, flags);
  1426.  
  1427. //check if we can add this item
  1428. ReturnValue ret = toCylinder->__queryAdd(index, item, item->getItemCount(), flags);
  1429. if(ret != RET_NOERROR)
  1430. return ret;
  1431.  
  1432. /*
  1433. Check if we can move add the whole amount, we do this by checking against the original cylinder,
  1434. since the queryDestination can return a cylinder that might only hold a part of the full amount.
  1435. */
  1436. uint32_t maxQueryCount = 0;
  1437. ret = destCylinder->__queryMaxCount(INDEX_WHEREEVER, item, item->getItemCount(), maxQueryCount, flags);
  1438. if(ret != RET_NOERROR)
  1439. return ret;
  1440.  
  1441. if(test)
  1442. return RET_NOERROR;
  1443.  
  1444. if(item->isStackable() && toItem && toItem->getID() == item->getID())
  1445. {
  1446. uint32_t m = std::min((uint32_t)item->getItemCount(), maxQueryCount);
  1447. uint32_t n = 0;
  1448.  
  1449. if(toItem->getID() == item->getID())
  1450. {
  1451. n = std::min((uint32_t)100 - toItem->getItemCount(), m);
  1452. toCylinder->__updateThing(toItem, toItem->getID(), toItem->getItemCount() + n);
  1453. }
  1454.  
  1455. int32_t count = m - n;
  1456. if(count > 0)
  1457. {
  1458. if(item->getItemCount() != count)
  1459. {
  1460. Item* remainderItem = Item::CreateItem(item->getID(), count);
  1461. if(internalAddItem(destCylinder, remainderItem, INDEX_WHEREEVER, flags, false) != RET_NOERROR)
  1462. {
  1463. FreeThing(remainderItem);
  1464. remainderCount = count;
  1465. }
  1466. }
  1467. else
  1468. {
  1469. toCylinder->__addThing(index, item);
  1470.  
  1471. int32_t itemIndex = toCylinder->__getIndexOfThing(item);
  1472. if(itemIndex != -1)
  1473. toCylinder->postAddNotification(item, NULL, itemIndex);
  1474. }
  1475. }
  1476. else
  1477. {
  1478. //fully merged with toItem, item will be destroyed
  1479. item->onRemoved();
  1480. FreeThing(item);
  1481.  
  1482. int32_t itemIndex = toCylinder->__getIndexOfThing(toItem);
  1483. if(itemIndex != -1)
  1484. toCylinder->postAddNotification(toItem, NULL, itemIndex);
  1485. }
  1486. }
  1487. else
  1488. {
  1489. toCylinder->__addThing(index, item);
  1490.  
  1491. int32_t itemIndex = toCylinder->__getIndexOfThing(item);
  1492. if(itemIndex != -1)
  1493. toCylinder->postAddNotification(item, NULL, itemIndex);
  1494. }
  1495. return RET_NOERROR;
  1496. }
  1497.  
  1498. ReturnValue Game::internalRemoveItem(Item* item, int32_t count /*= -1*/, bool test /*= false*/, uint32_t flags /*= 0*/)
  1499. {
  1500. Cylinder* cylinder = item->getParent();
  1501. if(cylinder == NULL)
  1502. return RET_NOTPOSSIBLE;
  1503.  
  1504. if(count == -1)
  1505. count = item->getItemCount();
  1506.  
  1507. //check if we can remove this item
  1508. ReturnValue ret = cylinder->__queryRemove(item, count, flags | FLAG_IGNORENOTMOVEABLE);
  1509. if(ret != RET_NOERROR)
  1510. return ret;
  1511.  
  1512. if(!item->canRemove())
  1513. return RET_NOTPOSSIBLE;
  1514.  
  1515. if(!test)
  1516. {
  1517. int32_t index = cylinder->__getIndexOfThing(item);
  1518.  
  1519. //remove the item
  1520. cylinder->__removeThing(item, count);
  1521. bool isCompleteRemoval = false;
  1522. if(item->isRemoved())
  1523. {
  1524. isCompleteRemoval = true;
  1525. FreeThing(item);
  1526. }
  1527. cylinder->postRemoveNotification(item, NULL, index, isCompleteRemoval);
  1528. }
  1529. item->onRemoved();
  1530. return RET_NOERROR;
  1531. }
  1532.  
  1533. ReturnValue Game::internalPlayerAddItem(Player* player, Item* item, bool dropOnMap /*= true*/, slots_t slot /*= SLOT_WHEREEVER*/)
  1534. {
  1535. uint32_t remainderCount = 0;
  1536. ReturnValue ret = internalAddItem(player, item, (int32_t)slot, 0, false, remainderCount);
  1537. if(remainderCount > 0)
  1538. {
  1539. Item* remainderItem = Item::CreateItem(item->getID(), remainderCount);
  1540. ReturnValue remaindRet = internalAddItem(player->getTile(), remainderItem, INDEX_WHEREEVER, FLAG_NOLIMIT);
  1541. if(remaindRet != RET_NOERROR)
  1542. FreeThing(remainderItem);
  1543. }
  1544.  
  1545. if(ret != RET_NOERROR && dropOnMap)
  1546. ret = internalAddItem(player->getTile(), item, INDEX_WHEREEVER, FLAG_NOLIMIT);
  1547.  
  1548. return ret;
  1549. }
  1550.  
  1551. Item* Game::findItemOfType(Cylinder* cylinder, uint16_t itemId,
  1552. bool depthSearch /*= true*/, int32_t subType /*= -1*/)
  1553. {
  1554. if(cylinder == NULL)
  1555. return NULL;
  1556.  
  1557. std::list<Container*> listContainer;
  1558. Container* tmpContainer = NULL;
  1559. Thing* thing = NULL;
  1560. Item* item = NULL;
  1561.  
  1562. for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex();)
  1563. {
  1564. if((thing = cylinder->__getThing(i)) && (item = thing->getItem()))
  1565. {
  1566. if(item->getID() == itemId && (subType == -1 || subType == item->getSubType()))
  1567. return item;
  1568. else
  1569. {
  1570. ++i;
  1571. if(depthSearch && (tmpContainer = item->getContainer()))
  1572. listContainer.push_back(tmpContainer);
  1573. }
  1574. }
  1575. else
  1576. ++i;
  1577. }
  1578.  
  1579. while(!listContainer.empty())
  1580. {
  1581. Container* container = listContainer.front();
  1582. listContainer.pop_front();
  1583. for(ItemList::const_iterator it = container->getItems(), end = container->getEnd(); it != end; ++it)
  1584. {
  1585. Item* item = *it;
  1586. if(item->getID() == itemId && (subType == -1 || subType == item->getSubType()))
  1587. return item;
  1588.  
  1589. if((tmpContainer = item->getContainer()))
  1590. listContainer.push_back(tmpContainer);
  1591. }
  1592. }
  1593. return NULL;
  1594. }
  1595.  
  1596. bool Game::removeItemOfType(Cylinder* cylinder, uint16_t itemId, int32_t count, int32_t subType /*= -1*/)
  1597. {
  1598. if(cylinder == NULL || ((int32_t)cylinder->__getItemTypeCount(itemId, subType) < count))
  1599. return false;
  1600.  
  1601. if(count <= 0)
  1602. return true;
  1603.  
  1604. std::list<Container*> listContainer;
  1605. Container* tmpContainer = NULL;
  1606. Thing* thing = NULL;
  1607. Item* item = NULL;
  1608.  
  1609. for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex() && count > 0;)
  1610. {
  1611. if((thing = cylinder->__getThing(i)) && (item = thing->getItem()))
  1612. {
  1613. if(item->getID() == itemId)
  1614. {
  1615. if(item->isStackable())
  1616. {
  1617. if(item->getItemCount() > count)
  1618. {
  1619. internalRemoveItem(item, count);
  1620. count = 0;
  1621. }
  1622. else
  1623. {
  1624. count -= item->getItemCount();
  1625. internalRemoveItem(item);
  1626. }
  1627. }
  1628. else if(subType == -1 || subType == item->getSubType())
  1629. {
  1630. --count;
  1631. internalRemoveItem(item);
  1632. }
  1633. else
  1634. ++i;
  1635. }
  1636. else
  1637. {
  1638. ++i;
  1639. if((tmpContainer = item->getContainer()))
  1640. listContainer.push_back(tmpContainer);
  1641. }
  1642. }
  1643. else
  1644. ++i;
  1645. }
  1646.  
  1647. while(!listContainer.empty() && count > 0)
  1648. {
  1649. Container* container = listContainer.front();
  1650. listContainer.pop_front();
  1651. for(int32_t i = 0; i < (int32_t)container->size() && count > 0;)
  1652. {
  1653. Item* item = container->getItem(i);
  1654. if(item->getID() == itemId)
  1655. {
  1656. if(item->isStackable())
  1657. {
  1658. if(item->getItemCount() > count)
  1659. {
  1660. internalRemoveItem(item, count);
  1661. count = 0;
  1662. }
  1663. else
  1664. {
  1665. count-= item->getItemCount();
  1666. internalRemoveItem(item);
  1667. }
  1668. }
  1669. else if(subType == -1 || subType == item->getSubType())
  1670. {
  1671. --count;
  1672. internalRemoveItem(item);
  1673. }
  1674. else
  1675. ++i;
  1676. }
  1677. else
  1678. {
  1679. ++i;
  1680. if((tmpContainer = item->getContainer()))
  1681. listContainer.push_back(tmpContainer);
  1682. }
  1683. }
  1684. }
  1685. return (count == 0);
  1686. }
  1687.  
  1688. uint32_t Game::getMoney(const Cylinder* cylinder)
  1689. {
  1690. if(cylinder == NULL)
  1691. return 0;
  1692.  
  1693. std::list<Container*> listContainer;
  1694. ItemList::const_iterator it;
  1695. Container* tmpContainer;
  1696.  
  1697. Thing* thing;
  1698. Item* item;
  1699.  
  1700. uint32_t moneyCount = 0;
  1701. for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex(); ++i)
  1702. {
  1703. if(!(thing = cylinder->__getThing(i)))
  1704. continue;
  1705.  
  1706. if(!(item = thing->getItem()))
  1707. continue;
  1708.  
  1709. if((tmpContainer = item->getContainer()))
  1710. listContainer.push_back(tmpContainer);
  1711. else if(item->getWorth() != 0)
  1712. moneyCount += item->getWorth();
  1713. }
  1714.  
  1715. while(!listContainer.empty())
  1716. {
  1717. Container* container = listContainer.front();
  1718. listContainer.pop_front();
  1719.  
  1720. for(it = container->getItems(); it != container->getEnd(); ++it)
  1721. {
  1722. Item* item = *it;
  1723. if((tmpContainer = item->getContainer()))
  1724. listContainer.push_back(tmpContainer);
  1725. else if(item->getWorth() != 0)
  1726. moneyCount += item->getWorth();
  1727. }
  1728. }
  1729. return moneyCount;
  1730. }
  1731.  
  1732. bool Game::removeMoney(Cylinder* cylinder, int32_t money, uint32_t flags /*= 0*/)
  1733. {
  1734. if(cylinder == NULL)
  1735. return false;
  1736.  
  1737. if(money <= 0)
  1738. return true;
  1739.  
  1740. std::list<Container*> listContainer;
  1741. Container* tmpContainer = NULL;
  1742.  
  1743. typedef std::multimap<int, Item*, std::less<int> > MoneyMap;
  1744. typedef MoneyMap::value_type moneymap_pair;
  1745. MoneyMap moneyMap;
  1746. Thing* thing;
  1747. Item* item;
  1748. int32_t moneyCount = 0;
  1749.  
  1750. for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex(); ++i)
  1751. {
  1752. if(!(thing = cylinder->__getThing(i)))
  1753. continue;
  1754.  
  1755. if(!(item = thing->getItem()))
  1756. continue;
  1757.  
  1758. if((tmpContainer = item->getContainer()))
  1759. listContainer.push_back(tmpContainer);
  1760. else if(item->getWorth() != 0)
  1761. {
  1762. moneyCount += item->getWorth();
  1763. moneyMap.insert(moneymap_pair(item->getWorth(), item));
  1764. }
  1765. }
  1766.  
  1767. while(!listContainer.empty())
  1768. {
  1769. Container* container = listContainer.front();
  1770. listContainer.pop_front();
  1771.  
  1772. for(ItemList::const_iterator it = container->getItems(), end = container->getEnd(); it != end; ++it)
  1773. {
  1774. Item* item = *it;
  1775. if((tmpContainer = item->getContainer()))
  1776. listContainer.push_back(tmpContainer);
  1777. else if(item->getWorth() != 0)
  1778. {
  1779. moneyCount += item->getWorth();
  1780. moneyMap.insert(moneymap_pair(item->getWorth(), item));
  1781. }
  1782. }
  1783. }
  1784.  
  1785. /*not enough money*/
  1786. if(moneyCount < money)
  1787. return false;
  1788.  
  1789. MoneyMap::iterator mit, mend;
  1790. for(mit = moneyMap.begin(), mend = moneyMap.end(); mit != mend && money > 0; ++mit)
  1791. {
  1792. Item* item = mit->second;
  1793. internalRemoveItem(item);
  1794. if(mit->first > money)
  1795. {
  1796. /* Remove a monetary value from an item*/
  1797. int32_t remaind = item->getWorth() - money;
  1798. addMoney(cylinder, remaind, flags);
  1799. money = 0;
  1800. }
  1801. else
  1802. money -= mit->first;
  1803. }
  1804. return (money == 0);
  1805. }
  1806.  
  1807. void Game::addMoney(Cylinder* cylinder, int32_t money, uint32_t flags /*= 0*/)
  1808. {
  1809. int32_t crys = money / 10000;
  1810. money -= crys * 10000;
  1811. int32_t plat = money / 100;
  1812. money -= plat * 100;
  1813. int32_t gold = money;
  1814.  
  1815. if(crys != 0)
  1816. {
  1817. do
  1818. {
  1819. Item* remaindItem = Item::CreateItem(ITEM_COINS_CRYSTAL, std::min(100, crys));
  1820.  
  1821. ReturnValue ret = internalAddItem(cylinder, remaindItem, INDEX_WHEREEVER, flags);
  1822. if(ret != RET_NOERROR)
  1823. internalAddItem(cylinder->getTile(), remaindItem, INDEX_WHEREEVER, FLAG_NOLIMIT);
  1824.  
  1825. crys -= std::min(100, crys);
  1826. }
  1827. while(crys > 0);
  1828. }
  1829.  
  1830. if(plat != 0)
  1831. {
  1832. Item* remaindItem = Item::CreateItem(ITEM_COINS_PLATINUM, plat);
  1833.  
  1834. ReturnValue ret = internalAddItem(cylinder, remaindItem, INDEX_WHEREEVER, flags);
  1835. if(ret != RET_NOERROR)
  1836. internalAddItem(cylinder->getTile(), remaindItem, INDEX_WHEREEVER, FLAG_NOLIMIT);
  1837. }
  1838.  
  1839. if(gold != 0)
  1840. {
  1841. Item* remaindItem = Item::CreateItem(ITEM_COINS_GOLD, gold);
  1842.  
  1843. ReturnValue ret = internalAddItem(cylinder, remaindItem, INDEX_WHEREEVER, flags);
  1844. if(ret != RET_NOERROR)
  1845. internalAddItem(cylinder->getTile(), remaindItem, INDEX_WHEREEVER, FLAG_NOLIMIT);
  1846. }
  1847. }
  1848.  
  1849. Item* Game::transformItem(Item* item, uint16_t newId, int32_t newCount /*= -1*/)
  1850. {
  1851. if(item->getID() == newId && (newCount == -1 || (newCount == item->getSubType() && newCount != 0))) //chargeless item placed on map = infinite
  1852. return item;
  1853.  
  1854. Cylinder* cylinder = item->getParent();
  1855. if(cylinder == NULL)
  1856. return NULL;
  1857.  
  1858. int32_t itemIndex = cylinder->__getIndexOfThing(item);
  1859. if(itemIndex == -1)
  1860. {
  1861. #ifdef __DEBUG__
  1862. std::cout << "Error: transformItem, itemIndex == -1" << std::endl;
  1863. #endif
  1864. return item;
  1865. }
  1866.  
  1867. if(!item->canTransform())
  1868. return item;
  1869.  
  1870. const ItemType& curType = Item::items[item->getID()];
  1871. const ItemType& newType = Item::items[newId];
  1872.  
  1873. if(curType.alwaysOnTop != newType.alwaysOnTop)
  1874. {
  1875. //This only occurs when you transform items on tiles from a downItem to a topItem (or vice versa)
  1876. //Remove the old, and add the new
  1877. ReturnValue ret = internalRemoveItem(item);
  1878. if(ret != RET_NOERROR)
  1879. return item;
  1880.  
  1881. Item* newItem = NULL;
  1882. if(newCount == -1)
  1883. newItem = Item::CreateItem(newId);
  1884. else
  1885. newItem = Item::CreateItem(newId, newCount);
  1886.  
  1887. if(newItem == NULL)
  1888. {
  1889. #ifdef __DEBUG__
  1890. std::cout << "Error: [Game::transformItem] Item of type " << item->getID() << " transforming into invalid type " << newId << std::endl;
  1891. #endif
  1892. return NULL;
  1893. }
  1894.  
  1895. newItem->copyAttributes(item);
  1896.  
  1897. ret = internalAddItem(cylinder, newItem, INDEX_WHEREEVER, FLAG_NOLIMIT);
  1898. if(ret != RET_NOERROR)
  1899. {
  1900. delete newItem;
  1901. return NULL;
  1902. }
  1903. return newItem;
  1904. }
  1905.  
  1906. if(curType.type == newType.type)
  1907. {
  1908. //Both items has the same type so we can safely change id/subtype
  1909. if(newCount == 0 && (item->isStackable() || item->hasCharges()))
  1910. {
  1911. if(item->isStackable())
  1912. {
  1913. internalRemoveItem(item);
  1914. return NULL;
  1915. }
  1916. else
  1917. {
  1918. int32_t newItemId = newId;
  1919. if(curType.id == newType.id)
  1920. newItemId = curType.decayTo;
  1921.  
  1922. if(newItemId == -1)
  1923. {
  1924. internalRemoveItem(item);
  1925. return NULL;
  1926. }
  1927. else if(newItemId != newId)
  1928. {
  1929. //Replacing the the old item with the new while maintaining the old position
  1930. Item* newItem = Item::CreateItem(newItemId, 1);
  1931. if(newItem == NULL)
  1932. {
  1933. #ifdef __DEBUG__
  1934. std::cout << "Error: [Game::transformItem] Item of type " << item->getID() << " transforming into invalid type " << newItemId << std::endl;
  1935. #endif
  1936. return NULL;
  1937. }
  1938.  
  1939. cylinder->__replaceThing(itemIndex, newItem);
  1940. cylinder->postAddNotification(newItem, cylinder, itemIndex);
  1941.  
  1942. item->setParent(NULL);
  1943. cylinder->postRemoveNotification(item, cylinder, itemIndex, true);
  1944. FreeThing(item);
  1945. return newItem;
  1946. }
  1947. else
  1948. {
  1949. item = transformItem(item, newItemId);
  1950. return item;
  1951. }
  1952. }
  1953. }
  1954. else
  1955. {
  1956. cylinder->postRemoveNotification(item, cylinder, itemIndex, false);
  1957. uint16_t itemId = item->getID();
  1958. int32_t count = item->getSubType();
  1959.  
  1960. if(curType.id != newType.id)
  1961. {
  1962. if(newType.group != curType.group)
  1963. item->setDefaultSubtype();
  1964.  
  1965. itemId = newId;
  1966. }
  1967.  
  1968. if(newCount != -1 && newType.hasSubType())
  1969. count = newCount;
  1970.  
  1971. cylinder->__updateThing(item, itemId, count);
  1972. cylinder->postAddNotification(item, cylinder, itemIndex);
  1973. return item;
  1974. }
  1975. }
  1976. else
  1977. {
  1978. //Replacing the the old item with the new while maintaining the old position
  1979. Item* newItem = NULL;
  1980. if(newCount == -1)
  1981. newItem = Item::CreateItem(newId);
  1982. else
  1983. newItem = Item::CreateItem(newId, newCount);
  1984.  
  1985. if(newItem == NULL)
  1986. {
  1987. #ifdef __DEBUG__
  1988. std::cout << "Error: [Game::transformItem] Item of type " << item->getID() << " transforming into invalid type " << newId << std::endl;
  1989. #endif
  1990. return NULL;
  1991. }
  1992.  
  1993. cylinder->__replaceThing(itemIndex, newItem);
  1994. cylinder->postAddNotification(newItem, cylinder, itemIndex);
  1995.  
  1996. item->setParent(NULL);
  1997. cylinder->postRemoveNotification(item, cylinder, itemIndex, true);
  1998. FreeThing(item);
  1999.  
  2000. return newItem;
  2001. }
  2002. return NULL;
  2003. }
  2004.  
  2005. ReturnValue Game::internalTeleport(Thing* thing, const Position& newPos, bool pushMove/* = true*/, uint32_t flags /*= 0*/)
  2006. {
  2007. if(newPos == thing->getPosition())
  2008. return RET_NOERROR;
  2009. else if(thing->isRemoved())
  2010. return RET_NOTPOSSIBLE;
  2011.  
  2012. Tile* toTile = getTile(newPos.x, newPos.y, newPos.z);
  2013. if(toTile)
  2014. {
  2015. if(Creature* creature = thing->getCreature())
  2016. {
  2017. ReturnValue ret = toTile->__queryAdd(0, creature, 1, FLAG_NOLIMIT);
  2018. if(ret != RET_NOERROR)
  2019. return ret;
  2020.  
  2021. creature->getTile()->moveCreature(creature, toTile, !pushMove);
  2022. return RET_NOERROR;
  2023. }
  2024. else if(Item* item = thing->getItem())
  2025. return internalMoveItem(item->getParent(), toTile, INDEX_WHEREEVER, item, item->getItemCount(), NULL, flags);
  2026. }
  2027. return RET_NOTPOSSIBLE;
  2028. }
  2029.  
  2030. //Implementation of player invoked events
  2031. bool Game::playerMove(uint32_t playerId, Direction direction)
  2032. {
  2033. Player* player = getPlayerByID(playerId);
  2034. if(!player || player->isRemoved())
  2035. return false;
  2036.  
  2037. player->resetIdleTime();
  2038. player->setNextWalkActionTask(NULL);
  2039.  
  2040. std::list<Direction> dirs;
  2041. dirs.push_back(direction);
  2042. return player->startAutoWalk(dirs);
  2043. }
  2044.  
  2045. bool Game::playerBroadcastMessage(Player* player, const std::string& text)
  2046. {
  2047. if(!player->hasFlag(PlayerFlag_CanBroadcast))
  2048. return false;
  2049.  
  2050. std::cout << "> " << player->getName() << " broadcasted: \"" << text << "\"." << std::endl;
  2051. for(AutoList<Player>::listiterator it = Player::listPlayer.list.begin(); it != Player::listPlayer.list.end(); ++it)
  2052. (*it).second->sendCreatureSay(player, SPEAK_BROADCAST, text);
  2053.  
  2054. return true;
  2055. }
  2056.  
  2057. bool Game::playerCreatePrivateChannel(uint32_t playerId)
  2058. {
  2059. Player* player = getPlayerByID(playerId);
  2060. if(!player || player->isRemoved() || !player->isPremium())
  2061. return false;
  2062.  
  2063. ChatChannel* channel = g_chat.createChannel(player, CHANNEL_PRIVATE);
  2064. if(!channel || !channel->addUser(player))
  2065. return false;
  2066.  
  2067. player->sendCreatePrivateChannel(channel->getId(), channel->getName());
  2068. return true;
  2069. }
  2070.  
  2071. bool Game::playerChannelInvite(uint32_t playerId, const std::string& name)
  2072. {
  2073. Player* player = getPlayerByID(playerId);
  2074. if(!player || player->isRemoved())
  2075. return false;
  2076.  
  2077. PrivateChatChannel* channel = g_chat.getPrivateChannel(player);
  2078. if(!channel)
  2079. return false;
  2080.  
  2081. Player* invitePlayer = getPlayerByName(name);
  2082. if(!invitePlayer)
  2083. return false;
  2084.  
  2085. channel->invitePlayer(player, invitePlayer);
  2086. return true;
  2087. }
  2088.  
  2089. bool Game::playerChannelExclude(uint32_t playerId, const std::string& name)
  2090. {
  2091. Player* player = getPlayerByID(playerId);
  2092. if(!player || player->isRemoved())
  2093. return false;
  2094.  
  2095. PrivateChatChannel* channel = g_chat.getPrivateChannel(player);
  2096. if(!channel)
  2097. return false;
  2098.  
  2099. Player* excludePlayer = getPlayerByName(name);
  2100. if(!excludePlayer)
  2101. return false;
  2102.  
  2103. channel->excludePlayer(player, excludePlayer);
  2104. return true;
  2105. }
  2106.  
  2107. bool Game::playerRequestChannels(uint32_t playerId)
  2108. {
  2109. Player* player = getPlayerByID(playerId);
  2110. if(!player || player->isRemoved())
  2111. return false;
  2112.  
  2113. player->sendChannelsDialog();
  2114. return true;
  2115. }
  2116.  
  2117. bool Game::playerOpenChannel(uint32_t playerId, uint16_t channelId)
  2118. {
  2119. Player* player = getPlayerByID(playerId);
  2120. if(!player || player->isRemoved())
  2121. return false;
  2122.  
  2123. ChatChannel* channel = g_chat.addUserToChannel(player, channelId);
  2124. if(!channel)
  2125. return false;
  2126.  
  2127. player->sendChannel(channel->getId(), channel->getName());
  2128. return true;
  2129. }
  2130.  
  2131. bool Game::playerCloseChannel(uint32_t playerId, uint16_t channelId)
  2132. {
  2133. Player* player = getPlayerByID(playerId);
  2134. if(!player || player->isRemoved())
  2135. return false;
  2136.  
  2137. g_chat.removeUserFromChannel(player, channelId);
  2138. return true;
  2139. }
  2140.  
  2141. bool Game::playerOpenPrivateChannel(uint32_t playerId, std::string& receiver)
  2142. {
  2143. Player* player = getPlayerByID(playerId);
  2144. if(!player || player->isRemoved())
  2145. return false;
  2146.  
  2147. if(!IOLoginData::getInstance()->playerExists(receiver))
  2148. {
  2149. player->sendCancel("A player with this name does not exist.");
  2150. return true;
  2151. }
  2152.  
  2153. player->sendOpenPrivateChannel(receiver);
  2154. return true;
  2155. }
  2156.  
  2157. bool Game::playerCloseNpcChannel(uint32_t playerId)
  2158. {
  2159. Player* player = getPlayerByID(playerId);
  2160. if(!player || player->isRemoved())
  2161. return false;
  2162.  
  2163. SpectatorVec list;
  2164. SpectatorVec::iterator it;
  2165. getSpectators(list, player->getPosition());
  2166. Npc* npc;
  2167.  
  2168. for(it = list.begin(); it != list.end(); ++it)
  2169. {
  2170. if((npc = (*it)->getNpc()))
  2171. npc->onPlayerCloseChannel(player);
  2172. }
  2173. return true;
  2174. }
  2175.  
  2176. bool Game::playerReceivePing(uint32_t playerId)
  2177. {
  2178. Player* player = getPlayerByID(playerId);
  2179. if(!player || player->isRemoved())
  2180. return false;
  2181.  
  2182. player->receivePing();
  2183. return true;
  2184. }
  2185.  
  2186. bool Game::playerReceivePingBack(uint32_t playerId)
  2187. {
  2188. Player* player = getPlayerByID(playerId);
  2189. if(!player || player->isRemoved())
  2190. return false;
  2191.  
  2192. player->sendPingBack();
  2193. return true;
  2194. }
  2195.  
  2196. bool Game::playerAutoWalk(uint32_t playerId, std::list<Direction>& listDir)
  2197. {
  2198. Player* player = getPlayerByID(playerId);
  2199. if(!player || player->isRemoved())
  2200. return false;
  2201.  
  2202. player->resetIdleTime();
  2203. player->setNextWalkTask(NULL);
  2204. return player->startAutoWalk(listDir);
  2205. }
  2206.  
  2207. bool Game::playerStopAutoWalk(uint32_t playerId)
  2208. {
  2209. Player* player = getPlayerByID(playerId);
  2210. if(!player || player->isRemoved())
  2211. return false;
  2212.  
  2213. player->stopWalk();
  2214. return true;
  2215. }
  2216.  
  2217. bool Game::playerUseItemEx(uint32_t playerId, const Position& fromPos, uint8_t fromStackPos, uint16_t fromSpriteId,
  2218. const Position& toPos, uint8_t toStackPos, uint16_t toSpriteId, bool isHotkey)
  2219. {
  2220. Player* player = getPlayerByID(playerId);
  2221. if(!player || player->isRemoved())
  2222. return false;
  2223.  
  2224. if(isHotkey && !g_config.getBoolean(ConfigManager::AIMBOT_HOTKEY_ENABLED))
  2225. return false;
  2226.  
  2227. Thing* thing = internalGetThing(player, fromPos, fromStackPos, fromSpriteId, STACKPOS_USEITEM);
  2228. if(!thing)
  2229. {
  2230. player->sendCancelMessage(RET_NOTPOSSIBLE);
  2231. return false;
  2232. }
  2233.  
  2234. Item* item = thing->getItem();
  2235. if(!item || !item->isUseable())
  2236. {
  2237. player->sendCancelMessage(RET_CANNOTUSETHISOBJECT);
  2238. return false;
  2239. }
  2240.  
  2241. Position walkToPos = fromPos;
  2242. ReturnValue ret = g_actions->canUse(player, fromPos);
  2243. if(ret == RET_NOERROR)
  2244. {
  2245. ret = g_actions->canUse(player, toPos, item);
  2246. if(ret == RET_TOOFARAWAY)
  2247. walkToPos = toPos;
  2248. }
  2249.  
  2250. if(ret != RET_NOERROR)
  2251. {
  2252. if(ret == RET_TOOFARAWAY)
  2253. {
  2254. Position itemPos = fromPos;
  2255. uint8_t itemStackPos = fromStackPos;
  2256.  
  2257. if(fromPos.x != 0xFFFF && toPos.x != 0xFFFF && Position::areInRange<1,1,0>(fromPos, player->getPosition()) &&
  2258. !Position::areInRange<1,1,0>(fromPos, toPos))
  2259. {
  2260. Item* moveItem = NULL;
  2261.  
  2262. ReturnValue ret = internalMoveItem(item->getParent(), player, INDEX_WHEREEVER,
  2263. item, item->getItemCount(), &moveItem);
  2264. if(ret != RET_NOERROR)
  2265. {
  2266. player->sendCancelMessage(ret);
  2267. return false;
  2268. }
  2269.  
  2270. //changing the position since its now in the inventory of the player
  2271. internalGetPosition(moveItem, itemPos, itemStackPos);
  2272. }
  2273.  
  2274. std::list<Direction> listDir;
  2275. if(getPathToEx(player, walkToPos, listDir, 0, 1, true, true))
  2276. {
  2277. g_dispatcher.addTask(createTask(boost::bind(&Game::playerAutoWalk,
  2278. this, player->getID(), listDir)));
  2279.  
  2280. SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerUseItemEx, this,
  2281. playerId, itemPos, itemStackPos, fromSpriteId, toPos, toStackPos, toSpriteId, isHotkey));
  2282. player->setNextWalkActionTask(task);
  2283. return true;
  2284. }
  2285. else
  2286. {
  2287. player->sendCancelMessage(RET_THEREISNOWAY);
  2288. return false;
  2289. }
  2290. }
  2291.  
  2292. player->sendCancelMessage(ret);
  2293. return false;
  2294. }
  2295.  
  2296. if(!player->canDoAction())
  2297. {
  2298. uint32_t delay = player->getNextActionTime();
  2299. SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerUseItemEx, this,
  2300. playerId, fromPos, fromStackPos, fromSpriteId, toPos, toStackPos, toSpriteId, isHotkey));
  2301. player->setNextActionTask(task);
  2302. return false;
  2303. }
  2304.  
  2305. player->resetIdleTime();
  2306. player->setNextActionTask(NULL);
  2307.  
  2308. return g_actions->useItemEx(player, fromPos, toPos, toStackPos, item, isHotkey);
  2309. }
  2310.  
  2311. bool Game::playerUseItem(uint32_t playerId, const Position& pos, uint8_t stackPos,
  2312. uint8_t index, uint16_t spriteId, bool isHotkey)
  2313. {
  2314. Player* player = getPlayerByID(playerId);
  2315. if(!player || player->isRemoved())
  2316. return false;
  2317.  
  2318. if(isHotkey && !g_config.getBoolean(ConfigManager::AIMBOT_HOTKEY_ENABLED))
  2319. return false;
  2320.  
  2321. Thing* thing = internalGetThing(player, pos, stackPos, spriteId, STACKPOS_USEITEM);
  2322. if(!thing)
  2323. {
  2324. player->sendCancelMessage(RET_NOTPOSSIBLE);
  2325. return false;
  2326. }
  2327.  
  2328. Item* item = thing->getItem();
  2329. if(!item || item->isUseable())
  2330. {
  2331. player->sendCancelMessage(RET_CANNOTUSETHISOBJECT);
  2332. return false;
  2333. }
  2334.  
  2335. ReturnValue ret = g_actions->canUse(player, pos);
  2336. if(ret != RET_NOERROR)
  2337. {
  2338. if(ret == RET_TOOFARAWAY)
  2339. {
  2340. std::list<Direction> listDir;
  2341. if(getPathToEx(player, pos, listDir, 0, 1, true, true))
  2342. {
  2343. g_dispatcher.addTask(createTask(boost::bind(&Game::playerAutoWalk,
  2344. this, player->getID(), listDir)));
  2345.  
  2346. SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerUseItem, this,
  2347. playerId, pos, stackPos, index, spriteId, isHotkey));
  2348. player->setNextWalkActionTask(task);
  2349. return true;
  2350. }
  2351. ret = RET_THEREISNOWAY;
  2352. }
  2353. player->sendCancelMessage(ret);
  2354. return false;
  2355. }
  2356.  
  2357. if(!player->canDoAction())
  2358. {
  2359. uint32_t delay = player->getNextActionTime();
  2360. SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerUseItem, this,
  2361. playerId, pos, stackPos, index, spriteId, isHotkey));
  2362. player->setNextActionTask(task);
  2363. return false;
  2364. }
  2365.  
  2366. player->resetIdleTime();
  2367. player->setNextActionTask(NULL);
  2368.  
  2369. g_actions->useItem(player, pos, index, item, isHotkey);
  2370. return true;
  2371. }
  2372.  
  2373. bool Game::playerUseBattleWindow(uint32_t playerId, const Position& fromPos, uint8_t fromStackPos,
  2374. uint32_t creatureId, uint16_t spriteId, bool isHotkey)
  2375. {
  2376. Player* player = getPlayerByID(playerId);
  2377. if(!player || player->isRemoved())
  2378. return false;
  2379.  
  2380. Creature* creature = getCreatureByID(creatureId);
  2381. if(!creature)
  2382. return false;
  2383.  
  2384. if(!Position::areInRange<7,5,0>(creature->getPosition(), player->getPosition()))
  2385. return false;
  2386.  
  2387. if(!g_config.getBoolean(ConfigManager::AIMBOT_HOTKEY_ENABLED))
  2388. {
  2389. if(creature->getPlayer() || isHotkey)
  2390. {
  2391. player->sendCancelMessage(RET_DIRECTPLAYERSHOOT);
  2392. return false;
  2393. }
  2394. }
  2395.  
  2396. Thing* thing = internalGetThing(player, fromPos, fromStackPos, spriteId, STACKPOS_USE);
  2397. if(!thing)
  2398. {
  2399. player->sendCancelMessage(RET_NOTPOSSIBLE);
  2400. return false;
  2401. }
  2402.  
  2403. Item* item = thing->getItem();
  2404. if(!item || item->getClientID() != spriteId)
  2405. {
  2406. player->sendCancelMessage(RET_CANNOTUSETHISOBJECT);
  2407. return false;
  2408. }
  2409.  
  2410. ReturnValue ret = g_actions->canUse(player, fromPos);
  2411. if(ret != RET_NOERROR)
  2412. {
  2413. if(ret == RET_TOOFARAWAY)
  2414. {
  2415. std::list<Direction> listDir;
  2416. if(getPathToEx(player, item->getPosition(), listDir, 0, 1, true, true))
  2417. {
  2418. g_dispatcher.addTask(createTask(boost::bind(&Game::playerAutoWalk,
  2419. this, player->getID(), listDir)));
  2420.  
  2421. SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerUseBattleWindow, this,
  2422. playerId, fromPos, fromStackPos, creatureId, spriteId, isHotkey));
  2423. player->setNextWalkActionTask(task);
  2424. return true;
  2425. }
  2426. ret = RET_THEREISNOWAY;
  2427. }
  2428. player->sendCancelMessage(ret);
  2429. return false;
  2430. }
  2431.  
  2432. if(!player->canDoAction())
  2433. {
  2434. uint32_t delay = player->getNextActionTime();
  2435. SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerUseBattleWindow, this,
  2436. playerId, fromPos, fromStackPos, creatureId, spriteId, isHotkey));
  2437. player->setNextActionTask(task);
  2438. return false;
  2439. }
  2440.  
  2441. player->setNextActionTask(NULL);
  2442. player->resetIdleTime();
  2443.  
  2444. return g_actions->useItemEx(player, fromPos, creature->getPosition(), creature->getParent()->__getIndexOfThing(creature), item, isHotkey, creatureId);
  2445. }
  2446.  
  2447. bool Game::playerCloseContainer(uint32_t playerId, uint8_t cid)
  2448. {
  2449. Player* player = getPlayerByID(playerId);
  2450. if(!player || player->isRemoved())
  2451. return false;
  2452.  
  2453. player->closeContainer(cid);
  2454. player->sendCloseContainer(cid);
  2455. return true;
  2456. }
  2457.  
  2458. bool Game::playerMoveUpContainer(uint32_t playerId, uint8_t cid)
  2459. {
  2460. Player* player = getPlayerByID(playerId);
  2461. if(!player || player->isRemoved())
  2462. return false;
  2463.  
  2464. Container* container = player->getContainer(cid);
  2465. if(!container)
  2466. return false;
  2467.  
  2468. Container* parentContainer = dynamic_cast<Container*>(container->getParent());
  2469. if(!parentContainer)
  2470. return false;
  2471.  
  2472. bool hasParent = (dynamic_cast<const Container*>(parentContainer->getParent()) != NULL);
  2473. player->addContainer(cid, parentContainer);
  2474. player->sendContainer(cid, parentContainer, hasParent);
  2475. return true;
  2476. }
  2477.  
  2478. bool Game::playerUpdateTile(uint32_t playerId, const Position& pos)
  2479. {
  2480. Player* player = getPlayerByID(playerId);
  2481. if(!player || player->isRemoved())
  2482. return false;
  2483.  
  2484. if(player->canSee(pos))
  2485. {
  2486. Tile* tile = getTile(pos.x, pos.y, pos.z);
  2487. player->sendUpdateTile(tile, pos);
  2488. return true;
  2489. }
  2490. return false;
  2491. }
  2492.  
  2493. bool Game::playerUpdateContainer(uint32_t playerId, uint8_t cid)
  2494. {
  2495. Player* player = getPlayerByID(playerId);
  2496. if(!player || player->isRemoved())
  2497. return false;
  2498.  
  2499. Container* container = player->getContainer(cid);
  2500. if(!container)
  2501. return false;
  2502.  
  2503. bool hasParent = (dynamic_cast<const Container*>(container->getParent()) != NULL);
  2504. player->sendContainer(cid, container, hasParent);
  2505. return true;
  2506. }
  2507.  
  2508. bool Game::playerRotateItem(uint32_t playerId, const Position& pos, uint8_t stackPos, const uint16_t spriteId)
  2509. {
  2510. Player* player = getPlayerByID(playerId);
  2511. if(!player || player->isRemoved())
  2512. return false;
  2513.  
  2514. Thing* thing = internalGetThing(player, pos, stackPos);
  2515. if(!thing)
  2516. return false;
  2517.  
  2518. Item* item = thing->getItem();
  2519. if(!item || item->getClientID() != spriteId || !item->isRoteable() || item->getUniqueId() != 0)
  2520. {
  2521. player->sendCancelMessage(RET_NOTPOSSIBLE);
  2522. return false;
  2523. }
  2524.  
  2525. if(pos.x != 0xFFFF && !Position::areInRange<1,1,0>(pos, player->getPosition()))
  2526. {
  2527. std::list<Direction> listDir;
  2528. if(getPathToEx(player, pos, listDir, 0, 1, true, true))
  2529. {
  2530. g_dispatcher.addTask(createTask(boost::bind(&Game::playerAutoWalk,
  2531. this, player->getID(), listDir)));
  2532.  
  2533. SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerRotateItem, this,
  2534. playerId, pos, stackPos, spriteId));
  2535. player->setNextWalkActionTask(task);
  2536. return true;
  2537. }
  2538. else
  2539. {
  2540. player->sendCancelMessage(RET_THEREISNOWAY);
  2541. return false;
  2542. }
  2543. }
  2544.  
  2545. uint16_t newId = Item::items[item->getID()].rotateTo;
  2546. if(newId != 0)
  2547. transformItem(item, newId);
  2548.  
  2549. return true;
  2550. }
  2551.  
  2552. bool Game::playerWriteItem(uint32_t playerId, uint32_t windowTextId, const std::string& text)
  2553. {
  2554. Player* player = getPlayerByID(playerId);
  2555. if(!player || player->isRemoved())
  2556. return false;
  2557.  
  2558. uint16_t maxTextLength = 0;
  2559. uint32_t internalWindowTextId = 0;
  2560. Item* writeItem = player->getWriteItem(internalWindowTextId, maxTextLength);
  2561.  
  2562. if(text.length() > maxTextLength || windowTextId != internalWindowTextId)
  2563. return false;
  2564.  
  2565. if(!writeItem || writeItem->isRemoved())
  2566. {
  2567. player->sendCancelMessage(RET_NOTPOSSIBLE);
  2568. return false;
  2569. }
  2570.  
  2571. Cylinder* topParent = writeItem->getTopParent();
  2572. Player* owner = dynamic_cast<Player*>(topParent);
  2573. if(owner && owner != player)
  2574. {
  2575. player->sendCancelMessage(RET_NOTPOSSIBLE);
  2576. return false;
  2577. }
  2578.  
  2579. if(!Position::areInRange<1,1,0>(writeItem->getPosition(), player->getPosition()))
  2580. {
  2581. player->sendCancelMessage(RET_NOTPOSSIBLE);
  2582. return false;
  2583. }
  2584.  
  2585. if(!text.empty())
  2586. {
  2587. if(writeItem->getText() != text)
  2588. {
  2589. writeItem->setText(text);
  2590. writeItem->setWriter(player->getName());
  2591. writeItem->setDate(std::time(NULL));
  2592. }
  2593. }
  2594. else
  2595. {
  2596. writeItem->resetText();
  2597. writeItem->resetWriter();
  2598. writeItem->resetDate();
  2599. }
  2600.  
  2601. uint16_t newId = Item::items[writeItem->getID()].writeOnceItemId;
  2602. if(newId != 0)
  2603. transformItem(writeItem, newId);
  2604.  
  2605. player->setWriteItem(NULL);
  2606. return true;
  2607. }
  2608.  
  2609. bool Game::playerUpdateHouseWindow(uint32_t playerId, uint8_t listId, uint32_t windowTextId, const std::string& text)
  2610. {
  2611. Player* player = getPlayerByID(playerId);
  2612. if(!player || player->isRemoved())
  2613. return false;
  2614.  
  2615. uint32_t internalWindowTextId;
  2616. uint32_t internalListId;
  2617. House* house = player->getEditHouse(internalWindowTextId, internalListId);
  2618. if(house && internalWindowTextId == windowTextId && listId == 0)
  2619. {
  2620. house->setAccessList(internalListId, text);
  2621. player->setEditHouse(NULL);
  2622. }
  2623. return true;
  2624. }
  2625.  
  2626. bool Game::playerRequestTrade(uint32_t playerId, const Position& pos, uint8_t stackPos,
  2627. uint32_t tradePlayerId, uint16_t spriteId)
  2628. {
  2629. Player* player = getPlayerByID(playerId);
  2630. if(!player || player->isRemoved())
  2631. return false;
  2632.  
  2633. Player* tradePartner = getPlayerByID(tradePlayerId);
  2634. if(!tradePartner || tradePartner == player)
  2635. {
  2636. player->sendTextMessage(MSG_INFO_DESCR, "Sorry, not possible.");
  2637. return false;
  2638. }
  2639.  
  2640. if(!Position::areInRange<2,2,0>(tradePartner->getPosition(), player->getPosition()))
  2641. {
  2642. std::ostringstream ss;
  2643. ss << tradePartner->getName() << " tells you to move closer.";
  2644. player->sendTextMessage(MSG_INFO_DESCR, ss.str());
  2645. return false;
  2646. }
  2647.  
  2648. if(!canThrowObjectTo(tradePartner->getPosition(), player->getPosition()))
  2649. {
  2650. player->sendCancelMessage(RET_CREATUREISNOTREACHABLE);
  2651. return false;
  2652. }
  2653.  
  2654. Item* tradeItem = dynamic_cast<Item*>(internalGetThing(player, pos, stackPos, spriteId, STACKPOS_USE));
  2655. if(!tradeItem || tradeItem->getClientID() != spriteId || !tradeItem->isPickupable() || tradeItem->getUniqueId() != 0)
  2656. {
  2657. player->sendCancelMessage(RET_NOTPOSSIBLE);
  2658. return false;
  2659. }
  2660.  
  2661. const Position& playerPosition = player->getPosition();
  2662. const Position& tradeItemPosition = tradeItem->getPosition();
  2663. if(playerPosition.z > tradeItemPosition.z)
  2664. {
  2665. player->sendCancelMessage(RET_FIRSTGOUPSTAIRS);
  2666. return false;
  2667. }
  2668. else if(playerPosition.z < tradeItemPosition.z)
  2669. {
  2670. player->sendCancelMessage(RET_FIRSTGODOWNSTAIRS);
  2671. return false;
  2672. }
  2673. else if(!Position::areInRange<1,1,0>(tradeItemPosition, playerPosition))
  2674. {
  2675. std::list<Direction> listDir;
  2676. if(getPathToEx(player, pos, listDir, 0, 1, true, true))
  2677. {
  2678. g_dispatcher.addTask(createTask(boost::bind(&Game::playerAutoWalk,
  2679. this, player->getID(), listDir)));
  2680.  
  2681. SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerRequestTrade, this,
  2682. playerId, pos, stackPos, tradePlayerId, spriteId));
  2683. player->setNextWalkActionTask(task);
  2684. return true;
  2685. }
  2686. else
  2687. {
  2688. player->sendCancelMessage(RET_THEREISNOWAY);
  2689. return false;
  2690. }
  2691. }
  2692.  
  2693. const Container* container = NULL;
  2694. std::map<Item*, uint32_t>::const_iterator it;
  2695. for(it = tradeItems.begin(); it != tradeItems.end(); ++it)
  2696. {
  2697. if(tradeItem == it->first ||
  2698. ((container = dynamic_cast<const Container*>(tradeItem)) && container->isHoldingItem(it->first)) ||
  2699. ((container = dynamic_cast<const Container*>(it->first)) && container->isHoldingItem(tradeItem)))
  2700. {
  2701. player->sendTextMessage(MSG_INFO_DESCR, "This item is already being traded.");
  2702. return false;
  2703. }
  2704. }
  2705.  
  2706. Container* tradeContainer = tradeItem->getContainer();
  2707. if(tradeContainer && tradeContainer->getItemHoldingCount() + 1 > 100)
  2708. {
  2709. player->sendTextMessage(MSG_INFO_DESCR, "You can not trade more than 100 items.");
  2710. return false;
  2711. }
  2712. return internalStartTrade(player, tradePartner, tradeItem);
  2713. }
  2714.  
  2715. bool Game::internalStartTrade(Player* player, Player* tradePartner, Item* tradeItem)
  2716. {
  2717. if(player->tradeState != TRADE_NONE && !(player->tradeState == TRADE_ACKNOWLEDGE && player->tradePartner == tradePartner))
  2718. {
  2719. player->sendCancelMessage(RET_YOUAREALREADYTRADING);
  2720. return false;
  2721. }
  2722. else if(tradePartner->tradeState != TRADE_NONE && tradePartner->tradePartner != player)
  2723. {
  2724. player->sendCancelMessage(RET_THISPLAYERISALREADYTRADING);
  2725. return false;
  2726. }
  2727.  
  2728. player->tradePartner = tradePartner;
  2729. player->tradeItem = tradeItem;
  2730. player->tradeState = TRADE_INITIATED;
  2731. tradeItem->useThing2();
  2732. tradeItems[tradeItem] = player->getID();
  2733.  
  2734. player->sendTradeItemRequest(player, tradeItem, true);
  2735.  
  2736. if(tradePartner->tradeState == TRADE_NONE)
  2737. {
  2738. std::ostringstream ss;
  2739. ss << player->getName() << " wants to trade with you";
  2740. tradePartner->sendTextMessage(MSG_INFO_DESCR, ss.str());
  2741. tradePartner->tradeState = TRADE_ACKNOWLEDGE;
  2742. tradePartner->tradePartner = player;
  2743. }
  2744. else
  2745. {
  2746. Item* counterOfferItem = tradePartner->tradeItem;
  2747. player->sendTradeItemRequest(tradePartner, counterOfferItem, false);
  2748. tradePartner->sendTradeItemRequest(player, tradeItem, false);
  2749. }
  2750. return true;
  2751. }
  2752.  
  2753. bool Game::playerAcceptTrade(uint32_t playerId)
  2754. {
  2755. Player* player = getPlayerByID(playerId);
  2756. if(!player || player->isRemoved())
  2757. return false;
  2758.  
  2759. if(!(player->getTradeState() == TRADE_ACKNOWLEDGE || player->getTradeState() == TRADE_INITIATED))
  2760. return false;
  2761.  
  2762. Player* tradePartner = player->tradePartner;
  2763. if(!tradePartner)
  2764. return false;
  2765.  
  2766. if(!canThrowObjectTo(tradePartner->getPosition(), player->getPosition()))
  2767. {
  2768. player->sendCancelMessage(RET_CREATUREISNOTREACHABLE);
  2769. return false;
  2770. }
  2771.  
  2772. player->setTradeState(TRADE_ACCEPT);
  2773. if(tradePartner->getTradeState() == TRADE_ACCEPT)
  2774. {
  2775. Item* tradeItem1 = player->tradeItem;
  2776. Item* tradeItem2 = tradePartner->tradeItem;
  2777.  
  2778. player->setTradeState(TRADE_TRANSFER);
  2779. tradePartner->setTradeState(TRADE_TRANSFER);
  2780.  
  2781. std::map<Item*, uint32_t>::iterator it;
  2782.  
  2783. it = tradeItems.find(tradeItem1);
  2784. if(it != tradeItems.end())
  2785. {
  2786. FreeThing(it->first);
  2787. tradeItems.erase(it);
  2788. }
  2789.  
  2790. it = tradeItems.find(tradeItem2);
  2791. if(it != tradeItems.end())
  2792. {
  2793. FreeThing(it->first);
  2794. tradeItems.erase(it);
  2795. }
  2796.  
  2797. bool isSuccess = false;
  2798.  
  2799. ReturnValue ret1 = internalAddItem(tradePartner, tradeItem1, INDEX_WHEREEVER, 0, true);
  2800. ReturnValue ret2 = internalAddItem(player, tradeItem2, INDEX_WHEREEVER, 0, true);
  2801.  
  2802. if(ret1 == RET_NOERROR && ret2 == RET_NOERROR)
  2803. {
  2804. ret1 = internalRemoveItem(tradeItem1, tradeItem1->getItemCount(), true);
  2805. ret2 = internalRemoveItem(tradeItem2, tradeItem2->getItemCount(), true);
  2806. if(ret1 == RET_NOERROR && ret2 == RET_NOERROR)
  2807. {
  2808. Cylinder* cylinder1 = tradeItem1->getParent();
  2809. Cylinder* cylinder2 = tradeItem2->getParent();
  2810.  
  2811. uint32_t count1 = tradeItem1->getItemCount();
  2812. uint32_t count2 = tradeItem2->getItemCount();
  2813.  
  2814. internalMoveItem(cylinder1, tradePartner, INDEX_WHEREEVER, tradeItem1, count1, NULL, FLAG_IGNOREAUTOSTACK);
  2815. internalMoveItem(cylinder2, player, INDEX_WHEREEVER, tradeItem2, count2, NULL, FLAG_IGNOREAUTOSTACK);
  2816.  
  2817. tradeItem1->onTradeEvent(ON_TRADE_TRANSFER, tradePartner);
  2818. tradeItem2->onTradeEvent(ON_TRADE_TRANSFER, player);
  2819.  
  2820. isSuccess = true;
  2821. }
  2822. }
  2823.  
  2824. if(!isSuccess)
  2825. {
  2826. std::string errorDescription;
  2827. if(tradePartner->tradeItem)
  2828. {
  2829. errorDescription = getTradeErrorDescription(ret1, tradeItem1);
  2830. tradePartner->sendTextMessage(MSG_INFO_DESCR, errorDescription);
  2831. tradePartner->tradeItem->onTradeEvent(ON_TRADE_CANCEL, tradePartner);
  2832. }
  2833.  
  2834. if(player->tradeItem)
  2835. {
  2836. errorDescription = getTradeErrorDescription(ret2, tradeItem2);
  2837. player->sendTextMessage(MSG_INFO_DESCR, errorDescription);
  2838. player->tradeItem->onTradeEvent(ON_TRADE_CANCEL, player);
  2839. }
  2840. }
  2841.  
  2842. player->setTradeState(TRADE_NONE);
  2843. player->tradeItem = NULL;
  2844. player->tradePartner = NULL;
  2845. player->sendTradeClose();
  2846.  
  2847. tradePartner->setTradeState(TRADE_NONE);
  2848. tradePartner->tradeItem = NULL;
  2849. tradePartner->tradePartner = NULL;
  2850. tradePartner->sendTradeClose();
  2851. return isSuccess;
  2852. }
  2853. return false;
  2854. }
  2855.  
  2856. std::string Game::getTradeErrorDescription(ReturnValue ret, Item* item)
  2857. {
  2858. std::ostringstream ss;
  2859. if(item)
  2860. {
  2861. if(ret == RET_NOTENOUGHCAPACITY)
  2862. {
  2863. ss << "You do not have enough capacity to carry";
  2864. if(item->isStackable() && item->getItemCount() > 1)
  2865. ss << " these objects.";
  2866. else
  2867. ss << " this object." ;
  2868.  
  2869. ss << std::endl << " " << item->getWeightDescription();
  2870. }
  2871. else if(ret == RET_NOTENOUGHROOM || ret == RET_CONTAINERNOTENOUGHROOM)
  2872. {
  2873. ss << "You do not have enough room to carry";
  2874. if(item->isStackable() && item->getItemCount() > 1)
  2875. ss << " these objects.";
  2876. else
  2877. ss << " this object.";
  2878. }
  2879. return ss.str();
  2880. }
  2881.  
  2882. ss << "Trade could not be completed.";
  2883. return ss.str().c_str();
  2884. }
  2885.  
  2886. bool Game::playerLookInTrade(uint32_t playerId, bool lookAtCounterOffer, int index)
  2887. {
  2888. Player* player = getPlayerByID(playerId);
  2889. if(!player || player->isRemoved())
  2890. return false;
  2891.  
  2892. Player* tradePartner = player->tradePartner;
  2893. if(!tradePartner)
  2894. return false;
  2895.  
  2896. Item* tradeItem = NULL;
  2897.  
  2898. if(lookAtCounterOffer)
  2899. tradeItem = tradePartner->getTradeItem();
  2900. else
  2901. tradeItem = player->getTradeItem();
  2902.  
  2903. if(!tradeItem)
  2904. return false;
  2905.  
  2906. const Position& playerPosition = player->getPosition();
  2907. const Position& tradeItemPosition = tradeItem->getPosition();
  2908. int32_t lookDistance = std::max(std::abs(playerPosition.x - tradeItemPosition.x),
  2909. std::abs(playerPosition.y - tradeItemPosition.y));
  2910.  
  2911. std::ostringstream ss;
  2912. if(index == 0)
  2913. {
  2914. ss << "You see " << tradeItem->getDescription(lookDistance);
  2915. player->sendTextMessage(MSG_INFO_DESCR, ss.str());
  2916. return false;
  2917. }
  2918.  
  2919. Container* tradeContainer = tradeItem->getContainer();
  2920. if(!tradeContainer || index > (int32_t)tradeContainer->getItemHoldingCount())
  2921. return false;
  2922.  
  2923. bool foundItem = false;
  2924. std::list<const Container*> listContainer;
  2925. ItemList::const_iterator it;
  2926. Container* tmpContainer = NULL;
  2927.  
  2928. listContainer.push_back(tradeContainer);
  2929. while(!foundItem && !listContainer.empty())
  2930. {
  2931. const Container* container = listContainer.front();
  2932. listContainer.pop_front();
  2933. for(it = container->getItems(); it != container->getEnd(); ++it)
  2934. {
  2935. if((tmpContainer = (*it)->getContainer()))
  2936. listContainer.push_back(tmpContainer);
  2937. --index;
  2938. if(index == 0)
  2939. {
  2940. tradeItem = *it;
  2941. foundItem = true;
  2942. break;
  2943. }
  2944. }
  2945. }
  2946.  
  2947. if(foundItem)
  2948. {
  2949. ss << "You see " << tradeItem->getDescription(lookDistance);
  2950. player->sendTextMessage(MSG_INFO_DESCR, ss.str());
  2951. }
  2952. return foundItem;
  2953. }
  2954.  
  2955. bool Game::playerCloseTrade(uint32_t playerId)
  2956. {
  2957. Player* player = getPlayerByID(playerId);
  2958. if(!player || player->isRemoved())
  2959. return false;
  2960.  
  2961. return internalCloseTrade(player);
  2962. }
  2963.  
  2964. bool Game::internalCloseTrade(Player* player)
  2965. {
  2966. Player* tradePartner = player->tradePartner;
  2967. if((tradePartner && tradePartner->getTradeState() == TRADE_TRANSFER) || player->getTradeState() == TRADE_TRANSFER)
  2968. {
  2969. std::cout << "Warning: [Game::playerCloseTrade] TradeState == TRADE_TRANSFER. " <<
  2970. player->getName() << " " << player->getTradeState() << " , " <<
  2971. tradePartner->getName() << " " << tradePartner->getTradeState() << std::endl;
  2972. return true;
  2973. }
  2974.  
  2975. std::vector<Item*>::iterator it;
  2976. if(player->getTradeItem())
  2977. {
  2978. std::map<Item*, uint32_t>::iterator it = tradeItems.find(player->getTradeItem());
  2979. if(it != tradeItems.end())
  2980. {
  2981. FreeThing(it->first);
  2982. tradeItems.erase(it);
  2983. }
  2984. player->tradeItem->onTradeEvent(ON_TRADE_CANCEL, player);
  2985. player->tradeItem = NULL;
  2986. }
  2987.  
  2988. player->setTradeState(TRADE_NONE);
  2989. player->tradePartner = NULL;
  2990.  
  2991. player->sendTextMessage(MSG_STATUS_SMALL, "Trade cancelled.");
  2992. player->sendTradeClose();
  2993.  
  2994. if(tradePartner)
  2995. {
  2996. if(tradePartner->getTradeItem())
  2997. {
  2998. std::map<Item*, uint32_t>::iterator it = tradeItems.find(tradePartner->getTradeItem());
  2999. if(it != tradeItems.end())
  3000. {
  3001. FreeThing(it->first);
  3002. tradeItems.erase(it);
  3003. }
  3004.  
  3005. tradePartner->tradeItem->onTradeEvent(ON_TRADE_CANCEL, tradePartner);
  3006. tradePartner->tradeItem = NULL;
  3007. }
  3008.  
  3009. tradePartner->setTradeState(TRADE_NONE);
  3010. tradePartner->tradePartner = NULL;
  3011.  
  3012. tradePartner->sendTextMessage(MSG_STATUS_SMALL, "Trade cancelled.");
  3013. tradePartner->sendTradeClose();
  3014. }
  3015. return true;
  3016. }
  3017.  
  3018. bool Game::playerPurchaseItem(uint32_t playerId, uint16_t spriteId, uint8_t count, uint8_t amount,
  3019. bool ignoreCap/* = false*/, bool inBackpacks/* = false*/)
  3020. {
  3021. if(amount == 0 || amount > 100)
  3022. return false;
  3023.  
  3024. Player* player = getPlayerByID(playerId);
  3025. if(player == NULL || player->isRemoved())
  3026. return false;
  3027.  
  3028. int32_t onBuy;
  3029. int32_t onSell;
  3030.  
  3031. Npc* merchant = player->getShopOwner(onBuy, onSell);
  3032. if(merchant == NULL)
  3033. return false;
  3034.  
  3035. const ItemType& it = Item::items.getItemIdByClientId(spriteId);
  3036. if(it.id == 0)
  3037. return false;
  3038.  
  3039. uint8_t subType;
  3040. if(it.isSplash() || it.isFluidContainer())
  3041. subType = clientFluidToServer(count);
  3042. else
  3043. subType = count;
  3044.  
  3045. if(!player->hasShopItemForSale(it.id, subType))
  3046. return false;
  3047.  
  3048. merchant->onPlayerTrade(player, SHOPEVENT_BUY, onBuy, it.id, subType, amount, ignoreCap, inBackpacks);
  3049. return true;
  3050. }
  3051.  
  3052. bool Game::playerSellItem(uint32_t playerId, uint16_t spriteId, uint8_t count,
  3053. uint8_t amount)
  3054. {
  3055. if(amount == 0 || amount > 100)
  3056. return false;
  3057.  
  3058. Player* player = getPlayerByID(playerId);
  3059. if(player == NULL || player->isRemoved())
  3060. return false;
  3061.  
  3062. int32_t onBuy;
  3063. int32_t onSell;
  3064.  
  3065. Npc* merchant = player->getShopOwner(onBuy, onSell);
  3066. if(merchant == NULL)
  3067. return false;
  3068.  
  3069. const ItemType& it = Item::items.getItemIdByClientId(spriteId);
  3070. if(it.id == 0)
  3071. return false;
  3072.  
  3073. uint8_t subType;
  3074. if(it.isSplash() || it.isFluidContainer())
  3075. subType = clientFluidToServer(count);
  3076. else
  3077. subType = count;
  3078.  
  3079. merchant->onPlayerTrade(player, SHOPEVENT_SELL, onSell, it.id, subType, amount);
  3080. return true;
  3081. }
  3082.  
  3083. bool Game::playerCloseShop(uint32_t playerId)
  3084. {
  3085. Player* player = getPlayerByID(playerId);
  3086. if(player == NULL || player->isRemoved())
  3087. return false;
  3088.  
  3089. player->closeShopWindow();
  3090. return true;
  3091. }
  3092.  
  3093. bool Game::playerLookInShop(uint32_t playerId, uint16_t spriteId, uint8_t count)
  3094. {
  3095. Player* player = getPlayerByID(playerId);
  3096. if(player == NULL || player->isRemoved())
  3097. return false;
  3098.  
  3099. const ItemType& it = Item::items.getItemIdByClientId(spriteId);
  3100. if(it.id == 0)
  3101. return false;
  3102.  
  3103. int32_t subType;
  3104. if(it.isFluidContainer() || it.isSplash())
  3105. subType = clientFluidToServer(count);
  3106. else
  3107. subType = count;
  3108.  
  3109. std::ostringstream ss;
  3110. ss << "You see " << Item::getDescription(it, 1, NULL, subType);
  3111. player->sendTextMessage(MSG_INFO_DESCR, ss.str());
  3112. return true;
  3113. }
  3114.  
  3115. bool Game::playerLookAt(uint32_t playerId, const Position& pos, uint16_t spriteId, uint8_t stackPos)
  3116. {
  3117. Player* player = getPlayerByID(playerId);
  3118. if(!player || player->isRemoved())
  3119. return false;
  3120.  
  3121. Thing* thing = internalGetThing(player, pos, stackPos, spriteId, STACKPOS_LOOK);
  3122. if(!thing)
  3123. {
  3124. player->sendCancelMessage(RET_NOTPOSSIBLE);
  3125. return false;
  3126. }
  3127.  
  3128. Position thingPos = thing->getPosition();
  3129. if(!player->canSee(thingPos))
  3130. {
  3131. player->sendCancelMessage(RET_NOTPOSSIBLE);
  3132. return false;
  3133. }
  3134.  
  3135. Position playerPos = player->getPosition();
  3136.  
  3137. int32_t lookDistance = -1;
  3138. if(thing != player)
  3139. {
  3140. lookDistance = std::max(std::abs(playerPos.x - thingPos.x), std::abs(playerPos.y - thingPos.y));
  3141. if(playerPos.z != thingPos.z)
  3142. lookDistance += 15;
  3143. }
  3144.  
  3145. std::ostringstream ss;
  3146. ss << "You see " << thing->getDescription(lookDistance);
  3147. if(player->isAccessPlayer())
  3148. {
  3149. Item* item = thing->getItem();
  3150. if(item)
  3151. {
  3152. ss << std::endl << "ItemID: [" << item->getID() << "]";
  3153. if(item->getActionId() > 0)
  3154. ss << ", ActionID: [" << item->getActionId() << "]";
  3155.  
  3156. if(item->getUniqueId() > 0)
  3157. ss << ", UniqueID: [" << item->getUniqueId() << "]";
  3158.  
  3159. ss << ".";
  3160. const ItemType& it = Item::items[item->getID()];
  3161. if(it.transformEquipTo)
  3162. ss << std::endl << "TransformTo: [" << it.transformEquipTo << "] (onEquip).";
  3163. else if(it.transformDeEquipTo)
  3164. ss << std::endl << "TransformTo: [" << it.transformDeEquipTo << "] (onDeEquip).";
  3165.  
  3166. if(it.decayTo != -1)
  3167. ss << std::endl << "DecayTo: [" << it.decayTo << "].";
  3168. }
  3169.  
  3170. if(const Creature* creature = thing->getCreature())
  3171. {
  3172. ss << std::endl << "Health: [" << creature->getHealth() << " / " << creature->getMaxHealth() << "]";
  3173. if(creature->getMaxMana() > 0)
  3174. ss << ", Mana: [" << creature->getMana() << " / " << creature->getMaxMana() << "]";
  3175.  
  3176. ss << ".";
  3177. }
  3178.  
  3179. ss << std::endl << "Position: [X: " << thingPos.x << "] [Y: " << thingPos.y << "] [Z: " << thingPos.z << "].";
  3180. }
  3181.  
  3182. player->sendTextMessage(MSG_INFO_DESCR, ss.str());
  3183. return true;
  3184. }
  3185.  
  3186. bool Game::playerLookInBattleList(uint32_t playerId, uint32_t creatureId)
  3187. {
  3188. Player* player = getPlayerByID(playerId);
  3189. if(!player || player->isRemoved())
  3190. return false;
  3191.  
  3192. Creature* creature = getCreatureByID(creatureId);
  3193. if(!creature || creature->isRemoved())
  3194. return false;
  3195.  
  3196. if(!player->canSeeCreature(creature))
  3197. return false;
  3198.  
  3199. const Position& creaturePos = creature->getPosition();
  3200. if(!player->canSee(creaturePos))
  3201. return false;
  3202.  
  3203. int32_t lookDistance;
  3204. if(creature != player)
  3205. {
  3206. const Position& playerPos = player->getPosition();
  3207. lookDistance = std::max(std::abs(playerPos.x - creaturePos.x), std::abs(playerPos.y - creaturePos.y));
  3208. if(playerPos.z != creaturePos.z)
  3209. lookDistance += 15;
  3210. }
  3211. else
  3212. lookDistance = -1;
  3213.  
  3214. std::ostringstream ss;
  3215. ss << "You see " << creature->getDescription(lookDistance);
  3216. if(player->isAccessPlayer())
  3217. {
  3218. ss << std::endl << "Health: [" << creature->getHealth() << " / " << creature->getMaxHealth() << "]";
  3219. if(creature->getMaxMana() > 0)
  3220. ss << ", Mana: [" << creature->getMana() << " / " << creature->getMaxMana() << "]";
  3221.  
  3222. ss << "." << std::endl;
  3223. ss << "Position: [X: " << creaturePos.x << "] [Y: " << creaturePos.y << "] [Z: " << creaturePos.z << "].";
  3224. }
  3225.  
  3226. player->sendTextMessage(MSG_INFO_DESCR, ss.str());
  3227. return true;
  3228. }
  3229.  
  3230. bool Game::playerCancelAttackAndFollow(uint32_t playerId)
  3231. {
  3232. Player* player = getPlayerByID(playerId);
  3233. if(!player || player->isRemoved())
  3234. return false;
  3235.  
  3236. playerSetAttackedCreature(playerId, 0);
  3237. playerFollowCreature(playerId, 0);
  3238. player->stopWalk();
  3239. return true;
  3240. }
  3241.  
  3242. bool Game::playerSetAttackedCreature(uint32_t playerId, uint32_t creatureId)
  3243. {
  3244. Player* player = getPlayerByID(playerId);
  3245. if(!player || player->isRemoved())
  3246. return false;
  3247.  
  3248. if(player->getAttackedCreature() && creatureId == 0)
  3249. {
  3250. player->setAttackedCreature(NULL);
  3251. player->sendCancelTarget();
  3252. return true;
  3253. }
  3254.  
  3255. Creature* attackCreature = getCreatureByID(creatureId);
  3256. if(!attackCreature)
  3257. {
  3258. player->setAttackedCreature(NULL);
  3259. player->sendCancelTarget();
  3260. return false;
  3261. }
  3262.  
  3263. ReturnValue ret = Combat::canTargetCreature(player, attackCreature);
  3264. if(ret != RET_NOERROR)
  3265. {
  3266. player->sendCancelMessage(ret);
  3267. player->sendCancelTarget();
  3268. player->setAttackedCreature(NULL);
  3269. return false;
  3270. }
  3271.  
  3272. player->setAttackedCreature(attackCreature);
  3273. g_dispatcher.addTask(createTask(boost::bind(&Game::updateCreatureWalk, this, player->getID())));
  3274. return true;
  3275. }
  3276.  
  3277. bool Game::playerFollowCreature(uint32_t playerId, uint32_t creatureId)
  3278. {
  3279. Player* player = getPlayerByID(playerId);
  3280. if(!player || player->isRemoved())
  3281. return false;
  3282.  
  3283. player->setAttackedCreature(NULL);
  3284. Creature* followCreature = NULL;
  3285. if(creatureId != 0)
  3286. followCreature = getCreatureByID(creatureId);
  3287.  
  3288. g_dispatcher.addTask(createTask(boost::bind(&Game::updateCreatureWalk, this, player->getID())));
  3289. return player->setFollowCreature(followCreature);
  3290. }
  3291.  
  3292. bool Game::playerSetFightModes(uint32_t playerId, fightMode_t fightMode, chaseMode_t chaseMode, secureMode_t secureMode)
  3293. {
  3294. Player* player = getPlayerByID(playerId);
  3295. if(!player || player->isRemoved())
  3296. return false;
  3297.  
  3298. player->setFightMode(fightMode);
  3299. player->setChaseMode(chaseMode);
  3300. player->setSecureMode(secureMode);
  3301. return true;
  3302. }
  3303.  
  3304. bool Game::playerRequestAddVip(uint32_t playerId, const std::string& vip_name)
  3305. {
  3306. if(vip_name.size() > 32)
  3307. return false;
  3308.  
  3309. Player* player = getPlayerByID(playerId);
  3310. if(!player || player->isRemoved())
  3311. return false;
  3312.  
  3313. std::string real_name;
  3314. real_name = vip_name;
  3315. uint32_t guid;
  3316. bool specialVip;
  3317.  
  3318. if(!IOLoginData::getInstance()->getGuidByNameEx(guid, specialVip, real_name))
  3319. {
  3320. player->sendTextMessage(MSG_STATUS_SMALL, "A player with that name does not exist.");
  3321. return false;
  3322. }
  3323.  
  3324. if(specialVip && !player->hasFlag(PlayerFlag_SpecialVIP))
  3325. {
  3326. player->sendTextMessage(MSG_STATUS_SMALL, "You can not add this player.");
  3327. return false;
  3328. }
  3329.  
  3330. bool online = (getPlayerByName(real_name) != NULL);
  3331. return player->addVIP(guid, real_name, online);
  3332. }
  3333.  
  3334. bool Game::playerRequestRemoveVip(uint32_t playerId, uint32_t guid)
  3335. {
  3336. Player* player = getPlayerByID(playerId);
  3337. if(!player || player->isRemoved())
  3338. return false;
  3339.  
  3340. player->removeVIP(guid);
  3341. return true;
  3342. }
  3343.  
  3344. bool Game::playerTurn(uint32_t playerId, Direction dir)
  3345. {
  3346. Player* player = getPlayerByID(playerId);
  3347. if(!player || player->isRemoved())
  3348. return false;
  3349.  
  3350. player->resetIdleTime();
  3351. return internalCreatureTurn(player, dir);
  3352. }
  3353.  
  3354. bool Game::playerRequestOutfit(uint32_t playerId)
  3355. {
  3356. if(!g_config.getBoolean(ConfigManager::ALLOW_CHANGEOUTFIT))
  3357. return false;
  3358.  
  3359. Player* player = getPlayerByID(playerId);
  3360. if(!player || player->isRemoved())
  3361. return false;
  3362.  
  3363. player->sendOutfitWindow();
  3364. return true;
  3365. }
  3366.  
  3367. bool Game::playerToggleMount(uint32_t playerId, bool mount)
  3368. {
  3369. Player* player = getPlayerByID(playerId);
  3370. if(!player || player->isRemoved())
  3371. return false;
  3372.  
  3373. return player->toggleMount(mount);
  3374. }
  3375.  
  3376. bool Game::playerChangeOutfit(uint32_t playerId, Outfit_t outfit)
  3377. {
  3378. if(!g_config.getBoolean(ConfigManager::ALLOW_CHANGEOUTFIT))
  3379. return false;
  3380.  
  3381. Player* player = getPlayerByID(playerId);
  3382. if(!player || player->isRemoved())
  3383. return false;
  3384.  
  3385. if(outfit.lookMount != 0)
  3386. {
  3387. Mount* mount = Mounts::getInstance()->getMountByClientID(outfit.lookMount);
  3388. if(!mount || !mount->isTamed(player))
  3389. return false;
  3390.  
  3391. if(player->isMounted())
  3392. {
  3393. Mount* prevMount = Mounts::getInstance()->getMountByID(player->getCurrentMount());
  3394. if(prevMount)
  3395. changeSpeed(player, mount->getSpeed() - prevMount->getSpeed());
  3396.  
  3397. player->setCurrentMount(mount->getID());
  3398. }
  3399. else
  3400. {
  3401. player->setCurrentMount(mount->getID());
  3402. outfit.lookMount = 0;
  3403. }
  3404. }
  3405. else if(player->isMounted())
  3406. player->dismount();
  3407.  
  3408. if(player->canWear(outfit.lookType, outfit.lookAddons) && player->hasRequestedOutfit())
  3409. {
  3410. player->hasRequestedOutfit(false);
  3411. player->defaultOutfit = outfit;
  3412. if(player->hasCondition(CONDITION_OUTFIT))
  3413. return false;
  3414.  
  3415. internalCreatureChangeOutfit(player, outfit);
  3416. }
  3417. return true;
  3418. }
  3419.  
  3420. bool Game::playerShowQuestLog(uint32_t playerId)
  3421. {
  3422. Player* player = getPlayerByID(playerId);
  3423. if(!player || player->isRemoved())
  3424. return false;
  3425.  
  3426. player->sendQuestLog();
  3427. return true;
  3428. }
  3429.  
  3430. bool Game::playerShowQuestLine(uint32_t playerId, uint16_t questId)
  3431. {
  3432. Player* player = getPlayerByID(playerId);
  3433. if(!player || player->isRemoved())
  3434. return false;
  3435.  
  3436. Quest* quest = Quests::getInstance()->getQuestByID(questId);
  3437. if(!quest)
  3438. return false;
  3439.  
  3440. player->sendQuestLine(quest);
  3441. return true;
  3442. }
  3443.  
  3444. bool Game::playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type,
  3445. const std::string& receiver, const std::string& text)
  3446. {
  3447. Player* player = getPlayerByID(playerId);
  3448. if(!player || player->isRemoved())
  3449. return false;
  3450.  
  3451. player->resetIdleTime();
  3452.  
  3453. uint32_t muteTime = player->isMuted();
  3454. if(muteTime > 0)
  3455. {
  3456. std::ostringstream ss;
  3457. ss << "You are still muted for " << muteTime << " seconds.";
  3458. player->sendTextMessage(MSG_STATUS_SMALL, ss.str());
  3459. return false;
  3460. }
  3461.  
  3462. if(playerSayCommand(player, type, text))
  3463. return true;
  3464.  
  3465. if(playerSaySpell(player, type, text))
  3466. return true;
  3467.  
  3468. player->removeMessageBuffer();
  3469.  
  3470. switch(type)
  3471. {
  3472. case SPEAK_SAY:
  3473. return internalCreatureSay(player, SPEAK_SAY, text, false);
  3474.  
  3475. case SPEAK_WHISPER:
  3476. return playerWhisper(player, text);
  3477.  
  3478. case SPEAK_YELL:
  3479. return playerYell(player, text);
  3480.  
  3481. case SPEAK_PRIVATE_TO:
  3482. case SPEAK_PRIVATE_RED_TO:
  3483. return playerSpeakTo(player, type, receiver, text);
  3484.  
  3485. case SPEAK_CHANNEL_O:
  3486. case SPEAK_CHANNEL_Y:
  3487. case SPEAK_CHANNEL_R1:
  3488. return playerTalkToChannel(player, type, text, channelId);
  3489.  
  3490. case SPEAK_PRIVATE_PN:
  3491. return playerSpeakToNpc(player, text);
  3492.  
  3493. case SPEAK_BROADCAST:
  3494. return playerBroadcastMessage(player, text);
  3495.  
  3496. default:
  3497. break;
  3498. }
  3499. return false;
  3500. }
  3501.  
  3502. bool Game::playerSayCommand(Player* player, SpeakClasses type, const std::string& text)
  3503. {
  3504. if(player->isAccountManager())
  3505. return internalCreatureSay(player, SPEAK_SAY, text, false);
  3506.  
  3507. //First, check if this was a command
  3508. for(uint32_t i = 0; i < commandTags.size(); i++)
  3509. {
  3510. if(commandTags[i] == text.substr(0,1))
  3511. {
  3512. if(commands.exeCommand(player, text))
  3513. return true;
  3514. }
  3515. }
  3516. return false;
  3517. }
  3518.  
  3519. bool Game::playerSaySpell(Player* player, SpeakClasses type, const std::string& text)
  3520. {
  3521. if(player->isAccountManager())
  3522. return internalCreatureSay(player, SPEAK_SAY, text, false);
  3523.  
  3524. std::string words = text;
  3525. TalkActionResult_t result = g_talkActions->playerSaySpell(player, type, words);
  3526. if(result == TALKACTION_BREAK)
  3527. return true;
  3528.  
  3529. result = g_spells->playerSaySpell(player, type, words);
  3530. if(result == TALKACTION_BREAK)
  3531. return internalCreatureSay(player, SPEAK_SAY, words, false);
  3532. else if(result == TALKACTION_FAILED)
  3533. return true;
  3534.  
  3535. return false;
  3536. }
  3537.  
  3538. bool Game::playerWhisper(Player* player, const std::string& text)
  3539. {
  3540. SpectatorVec list;
  3541. getSpectators(list, player->getPosition(), false, false,
  3542. Map::maxClientViewportX, Map::maxClientViewportX,
  3543. Map::maxClientViewportY, Map::maxClientViewportY);
  3544. SpectatorVec::const_iterator it;
  3545.  
  3546. //send to client
  3547. Player* tmpPlayer = NULL;
  3548. for(it = list.begin(); it != list.end(); ++it)
  3549. {
  3550. if((tmpPlayer = (*it)->getPlayer()))
  3551. {
  3552. if(!Position::areInRange<1,1,0>(player->getPosition(), (*it)->getPosition()))
  3553. tmpPlayer->sendCreatureSay(player, SPEAK_WHISPER, "pspsps");
  3554. else
  3555. tmpPlayer->sendCreatureSay(player, SPEAK_WHISPER, text);
  3556. }
  3557. }
  3558.  
  3559. //event method
  3560. for(it = list.begin(); it != list.end(); ++it)
  3561. (*it)->onCreatureSay(player, SPEAK_WHISPER, text);
  3562.  
  3563. return true;
  3564. }
  3565.  
  3566. bool Game::playerYell(Player* player, const std::string& text)
  3567. {
  3568. if(player->getLevel() > 1)
  3569. {
  3570. if(!player->hasCondition(CONDITION_YELLTICKS))
  3571. {
  3572. if(player->getAccountType() < ACCOUNT_TYPE_GAMEMASTER)
  3573. {
  3574. Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_YELLTICKS, 30000, 0);
  3575. player->addCondition(condition);
  3576. }
  3577. internalCreatureSay(player, SPEAK_YELL, asUpperCaseString(text), false);
  3578. }
  3579. else
  3580. player->sendCancelMessage(RET_YOUAREEXHAUSTED);
  3581. }
  3582. else
  3583. player->sendTextMessage(MSG_STATUS_SMALL, "You may not yell as long as you are on level 1.");
  3584.  
  3585. return true;
  3586. }
  3587.  
  3588. bool Game::playerSpeakTo(Player* player, SpeakClasses type, const std::string& receiver,
  3589. const std::string& text)
  3590. {
  3591. Player* toPlayer = getPlayerByName(receiver);
  3592. if(!toPlayer || toPlayer->isRemoved())
  3593. {
  3594. player->sendTextMessage(MSG_STATUS_SMALL, "A player with this name is not online.");
  3595. return false;
  3596. }
  3597.  
  3598. if(type == SPEAK_PRIVATE_RED_TO && (player->hasFlag(PlayerFlag_CanTalkRedPrivate) || player->getAccountType() >= ACCOUNT_TYPE_GAMEMASTER))
  3599. type = SPEAK_PRIVATE_RED_FROM;
  3600. else
  3601. type = SPEAK_PRIVATE_FROM;
  3602.  
  3603. toPlayer->sendCreatureSay(player, type, text);
  3604. toPlayer->onCreatureSay(player, type, text);
  3605.  
  3606. if(toPlayer->isInGhostMode() && !player->isAccessPlayer())
  3607. player->sendTextMessage(MSG_STATUS_SMALL, "A player with this name is not online.");
  3608. else
  3609. {
  3610. std::ostringstream ss;
  3611. ss << "Message sent to " << toPlayer->getName() << ".";
  3612. player->sendTextMessage(MSG_STATUS_SMALL, ss.str());
  3613. }
  3614. return true;
  3615. }
  3616.  
  3617. bool Game::playerTalkToChannel(Player* player, SpeakClasses type, const std::string& text, uint16_t channelId)
  3618. {
  3619. switch(type)
  3620. {
  3621. case SPEAK_CHANNEL_Y:
  3622. {
  3623. if(player->isAccessPlayer() || (channelId == CHANNEL_HELP && (player->hasFlag(PlayerFlag_TalkOrangeHelpChannel) || player->getAccountType() > ACCOUNT_TYPE_NORMAL)))
  3624. type = SPEAK_CHANNEL_O;
  3625.  
  3626. break;
  3627. }
  3628.  
  3629. case SPEAK_CHANNEL_O:
  3630. {
  3631. if(channelId != CHANNEL_HELP || (!player->hasFlag(PlayerFlag_TalkOrangeHelpChannel) && player->getAccountType() == ACCOUNT_TYPE_NORMAL))
  3632. type = SPEAK_CHANNEL_Y;
  3633.  
  3634. break;
  3635. }
  3636.  
  3637. case SPEAK_CHANNEL_R1:
  3638. {
  3639. if(!player->hasFlag(PlayerFlag_CanTalkRedChannel) && player->getAccountType() < ACCOUNT_TYPE_GAMEMASTER)
  3640. {
  3641. if(channelId == CHANNEL_HELP && (player->hasFlag(PlayerFlag_TalkOrangeHelpChannel) || player->getAccountType() >= ACCOUNT_TYPE_TUTOR))
  3642. type = SPEAK_CHANNEL_O;
  3643. else
  3644. type = SPEAK_CHANNEL_Y;
  3645. }
  3646. break;
  3647. }
  3648.  
  3649. default:
  3650. break;
  3651. }
  3652. return g_chat.talkToChannel(player, type, text, channelId);
  3653. }
  3654.  
  3655. bool Game::playerSpeakToNpc(Player* player, const std::string& text)
  3656. {
  3657. SpectatorVec list;
  3658. SpectatorVec::iterator it;
  3659. getSpectators(list, player->getPosition());
  3660.  
  3661. //send to npcs only
  3662. for(it = list.begin(); it != list.end(); ++it)
  3663. {
  3664. if((*it)->getNpc())
  3665. (*it)->onCreatureSay(player, SPEAK_PRIVATE_PN, text);
  3666. }
  3667. return true;
  3668. }
  3669.  
  3670. bool Game::npcSpeakToPlayer(Npc* npc, Player* player, const std::string& text, bool publicize)
  3671. {
  3672. if(player != NULL)
  3673. {
  3674. player->sendCreatureSay(npc, SPEAK_PRIVATE_NP, text);
  3675. player->onCreatureSay(npc, SPEAK_PRIVATE_NP, text);
  3676. }
  3677.  
  3678. if(publicize)
  3679. {
  3680. SpectatorVec list;
  3681. SpectatorVec::iterator it;
  3682. getSpectators(list, npc->getPosition());
  3683.  
  3684. //send to client
  3685. Player* tmpPlayer = NULL;
  3686. for(it = list.begin(); it != list.end(); ++it)
  3687. {
  3688. tmpPlayer = (*it)->getPlayer();
  3689. if((tmpPlayer != NULL) && (tmpPlayer != player))
  3690. tmpPlayer->sendCreatureSay(npc, SPEAK_SAY, text);
  3691. }
  3692.  
  3693. //event method
  3694. for(it = list.begin(); it != list.end(); ++it)
  3695. {
  3696. if((*it) != player)
  3697. (*it)->onCreatureSay(npc, SPEAK_SAY, text);
  3698. }
  3699. }
  3700. return true;
  3701. }
  3702.  
  3703. //--
  3704. bool Game::canThrowObjectTo(const Position& fromPos, const Position& toPos, bool checkLineOfSight /*= true*/,
  3705. int32_t rangex /*= Map::maxClientViewportX*/, int32_t rangey /*= Map::maxClientViewportY*/)
  3706. {
  3707. return map->canThrowObjectTo(fromPos, toPos, checkLineOfSight, rangex, rangey);
  3708. }
  3709.  
  3710. bool Game::isSightClear(const Position& fromPos, const Position& toPos, bool floorCheck)
  3711. {
  3712. return map->isSightClear(fromPos, toPos, floorCheck);
  3713. }
  3714.  
  3715. bool Game::internalCreatureTurn(Creature* creature, Direction dir)
  3716. {
  3717. if(creature->getDirection() != dir)
  3718. {
  3719. creature->setDirection(dir);
  3720.  
  3721. int32_t stackpos = creature->getParent()->__getIndexOfThing(creature);
  3722.  
  3723. const SpectatorVec& list = getSpectators(creature->getPosition());
  3724. SpectatorVec::const_iterator it;
  3725.  
  3726. //send to client
  3727. Player* tmpPlayer = NULL;
  3728. for(it = list.begin(); it != list.end(); ++it)
  3729. {
  3730. if((tmpPlayer = (*it)->getPlayer()))
  3731. tmpPlayer->sendCreatureTurn(creature);
  3732. }
  3733.  
  3734. //event method
  3735. for(it = list.begin(); it != list.end(); ++it)
  3736. (*it)->onCreatureTurn(creature, stackpos);
  3737.  
  3738. return true;
  3739. }
  3740. return false;
  3741. }
  3742.  
  3743. bool Game::internalCreatureSay(Creature* creature, SpeakClasses type, const std::string& text,
  3744. bool ghostMode, SpectatorVec* listPtr/* = NULL*/, Position* pos/* = NULL*/)
  3745. {
  3746. if(g_config.getBoolean(ConfigManager::ACCOUNT_MANAGER))
  3747. {
  3748. Player* player = creature->getPlayer();
  3749. if(player && player->isAccountManager())
  3750. {
  3751. player->manageAccount(text);
  3752. return true;
  3753. }
  3754. }
  3755.  
  3756. Position destPos = creature->getPosition();
  3757. if(pos)
  3758. destPos = (*pos);
  3759.  
  3760. SpectatorVec list;
  3761. SpectatorVec::const_iterator it;
  3762. if(!listPtr || !listPtr->size())
  3763. {
  3764. // This somewhat complex construct ensures that the cached SpectatorVec
  3765. // is used if available and if it can be used, else a local vector is
  3766. // used (hopefully the compiler will optimize away the construction of
  3767. // the temporary when it's not used).
  3768. if(type != SPEAK_YELL && type != SPEAK_MONSTER_YELL)
  3769. {
  3770. getSpectators(list, destPos, false, false,
  3771. Map::maxClientViewportX, Map::maxClientViewportX,
  3772. Map::maxClientViewportY, Map::maxClientViewportY);
  3773. }
  3774. else
  3775. getSpectators(list, destPos, false, true, 18, 18, 14, 14);
  3776. }
  3777. else
  3778. list = (*listPtr);
  3779.  
  3780. //send to client
  3781. Player* tmpPlayer = NULL;
  3782. for(it = list.begin(); it != list.end(); ++it)
  3783. {
  3784. if(!(tmpPlayer = (*it)->getPlayer()))
  3785. continue;
  3786.  
  3787. if(!ghostMode || tmpPlayer->canSeeCreature(creature))
  3788. tmpPlayer->sendCreatureSay(creature, type, text, &destPos);
  3789. }
  3790.  
  3791. //event method
  3792. for(it = list.begin(); it != list.end(); ++it)
  3793. (*it)->onCreatureSay(creature, type, text, &destPos);
  3794.  
  3795. return true;
  3796. }
  3797.  
  3798. bool Game::getPathTo(const Creature* creature, const Position& destPos,
  3799. std::list<Direction>& listDir, int32_t maxSearchDist /*= -1*/)
  3800. {
  3801. return map->getPathTo(creature, destPos, listDir, maxSearchDist);
  3802. }
  3803.  
  3804. bool Game::getPathToEx(const Creature* creature, const Position& targetPos,
  3805. std::list<Direction>& dirList, const FindPathParams& fpp)
  3806. {
  3807. return map->getPathMatching(creature, dirList, FrozenPathingConditionCall(targetPos), fpp);
  3808. }
  3809.  
  3810. bool Game::getPathToEx(const Creature* creature, const Position& targetPos, std::list<Direction>& dirList,
  3811. uint32_t minTargetDist, uint32_t maxTargetDist, bool fullPathSearch /*= true*/,
  3812. bool clearSight /*= true*/, int32_t maxSearchDist /*= -1*/)
  3813. {
  3814. FindPathParams fpp;
  3815. fpp.fullPathSearch = fullPathSearch;
  3816. fpp.maxSearchDist = maxSearchDist;
  3817. fpp.clearSight = clearSight;
  3818. fpp.minTargetDist = minTargetDist;
  3819. fpp.maxTargetDist = maxTargetDist;
  3820. return getPathToEx(creature, targetPos, dirList, fpp);
  3821. }
  3822.  
  3823. void Game::checkCreatureWalk(uint32_t creatureId)
  3824. {
  3825. Creature* creature = getCreatureByID(creatureId);
  3826. if(creature && creature->getHealth() > 0)
  3827. {
  3828. creature->onWalk();
  3829. cleanup();
  3830. }
  3831. }
  3832.  
  3833. void Game::updateCreatureWalk(uint32_t creatureId)
  3834. {
  3835. Creature* creature = getCreatureByID(creatureId);
  3836. if(creature && creature->getHealth() > 0)
  3837. creature->goToFollowCreature();
  3838. }
  3839.  
  3840. void Game::checkCreatureAttack(uint32_t creatureId)
  3841. {
  3842. Creature* creature = getCreatureByID(creatureId);
  3843. if(creature && creature->getHealth() > 0)
  3844. creature->onAttacking(0);
  3845. }
  3846.  
  3847. void Game::addCreatureCheck(Creature* creature)
  3848. {
  3849. if(creature->isRemoved())
  3850. return;
  3851.  
  3852. creature->creatureCheck = true;
  3853. if(creature->checkCreatureVectorIndex >= 0)
  3854. return; //Already in a vector
  3855.  
  3856. toAddCheckCreatureVector.push_back(creature);
  3857. creature->checkCreatureVectorIndex = random_range(0, EVENT_CREATURECOUNT - 1);
  3858. creature->useThing2();
  3859. }
  3860.  
  3861. void Game::removeCreatureCheck(Creature* creature)
  3862. {
  3863. if(creature->checkCreatureVectorIndex == -1)
  3864. return;
  3865.  
  3866. creature->creatureCheck = false;
  3867. }
  3868.  
  3869. void Game::checkCreatures()
  3870. {
  3871. checkCreatureEvent = g_scheduler.addEvent(createSchedulerTask(EVENT_CHECK_CREATURE_INTERVAL, boost::bind(&Game::checkCreatures, this)));
  3872.  
  3873. Creature* creature;
  3874. std::vector<Creature*>::iterator it;
  3875.  
  3876. //add any new creatures
  3877. for(it = toAddCheckCreatureVector.begin(); it != toAddCheckCreatureVector.end(); ++it)
  3878. {
  3879. creature = (*it);
  3880. checkCreatureVectors[creature->checkCreatureVectorIndex].push_back(creature);
  3881. }
  3882. toAddCheckCreatureVector.clear();
  3883.  
  3884. checkCreatureLastIndex++;
  3885. if(checkCreatureLastIndex == EVENT_CREATURECOUNT)
  3886. checkCreatureLastIndex = 0;
  3887.  
  3888. CreatureVector& checkCreatureVector = checkCreatureVectors[checkCreatureLastIndex];
  3889. for(it = checkCreatureVector.begin(); it != checkCreatureVector.end();)
  3890. {
  3891. creature = (*it);
  3892. if(creature->creatureCheck)
  3893. {
  3894. if(creature->getHealth() > 0)
  3895. {
  3896. creature->onThink(EVENT_CREATURE_THINK_INTERVAL);
  3897. creature->onAttacking(EVENT_CREATURE_THINK_INTERVAL);
  3898. creature->executeConditions(EVENT_CREATURE_THINK_INTERVAL);
  3899. }
  3900. else
  3901. creature->onDeath();
  3902.  
  3903. ++it;
  3904. }
  3905. else
  3906. {
  3907. creature->checkCreatureVectorIndex = -1;
  3908. it = checkCreatureVector.erase(it);
  3909. FreeThing(creature);
  3910. }
  3911. }
  3912. cleanup();
  3913. }
  3914.  
  3915. void Game::changeSpeed(Creature* creature, int32_t varSpeedDelta)
  3916. {
  3917. int32_t varSpeed = creature->getSpeed() - creature->getBaseSpeed();
  3918. varSpeed += varSpeedDelta;
  3919.  
  3920. creature->setSpeed(varSpeed);
  3921.  
  3922. const SpectatorVec& list = getSpectators(creature->getPosition());
  3923. SpectatorVec::const_iterator it;
  3924.  
  3925. //send to client
  3926. Player* tmpPlayer = NULL;
  3927. for(it = list.begin(); it != list.end(); ++it)
  3928. {
  3929. if((tmpPlayer = (*it)->getPlayer()))
  3930. tmpPlayer->sendChangeSpeed(creature, creature->getStepSpeed());
  3931. }
  3932. }
  3933.  
  3934. void Game::internalCreatureChangeOutfit(Creature* creature, const Outfit_t& outfit)
  3935. {
  3936. creature->setCurrentOutfit(outfit);
  3937. if(!creature->isInvisible())
  3938. {
  3939. const SpectatorVec& list = getSpectators(creature->getPosition());
  3940. SpectatorVec::const_iterator it;
  3941.  
  3942. //send to client
  3943. Player* tmpPlayer = NULL;
  3944. for(it = list.begin(); it != list.end(); ++it)
  3945. {
  3946. if((tmpPlayer = (*it)->getPlayer()))
  3947. tmpPlayer->sendCreatureChangeOutfit(creature, outfit);
  3948. }
  3949.  
  3950. //event method
  3951. for(it = list.begin(); it != list.end(); ++it)
  3952. (*it)->onCreatureChangeOutfit(creature, outfit);
  3953. }
  3954. }
  3955.  
  3956. void Game::internalCreatureChangeVisible(Creature* creature, bool visible)
  3957. {
  3958. const SpectatorVec& list = getSpectators(creature->getPosition());
  3959. SpectatorVec::const_iterator it;
  3960.  
  3961. //send to client
  3962. Player* tmpPlayer = NULL;
  3963. for(it = list.begin(); it != list.end(); ++it)
  3964. {
  3965. if((tmpPlayer = (*it)->getPlayer()))
  3966. tmpPlayer->sendCreatureChangeVisible(creature, visible);
  3967. }
  3968.  
  3969. //event method
  3970. for(it = list.begin(); it != list.end(); ++it)
  3971. (*it)->onCreatureChangeVisible(creature, visible);
  3972. }
  3973.  
  3974.  
  3975. void Game::changeLight(const Creature* creature)
  3976. {
  3977. const SpectatorVec& list = getSpectators(creature->getPosition());
  3978.  
  3979. //send to client
  3980. Player* tmpPlayer = NULL;
  3981. for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
  3982. {
  3983. if((tmpPlayer = (*it)->getPlayer()))
  3984. tmpPlayer->sendCreatureLight(creature);
  3985. }
  3986. }
  3987.  
  3988. bool Game::combatBlockHit(CombatType_t combatType, Creature* attacker, Creature* target,
  3989. int32_t& healthChange, bool checkDefense, bool checkArmor)
  3990. {
  3991. if(target->getPlayer() && target->getPlayer()->isInGhostMode())
  3992. return true;
  3993.  
  3994. if(healthChange > 0)
  3995. return false;
  3996.  
  3997. const Position& targetPos = target->getPosition();
  3998. const SpectatorVec& list = getSpectators(targetPos);
  3999.  
  4000. if(!target->isAttackable() || Combat::canDoCombat(attacker, target) != RET_NOERROR)
  4001. {
  4002. addMagicEffect(list, targetPos, NM_ME_POFF, target->isInGhostMode());
  4003. return true;
  4004. }
  4005.  
  4006. int32_t damage = -healthChange;
  4007. BlockType_t blockType = target->blockHit(attacker, combatType, damage, checkDefense, checkArmor);
  4008. healthChange = -damage;
  4009.  
  4010. if(blockType == BLOCK_DEFENSE)
  4011. {
  4012. addMagicEffect(list, targetPos, NM_ME_POFF);
  4013. return true;
  4014. }
  4015. else if(blockType == BLOCK_ARMOR)
  4016. {
  4017. addMagicEffect(list, targetPos, NM_ME_BLOCKHIT);
  4018. return true;
  4019. }
  4020. else if(blockType == BLOCK_IMMUNITY)
  4021. {
  4022. uint8_t hitEffect = 0;
  4023. switch(combatType)
  4024. {
  4025. case COMBAT_UNDEFINEDDAMAGE:
  4026. break;
  4027.  
  4028. case COMBAT_ENERGYDAMAGE:
  4029. case COMBAT_FIREDAMAGE:
  4030. case COMBAT_PHYSICALDAMAGE:
  4031. case COMBAT_ICEDAMAGE:
  4032. case COMBAT_DEATHDAMAGE:
  4033. {
  4034. hitEffect = NM_ME_BLOCKHIT;
  4035. break;
  4036. }
  4037.  
  4038. case COMBAT_EARTHDAMAGE:
  4039. {
  4040. hitEffect = NM_ME_POISON_RINGS;
  4041. break;
  4042. }
  4043.  
  4044. case COMBAT_HOLYDAMAGE:
  4045. {
  4046. hitEffect = NM_ME_HOLYDAMAGE;
  4047. break;
  4048. }
  4049.  
  4050. default:
  4051. {
  4052. hitEffect = NM_ME_POFF;
  4053. break;
  4054. }
  4055. }
  4056. addMagicEffect(list, targetPos, hitEffect);
  4057. return true;
  4058. }
  4059. return false;
  4060. }
  4061.  
  4062. bool Game::combatChangeHealth(CombatType_t combatType, Creature* attacker, Creature* target, int32_t healthChange)
  4063. {
  4064. const Position& targetPos = target->getPosition();
  4065. if(healthChange > 0)
  4066. {
  4067. if(target->getHealth() <= 0)
  4068. return false;
  4069.  
  4070. Player* attackerPlayer = NULL;
  4071. if(attacker)
  4072. attackerPlayer = attacker->getPlayer();
  4073.  
  4074. Player* targetPlayer = target->getPlayer();
  4075. if(attackerPlayer && targetPlayer)
  4076. {
  4077. if(g_config.getBoolean(ConfigManager::CANNOT_ATTACK_SAME_LOOKFEET) && attacker->defaultOutfit.lookFeet == target->defaultOutfit.lookFeet && combatType != COMBAT_HEALING)
  4078. return false;
  4079.  
  4080. if(attackerPlayer->getSkull() == SKULL_BLACK && attackerPlayer->getSkullClient(targetPlayer) == SKULL_NONE)
  4081. return false;
  4082. }
  4083.  
  4084. int32_t realHealthChange = target->getHealth();
  4085. target->changeHealth(healthChange);
  4086. realHealthChange = target->getHealth() - realHealthChange;
  4087. if(realHealthChange > 0 && !target->isInGhostMode())
  4088. {
  4089. std::ostringstream ss;
  4090. if(!attacker)
  4091. ss << ucfirst(target->getNameDescription()) << " was healed for " << realHealthChange << " hitpoint" << (realHealthChange != 1 ? "s." : ".");
  4092. else if(attacker == target)
  4093. ss << ucfirst(attacker->getNameDescription()) << " healed " << (targetPlayer ? (targetPlayer->getSex() == PLAYERSEX_FEMALE ? "herself for " : "himself for ") : "itself for ") << realHealthChange << " hitpoint" << (realHealthChange != 1 ? "s." : ".");
  4094. else
  4095. ss << ucfirst(attacker->getNameDescription()) << " healed " << target->getNameDescription() << " for " << realHealthChange << " hitpoint" << (realHealthChange != 1 ? "s." : ".");
  4096.  
  4097. std::string message = ss.str();
  4098.  
  4099. Player* tmpPlayer = NULL;
  4100. SpectatorVec list;
  4101. getSpectators(list, targetPos);
  4102. for(SpectatorVec::const_iterator it = list.begin(), end = list.end(); it != end; ++it)
  4103. {
  4104. if((tmpPlayer = (*it)->getPlayer()))
  4105. {
  4106. if(tmpPlayer == attackerPlayer && attackerPlayer != targetPlayer)
  4107. {
  4108. std::ostringstream tmpSs;
  4109. tmpSs << "You heal " << target->getNameDescription() << " for " << realHealthChange << " hitpoint" << (realHealthChange != 1 ? "s." : ".");
  4110. tmpPlayer->sendHealMessage(MSG_HEALED, tmpSs.str(), targetPos, realHealthChange, TEXTCOLOR_MAYABLUE);
  4111. }
  4112. else if(tmpPlayer == targetPlayer)
  4113. {
  4114. std::ostringstream tmpSs;
  4115. if(!attacker)
  4116. tmpSs << "You were healed for " << realHealthChange << " hitpoint" << (realHealthChange != 1 ? "s." : ".");
  4117. else if(targetPlayer == attackerPlayer)
  4118. tmpSs << "You heal yourself for " << realHealthChange << " hitpoint" << (realHealthChange != 1 ? "s." : ".");
  4119. else
  4120. tmpSs << "You were healed by " << attacker->getNameDescription() << " for " << realHealthChange << " hitpoint" << (realHealthChange != 1 ? "s." : ".");
  4121.  
  4122. tmpPlayer->sendHealMessage(MSG_HEALED, tmpSs.str(), targetPos, realHealthChange, TEXTCOLOR_MAYABLUE);
  4123. }
  4124. else
  4125. tmpPlayer->sendHealMessage(MSG_HEALED_OTHERS, message, targetPos, realHealthChange, TEXTCOLOR_MAYABLUE);
  4126. }
  4127. }
  4128. }
  4129. }
  4130. else
  4131. {
  4132. const SpectatorVec& list = getSpectators(targetPos);
  4133. if(!target->isAttackable() || Combat::canDoCombat(attacker, target) != RET_NOERROR)
  4134. {
  4135. addMagicEffect(list, targetPos, NM_ME_POFF);
  4136. return true;
  4137. }
  4138.  
  4139. Player* attackerPlayer = NULL;
  4140. if(attacker)
  4141. attackerPlayer = attacker->getPlayer();
  4142.  
  4143. Player* targetPlayer = target->getPlayer();
  4144. if(attackerPlayer && targetPlayer)
  4145. {
  4146. if(g_config.getBoolean(ConfigManager::CANNOT_ATTACK_SAME_LOOKFEET) && attacker->defaultOutfit.lookFeet == target->defaultOutfit.lookFeet && combatType != COMBAT_HEALING)
  4147. return false;
  4148.  
  4149. if(attackerPlayer->getSkull() == SKULL_BLACK && attackerPlayer->getSkullClient(targetPlayer) == SKULL_NONE)
  4150. return false;
  4151. }
  4152.  
  4153. int32_t damage = -healthChange;
  4154. if(damage != 0)
  4155. {
  4156. if(target->hasCondition(CONDITION_MANASHIELD) && combatType != COMBAT_UNDEFINEDDAMAGE)
  4157. {
  4158. int32_t manaDamage = std::min(target->getMana(), damage);
  4159. damage = std::max((int32_t)0, damage - manaDamage);
  4160. if(manaDamage != 0)
  4161. {
  4162. target->drainMana(attacker, manaDamage);
  4163. addMagicEffect(list, targetPos, NM_ME_LOSE_ENERGY);
  4164.  
  4165. std::ostringstream ss;
  4166. if(!attacker)
  4167. ss << ucfirst(target->getNameDescription()) << " loses " << manaDamage << " mana.";
  4168. else if(attacker == target)
  4169. ss << ucfirst(target->getNameDescription()) << " loses " << manaDamage << " mana blocking an attack by " << (targetPlayer ? (targetPlayer->getSex() == PLAYERSEX_FEMALE ? "herself." : "himself.") : "itself.");
  4170. else
  4171. ss << ucfirst(target->getNameDescription()) << " loses " << manaDamage << " mana blocking an attack by " << attacker->getNameDescription() << ".";
  4172.  
  4173. std::string message = ss.str();
  4174.  
  4175. Player* tmpPlayer = NULL;
  4176. SpectatorVec listEx;
  4177. getSpectators(listEx, targetPos);
  4178. for(SpectatorVec::const_iterator it = listEx.begin(), end = listEx.end(); it != end; ++it)
  4179. {
  4180. if((tmpPlayer = (*it)->getPlayer()))
  4181. {
  4182. if(tmpPlayer == attackerPlayer && attackerPlayer != targetPlayer)
  4183. {
  4184. std::ostringstream tmpSs;
  4185. tmpSs << ucfirst(target->getNameDescription()) << " loses " << manaDamage << " mana blocking your attack.";
  4186. tmpPlayer->sendDamageMessage(MSG_DAMAGE_DEALT, tmpSs.str(), targetPos, manaDamage, TEXTCOLOR_BLUE);
  4187. }
  4188. else if(tmpPlayer == targetPlayer)
  4189. {
  4190. std::ostringstream tmpSs;
  4191. if(!attacker)
  4192. tmpSs << "You lose " << manaDamage << " mana.";
  4193. else if(targetPlayer == attackerPlayer)
  4194. tmpSs << "You lose " << manaDamage << " mana blocking an attack by yourself.";
  4195. else
  4196. tmpSs << "You lose " << manaDamage << " mana blocking an attack by " << attacker->getNameDescription() << ".";
  4197.  
  4198. tmpPlayer->sendDamageMessage(MSG_DAMAGE_RECEIVED, tmpSs.str(), targetPos, manaDamage, TEXTCOLOR_BLUE);
  4199. }
  4200. else
  4201. tmpPlayer->sendDamageMessage(MSG_DAMAGE_OTHERS, message, targetPos, manaDamage, TEXTCOLOR_BLUE);
  4202. }
  4203. }
  4204. }
  4205. }
  4206.  
  4207. Player* targetPlayer = target->getPlayer();
  4208. if(targetPlayer)
  4209. {
  4210. if(damage >= targetPlayer->getHealth())
  4211. {
  4212. //scripting event - onPrepareDeath
  4213. CreatureEventList prepareDeathEvents = targetPlayer->getCreatureEvents(CREATURE_EVENT_PREPAREDEATH);
  4214. for(CreatureEventList::const_iterator it = prepareDeathEvents.begin(); it != prepareDeathEvents.end(); ++it)
  4215. (*it)->executeOnPrepareDeath(targetPlayer, attacker);
  4216. }
  4217. }
  4218.  
  4219. damage = std::min(target->getHealth(), damage);
  4220. if(damage > 0 && attacker)
  4221. {
  4222.  
  4223. const Player* attack = attacker->getPlayer();
  4224. const Player* targ = target->getPlayer();
  4225. if(attack && targ)
  4226. {
  4227. if(attack->getLevel() < 80 || targ->getLevel() < 80)
  4228. {
  4229. if(abs(attack->getLevel() - targ->getLevel()) > g_config.getNumber(ConfigManager::TARGET_LEVEL_DIFFERENCE))
  4230. {
  4231. int i = g_config.getNumber(ConfigManager::TARGET_LEVEL_DIFFERENCE);
  4232. std::string s;
  4233. std::stringstream out;
  4234. out << i;
  4235. s = out.str();
  4236. attack->sendCancel("You can't attack player higher/lower than " + s + " levels.");
  4237. return false;
  4238. }
  4239. }
  4240. }
  4241.  
  4242. target->drainHealth(attacker, combatType, damage);
  4243. addCreatureHealth(list, target);
  4244.  
  4245. TextColor_t textColor = TEXTCOLOR_NONE;
  4246. uint8_t hitEffect = 0;
  4247. switch(combatType)
  4248. {
  4249. case COMBAT_PHYSICALDAMAGE:
  4250. {
  4251. Item* splash = NULL;
  4252. switch(target->getRace())
  4253. {
  4254. case RACE_VENOM:
  4255. textColor = TEXTCOLOR_LIGHTGREEN;
  4256. hitEffect = NM_ME_POISON;
  4257. splash = Item::CreateItem(ITEM_SMALLSPLASH, FLUID_GREEN);
  4258. break;
  4259.  
  4260. case RACE_BLOOD:
  4261. textColor = TEXTCOLOR_RED;
  4262. hitEffect = NM_ME_DRAW_BLOOD;
  4263. splash = Item::CreateItem(ITEM_SMALLSPLASH, FLUID_BLOOD);
  4264. break;
  4265.  
  4266. case RACE_UNDEAD:
  4267. textColor = TEXTCOLOR_LIGHTGREY;
  4268. hitEffect = NM_ME_HIT_AREA;
  4269. break;
  4270.  
  4271. case RACE_FIRE:
  4272. textColor = TEXTCOLOR_ORANGE;
  4273. hitEffect = NM_ME_DRAW_BLOOD;
  4274. break;
  4275.  
  4276. case RACE_ENERGY:
  4277. textColor = TEXTCOLOR_PURPLE;
  4278. hitEffect = NM_ME_ENERGY_DAMAGE;
  4279. break;
  4280.  
  4281. default:
  4282. break;
  4283. }
  4284.  
  4285. if(splash)
  4286. {
  4287. internalAddItem(target->getTile(), splash, INDEX_WHEREEVER, FLAG_NOLIMIT);
  4288. startDecay(splash);
  4289. }
  4290. break;
  4291. }
  4292.  
  4293. case COMBAT_ENERGYDAMAGE:
  4294. {
  4295. textColor = TEXTCOLOR_PURPLE;
  4296. hitEffect = NM_ME_ENERGY_DAMAGE;
  4297. break;
  4298. }
  4299.  
  4300. case COMBAT_EARTHDAMAGE:
  4301. {
  4302. textColor = TEXTCOLOR_LIGHTGREEN;
  4303. hitEffect = NM_ME_POISON_RINGS;
  4304. break;
  4305. }
  4306.  
  4307. case COMBAT_DROWNDAMAGE:
  4308. {
  4309. textColor = TEXTCOLOR_LIGHTBLUE;
  4310. hitEffect = NM_ME_LOSE_ENERGY;
  4311. break;
  4312. }
  4313.  
  4314. case COMBAT_FIREDAMAGE:
  4315. {
  4316. textColor = TEXTCOLOR_ORANGE;
  4317. hitEffect = NM_ME_HITBY_FIRE;
  4318. break;
  4319. }
  4320.  
  4321. case COMBAT_ICEDAMAGE:
  4322. {
  4323. textColor = TEXTCOLOR_SKYBLUE;
  4324. hitEffect = NM_ME_ICEATTACK;
  4325. break;
  4326. }
  4327.  
  4328. case COMBAT_HOLYDAMAGE:
  4329. {
  4330. textColor = TEXTCOLOR_YELLOW;
  4331. hitEffect = NM_ME_HOLYDAMAGE;
  4332. break;
  4333. }
  4334.  
  4335. case COMBAT_DEATHDAMAGE:
  4336. {
  4337. textColor = TEXTCOLOR_DARKRED;
  4338. hitEffect = NM_ME_SMALLCLOUDS;
  4339. break;
  4340. }
  4341.  
  4342. case COMBAT_LIFEDRAIN:
  4343. {
  4344. textColor = TEXTCOLOR_RED;
  4345. hitEffect = NM_ME_MAGIC_BLOOD;
  4346. break;
  4347. }
  4348.  
  4349. default:
  4350. break;
  4351. }
  4352.  
  4353. if(textColor != TEXTCOLOR_NONE)
  4354. {
  4355. addMagicEffect(list, targetPos, hitEffect);
  4356.  
  4357. std::ostringstream ss;
  4358. if(!attacker)
  4359. ss << ucfirst(target->getNameDescription()) << " loses " << damage << " hitpoint" << (damage != 1 ? "s." : ".");
  4360. else if(attacker == target)
  4361. ss << ucfirst(target->getNameDescription()) << " loses " << damage << " hitpoint" << (damage != 1 ? "s" : "") << " due to " << (targetPlayer ? (targetPlayer->getSex() == PLAYERSEX_FEMALE ? "her" : "his") : "its") << " own attack.";
  4362. else
  4363. ss << ucfirst(target->getNameDescription()) << " loses " << damage << " hitpoint" << (damage != 1 ? "s" : "") << " due to an attack by " << attacker->getNameDescription() << ".";
  4364.  
  4365. std::string message = ss.str();
  4366.  
  4367. Player* tmpPlayer = NULL;
  4368. SpectatorVec listEx;
  4369. getSpectators(listEx, targetPos);
  4370. for(SpectatorVec::const_iterator it = listEx.begin(), end = listEx.end(); it != end; ++it)
  4371. {
  4372. if((tmpPlayer = (*it)->getPlayer()))
  4373. {
  4374. if(tmpPlayer == attackerPlayer && attackerPlayer != targetPlayer)
  4375. {
  4376. std::ostringstream tmpSs;
  4377. tmpSs << ucfirst(target->getNameDescription()) << " loses " << damage << " hitpoint" << (damage != 1 ? "s" : "") << " due to your attack.";
  4378. tmpPlayer->sendDamageMessage(MSG_DAMAGE_DEALT, tmpSs.str(), targetPos, damage, textColor);
  4379. }
  4380. else if(tmpPlayer == targetPlayer)
  4381. {
  4382. std::ostringstream tmpSs;
  4383. if(!attacker)
  4384. tmpSs << "You lose " << damage << " hitpoint" << (damage != 1 ? "s." : ".");
  4385. else if(targetPlayer == attackerPlayer)
  4386. tmpSs << "You lose " << damage << " hitpoint" << (damage != 1 ? "s" : "") << " due to your own attack.";
  4387. else
  4388. tmpSs << "You lose " << damage << " hitpoint" << (damage != 1 ? "s" : "") << " due to an attack by " << attacker->getNameDescription() << ".";
  4389.  
  4390. tmpPlayer->sendDamageMessage(MSG_DAMAGE_RECEIVED, tmpSs.str(), targetPos, damage, textColor);
  4391. }
  4392. else
  4393. tmpPlayer->sendDamageMessage(MSG_DAMAGE_OTHERS, message, targetPos, damage, textColor);
  4394. }
  4395. }
  4396. }
  4397. }
  4398. }
  4399. }
  4400. return true;
  4401. }
  4402.  
  4403. bool Game::combatChangeMana(Creature* attacker, Creature* target, int32_t manaChange)
  4404. {
  4405. if(manaChange > 0)
  4406. {
  4407. if(attacker)
  4408. {
  4409. Player* attackerPlayer = attacker->getPlayer();
  4410. Player* targetPlayer = target->getPlayer();
  4411. if(attackerPlayer && targetPlayer)
  4412. {
  4413. if(g_config.getBoolean(ConfigManager::CANNOT_ATTACK_SAME_LOOKFEET) && attacker->defaultOutfit.lookFeet == target->defaultOutfit.lookFeet)
  4414. return false;
  4415.  
  4416. if(attackerPlayer->getSkull() == SKULL_BLACK && attackerPlayer->getSkullClient(targetPlayer) == SKULL_NONE)
  4417. return false;
  4418. }
  4419. }
  4420. target->changeMana(manaChange);
  4421. }
  4422. else
  4423. {
  4424. const Position& targetPos = target->getPosition();
  4425. if(!target->isAttackable() || Combat::canDoCombat(attacker, target) != RET_NOERROR)
  4426. {
  4427. addMagicEffect(getSpectators(targetPos), targetPos, NM_ME_POFF);
  4428. return false;
  4429. }
  4430.  
  4431. Player* attackerPlayer = NULL;
  4432. if(attacker)
  4433. attackerPlayer = attacker->getPlayer();
  4434.  
  4435. Player* targetPlayer = target->getPlayer();
  4436. if(attackerPlayer && targetPlayer)
  4437. {
  4438. if(g_config.getBoolean(ConfigManager::CANNOT_ATTACK_SAME_LOOKFEET) && attacker->defaultOutfit.lookFeet == target->defaultOutfit.lookFeet)
  4439. return false;
  4440.  
  4441. if(attackerPlayer->getSkull() == SKULL_BLACK && attackerPlayer->getSkullClient(targetPlayer) == SKULL_NONE)
  4442. return false;
  4443. }
  4444.  
  4445. int32_t manaLoss = std::min(target->getMana(), -manaChange);
  4446. BlockType_t blockType = target->blockHit(attacker, COMBAT_MANADRAIN, manaLoss);
  4447.  
  4448. if(blockType != BLOCK_NONE)
  4449. {
  4450. addMagicEffect(getSpectators(targetPos), targetPos, NM_ME_POFF);
  4451. return false;
  4452. }
  4453.  
  4454. if(manaLoss > 0)
  4455. {
  4456. target->drainMana(attacker, manaLoss);
  4457.  
  4458. std::ostringstream ss;
  4459. if(!attacker)
  4460. ss << ucfirst(target->getNameDescription()) << " loses " << manaLoss << " mana.";
  4461. else if(attacker == target)
  4462. ss << ucfirst(target->getNameDescription()) << " loses " << manaLoss << " mana blocking an attack by " << (targetPlayer ? (targetPlayer->getSex() == PLAYERSEX_FEMALE ? "herself." : "himself.") : "itself.");
  4463. else
  4464. ss << ucfirst(target->getNameDescription()) << " loses " << manaLoss << " mana blocking an attack by " << attacker->getNameDescription() << ".";
  4465.  
  4466. std::string message = ss.str();
  4467.  
  4468. Player* tmpPlayer = NULL;
  4469. SpectatorVec list;
  4470. getSpectators(list, targetPos);
  4471. for(SpectatorVec::const_iterator it = list.begin(), end = list.end(); it != end; ++it)
  4472. {
  4473. if((tmpPlayer = (*it)->getPlayer()))
  4474. {
  4475. if(tmpPlayer == attackerPlayer && attackerPlayer != targetPlayer)
  4476. {
  4477. std::ostringstream tmpSs;
  4478. tmpSs << ucfirst(target->getNameDescription()) << " loses " << manaLoss << " mana blocking your attack.";
  4479. tmpPlayer->sendDamageMessage(MSG_DAMAGE_DEALT, tmpSs.str(), targetPos, manaLoss, TEXTCOLOR_BLUE);
  4480. }
  4481. else if(tmpPlayer == targetPlayer)
  4482. {
  4483. std::ostringstream tmpSs;
  4484. if(!attacker)
  4485. tmpSs << "You lose " << manaLoss << " mana.";
  4486. else if(targetPlayer == attackerPlayer)
  4487. tmpSs << "You lose " << manaLoss << " mana blocking an attack by yourself.";
  4488. else
  4489. tmpSs << "You lose " << manaLoss << " mana blocking an attack by " << attacker->getNameDescription() << ".";
  4490.  
  4491. tmpPlayer->sendDamageMessage(MSG_DAMAGE_RECEIVED, tmpSs.str(), targetPos, manaLoss, TEXTCOLOR_BLUE);
  4492. }
  4493. else
  4494. tmpPlayer->sendDamageMessage(MSG_DAMAGE_OTHERS, message, targetPos, manaLoss, TEXTCOLOR_BLUE);
  4495. }
  4496. }
  4497. }
  4498. }
  4499. return true;
  4500. }
  4501.  
  4502. void Game::addCreatureHealth(const Creature* target)
  4503. {
  4504. const SpectatorVec& list = getSpectators(target->getPosition());
  4505. addCreatureHealth(list, target);
  4506. }
  4507.  
  4508. void Game::addCreatureHealth(const SpectatorVec& list, const Creature* target)
  4509. {
  4510. Player* player = NULL;
  4511. for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
  4512. {
  4513. if((player = (*it)->getPlayer()))
  4514. player->sendCreatureHealth(target);
  4515. }
  4516. }
  4517.  
  4518. void Game::addMagicEffect(const Position& pos, uint8_t effect, bool ghostMode /* = false */)
  4519. {
  4520. if(ghostMode)
  4521. return;
  4522.  
  4523. const SpectatorVec& list = getSpectators(pos);
  4524. addMagicEffect(list, pos, effect);
  4525. }
  4526.  
  4527. void Game::addMagicEffect(const SpectatorVec& list, const Position& pos, uint8_t effect, bool ghostMode /* = false */)
  4528. {
  4529. if(ghostMode)
  4530. return;
  4531.  
  4532. Player* player = NULL;
  4533. for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
  4534. {
  4535. if((player = (*it)->getPlayer()))
  4536. player->sendMagicEffect(pos, effect);
  4537. }
  4538. }
  4539.  
  4540. void Game::addDistanceEffect(const Position& fromPos, const Position& toPos,
  4541. uint8_t effect)
  4542. {
  4543. SpectatorVec list;
  4544.  
  4545. getSpectators(list, fromPos, false, true);
  4546. getSpectators(list, toPos, true, true);
  4547.  
  4548. Player* player = NULL;
  4549. for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
  4550. {
  4551. if((player = (*it)->getPlayer()))
  4552. player->sendDistanceShoot(fromPos, toPos, effect);
  4553. }
  4554. }
  4555.  
  4556. void Game::startDecay(Item* item)
  4557. {
  4558. if(item && item->canDecay())
  4559. {
  4560. uint32_t decayState = item->getDecaying();
  4561. if(decayState == DECAYING_TRUE)
  4562. return;
  4563.  
  4564. if(item->getDuration() > 0)
  4565. {
  4566. item->useThing2();
  4567. item->setDecaying(DECAYING_TRUE);
  4568. toDecayItems.push_back(item);
  4569. }
  4570. else
  4571. internalDecayItem(item);
  4572. }
  4573. }
  4574.  
  4575. void Game::internalDecayItem(Item* item)
  4576. {
  4577. const ItemType& it = Item::items[item->getID()];
  4578. if(it.decayTo != 0)
  4579. {
  4580. Item* newItem = transformItem(item, it.decayTo);
  4581. startDecay(newItem);
  4582. }
  4583. else
  4584. {
  4585. ReturnValue ret = internalRemoveItem(item);
  4586. if(ret != RET_NOERROR)
  4587. std::cout << "DEBUG, internalDecayItem failed, error code: " << (int32_t) ret << "item id: " << item->getID() << std::endl;
  4588. }
  4589. }
  4590.  
  4591. void Game::checkDecay()
  4592. {
  4593. checkDecayEvent = g_scheduler.addEvent(createSchedulerTask(EVENT_DECAYINTERVAL,
  4594. boost::bind(&Game::checkDecay, this)));
  4595.  
  4596. size_t bucket = (lastBucket + 1) % EVENT_DECAY_BUCKETS;
  4597. for(DecayList::iterator it = decayItems[bucket].begin(); it != decayItems[bucket].end();)
  4598. {
  4599. Item* item = *it;
  4600. if(!item->canDecay())
  4601. {
  4602. item->setDecaying(DECAYING_FALSE);
  4603. FreeThing(item);
  4604. it = decayItems[bucket].erase(it);
  4605. continue;
  4606. }
  4607.  
  4608. int32_t decreaseTime = EVENT_DECAYINTERVAL * EVENT_DECAY_BUCKETS;
  4609. if((int32_t)item->getDuration() - decreaseTime < 0)
  4610. decreaseTime = item->getDuration();
  4611.  
  4612. item->decreaseDuration(decreaseTime);
  4613.  
  4614. int32_t dur = item->getDuration();
  4615. if(dur <= 0)
  4616. {
  4617. it = decayItems[bucket].erase(it);
  4618. internalDecayItem(item);
  4619. FreeThing(item);
  4620. }
  4621. else if(dur < EVENT_DECAYINTERVAL * EVENT_DECAY_BUCKETS)
  4622. {
  4623. it = decayItems[bucket].erase(it);
  4624. size_t newBucket = (bucket + ((dur + EVENT_DECAYINTERVAL / 2) / 1000)) % EVENT_DECAY_BUCKETS;
  4625. if(newBucket == bucket)
  4626. {
  4627. internalDecayItem(item);
  4628. FreeThing(item);
  4629. }
  4630. else
  4631. decayItems[newBucket].push_back(item);
  4632. }
  4633. else
  4634. ++it;
  4635. }
  4636.  
  4637. lastBucket = bucket;
  4638. cleanup();
  4639. }
  4640.  
  4641. void Game::checkLight()
  4642. {
  4643. checkLightEvent = g_scheduler.addEvent(createSchedulerTask(EVENT_LIGHTINTERVAL,
  4644. boost::bind(&Game::checkLight, this)));
  4645.  
  4646. lightHour += lightHourDelta;
  4647. if(lightHour > 1440)
  4648. lightHour -= 1440;
  4649.  
  4650. if(std::abs(lightHour - SUNRISE) < 2 * lightHourDelta)
  4651. lightState = LIGHT_STATE_SUNRISE;
  4652. else if(std::abs(lightHour - SUNSET) < 2 * lightHourDelta)
  4653. lightState = LIGHT_STATE_SUNSET;
  4654.  
  4655. int32_t newLightLevel = lightLevel;
  4656. bool lightChange = false;
  4657. switch(lightState)
  4658. {
  4659. case LIGHT_STATE_SUNRISE:
  4660. {
  4661. newLightLevel += (LIGHT_LEVEL_DAY - LIGHT_LEVEL_NIGHT) / 30;
  4662. lightChange = true;
  4663. break;
  4664. }
  4665. case LIGHT_STATE_SUNSET:
  4666. {
  4667. newLightLevel -= (LIGHT_LEVEL_DAY - LIGHT_LEVEL_NIGHT) / 30;
  4668. lightChange = true;
  4669. break;
  4670. }
  4671. default:
  4672. break;
  4673. }
  4674.  
  4675. if(newLightLevel <= LIGHT_LEVEL_NIGHT)
  4676. {
  4677. lightLevel = LIGHT_LEVEL_NIGHT;
  4678. lightState = LIGHT_STATE_NIGHT;
  4679. }
  4680. else if(newLightLevel >= LIGHT_LEVEL_DAY)
  4681. {
  4682. lightLevel = LIGHT_LEVEL_DAY;
  4683. lightState = LIGHT_STATE_DAY;
  4684. }
  4685. else
  4686. lightLevel = newLightLevel;
  4687.  
  4688. if(lightChange)
  4689. {
  4690. LightInfo lightInfo;
  4691. getWorldLightInfo(lightInfo);
  4692. for(AutoList<Player>::listiterator it = Player::listPlayer.list.begin(); it != Player::listPlayer.list.end(); ++it)
  4693. (*it).second->sendWorldLight(lightInfo);
  4694. }
  4695. }
  4696.  
  4697. void Game::getWorldLightInfo(LightInfo& lightInfo) const
  4698. {
  4699. lightInfo.level = lightLevel;
  4700. lightInfo.color = 0xD7;
  4701. }
  4702.  
  4703. void Game::addCommandTag(std::string tag)
  4704. {
  4705. bool found = false;
  4706. for(uint32_t i=0; i< commandTags.size() ;i++)
  4707. {
  4708. if(commandTags[i] == tag)
  4709. {
  4710. found = true;
  4711. break;
  4712. }
  4713. }
  4714.  
  4715. if(!found)
  4716. commandTags.push_back(tag);
  4717. }
  4718.  
  4719. void Game::resetCommandTag()
  4720. {
  4721. commandTags.clear();
  4722. }
  4723.  
  4724. void Game::shutdown()
  4725. {
  4726. std::cout << "Shutting down server..." << std::flush;
  4727.  
  4728. g_scheduler.shutdown();
  4729. g_dispatcher.shutdown();
  4730. Spawns::getInstance()->clear();
  4731. Raids::getInstance()->clear();
  4732.  
  4733. cleanup();
  4734.  
  4735. if(services)
  4736. services->stop();
  4737.  
  4738. std::cout << " done!";
  4739. }
  4740.  
  4741. void Game::cleanup()
  4742. {
  4743. //free memory
  4744. for(std::vector<Thing*>::iterator it = ToReleaseThings.begin(); it != ToReleaseThings.end(); ++it)
  4745. (*it)->releaseThing2();
  4746.  
  4747. ToReleaseThings.clear();
  4748. for(DecayList::iterator it = toDecayItems.begin(); it != toDecayItems.end(); ++it)
  4749. {
  4750. int32_t dur = (*it)->getDuration();
  4751. if(dur >= EVENT_DECAYINTERVAL * EVENT_DECAY_BUCKETS)
  4752. decayItems[lastBucket].push_back(*it);
  4753. else
  4754. decayItems[(lastBucket + 1 + (*it)->getDuration() / 1000) % EVENT_DECAY_BUCKETS].push_back(*it);
  4755. }
  4756.  
  4757. toDecayItems.clear();
  4758. }
  4759.  
  4760. void Game::FreeThing(Thing* thing)
  4761. {
  4762. ToReleaseThings.push_back(thing);
  4763. }
  4764.  
  4765. bool Game::reloadHighscores()
  4766. {
  4767. lastHSUpdate = time(NULL);
  4768. for(int16_t i = 0; i <= 8; i++)
  4769. highscoreStorage[i] = getHighscore(i);
  4770. return true;
  4771. }
  4772.  
  4773. void Game::timedHighscoreUpdate()
  4774. {
  4775. int32_t highscoreUpdateTime = g_config.getNumber(ConfigManager::HIGHSCORES_UPDATETIME) * 60 * 1000;
  4776. if(highscoreUpdateTime <= 0)
  4777. return;
  4778.  
  4779. reloadHighscores();
  4780. g_scheduler.addEvent(createSchedulerTask(highscoreUpdateTime, boost::bind(&Game::timedHighscoreUpdate, this)));
  4781. }
  4782.  
  4783. std::string Game::getHighscoreString(uint16_t skill)
  4784. {
  4785. Highscore hs = highscoreStorage[skill];
  4786. std::ostringstream ss;
  4787. ss << "Highscore for " << getSkillName(skill) << "\n\nRank Level - Player Name";
  4788. for(uint32_t i = 0; i < hs.size(); ++i)
  4789. ss << "\n" << (i + 1) << ". " << hs[i].second << " - " << hs[i].first;
  4790.  
  4791. ss << "\n\nLast updated on:\n" << std::ctime(&lastHSUpdate);
  4792. std::string highscoresStr = ss.str();
  4793. highscoresStr.erase(highscoresStr.length() - 1);
  4794. return highscoresStr;
  4795. }
  4796.  
  4797. bool Game::broadcastMessage(const std::string& text, MessageClasses type)
  4798. {
  4799. std::cout << "> Broadcasted message: \"" << text << "\"." << std::endl;
  4800. for(AutoList<Player>::listiterator it = Player::listPlayer.list.begin(); it != Player::listPlayer.list.end(); ++it)
  4801. (*it).second->sendTextMessage(type, text);
  4802. return true;
  4803. }
  4804.  
  4805. Highscore Game::getHighscore(uint16_t skill)
  4806. {
  4807. Highscore hs;
  4808. Database* db = Database::getInstance();
  4809.  
  4810. DBQuery query;
  4811. uint32_t highscoresTop = g_config.getNumber(ConfigManager::HIGHSCORES_TOP);
  4812. if(skill > SKILL_LAST)
  4813. {
  4814. if(skill == SKILL__MAGLEVEL)
  4815. query << "SELECT `name`, `maglevel` FROM `players` ORDER BY `maglevel` DESC, `manaspent` DESC LIMIT " << highscoresTop;
  4816. else if(skill == SKILL__LEVEL)
  4817. query << "SELECT `name`, `level` FROM `players` ORDER BY `level` DESC, `experience` DESC LIMIT " << highscoresTop;
  4818. else
  4819. return hs;
  4820.  
  4821. DBResult* result;
  4822. if((result = db->storeQuery(query.str())))
  4823. {
  4824. do
  4825. {
  4826. uint32_t level;
  4827. if(skill == SKILL__MAGLEVEL)
  4828. level = result->getDataInt("maglevel");
  4829. else
  4830. level = result->getDataInt("level");
  4831.  
  4832. hs.push_back(make_pair(result->getDataString("name"), level));
  4833.  
  4834. highscoresTop--;
  4835. if(highscoresTop == 0)
  4836. break;
  4837. }
  4838. while(result->next());
  4839. db->freeResult(result);
  4840. }
  4841. }
  4842. else
  4843. {
  4844. query << "SELECT * FROM `player_skills` WHERE `skillid`=" << skill << " ORDER BY `value` DESC, `count` DESC";
  4845.  
  4846. DBResult* result;
  4847. if((result = db->storeQuery(query.str())))
  4848. {
  4849. do
  4850. {
  4851. query.str("");
  4852. query << "SELECT `name` FROM `players` WHERE `id` = " << result->getDataInt("player_id") << ";";
  4853.  
  4854. DBResult* tmpResult;
  4855. if((tmpResult = db->storeQuery(query.str())))
  4856. {
  4857. hs.push_back(make_pair(tmpResult->getDataString("name"), result->getDataInt("value")));
  4858. db->freeResult(tmpResult);
  4859. }
  4860.  
  4861. highscoresTop--;
  4862. if(highscoresTop == 0)
  4863. break;
  4864. }
  4865. while(result->next());
  4866. db->freeResult(result);
  4867. }
  4868. }
  4869. return hs;
  4870. }
  4871.  
  4872. void Game::updateCreatureSkull(Player* player)
  4873. {
  4874. if(getWorldType() != WORLD_TYPE_PVP)
  4875. return;
  4876.  
  4877. const SpectatorVec& list = getSpectators(player->getPosition());
  4878.  
  4879. //send to client
  4880. Player* tmpPlayer = NULL;
  4881. for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
  4882. {
  4883. if((tmpPlayer = (*it)->getPlayer()))
  4884. tmpPlayer->sendCreatureSkull(player);
  4885. }
  4886. }
  4887.  
  4888. void Game::updatePremium(Account& account)
  4889. {
  4890. bool save = false;
  4891. time_t timeNow = time(NULL);
  4892. if(account.premiumDays != 0 && account.premiumDays != 0xFFFF)
  4893. {
  4894. if(account.lastDay == 0)
  4895. {
  4896. account.lastDay = timeNow;
  4897. save = true;
  4898. }
  4899. else
  4900. {
  4901. uint32_t days = (timeNow - account.lastDay) / 86400;
  4902. if(days > 0)
  4903. {
  4904. if(days >= account.premiumDays)
  4905. {
  4906. account.premiumDays = 0;
  4907. account.lastDay = 0;
  4908. }
  4909. else
  4910. {
  4911. account.premiumDays -= days;
  4912. uint32_t remainder = (timeNow - account.lastDay) % 86400;
  4913. account.lastDay = timeNow - remainder;
  4914. }
  4915. save = true;
  4916. }
  4917. }
  4918. }
  4919. else if(account.lastDay != 0)
  4920. {
  4921. account.lastDay = 0;
  4922. save = true;
  4923. }
  4924.  
  4925. if(save && !IOLoginData::getInstance()->saveAccount(account))
  4926. std::cout << "> ERROR: Failed to save account: " << account.name << "!" << std::endl;
  4927. }
  4928.  
  4929. void Game::autoSave()
  4930. {
  4931. int32_t autoSaveEachMinutes = g_config.getNumber(ConfigManager::AUTO_SAVE_EACH_MINUTES);
  4932. if(autoSaveEachMinutes <= 0)
  4933. return;
  4934.  
  4935. g_dispatcher.addTask(createTask(boost::bind(&Game::saveGameState, this)));
  4936. g_scheduler.addEvent(createSchedulerTask(autoSaveEachMinutes * 1000 * 60, boost::bind(&Game::autoSave, this)));
  4937. }
  4938.  
  4939. void Game::prepareServerSave()
  4940. {
  4941. if(!serverSaveMessage[0])
  4942. {
  4943. serverSaveMessage[0] = true;
  4944. broadcastMessage("Server is saving game in 5 minutes. Please logout.", MSG_STATUS_WARNING);
  4945. g_scheduler.addEvent(createSchedulerTask(120000, boost::bind(&Game::prepareServerSave, this)));
  4946. }
  4947. else if(!serverSaveMessage[1])
  4948. {
  4949. serverSaveMessage[1] = true;
  4950. broadcastMessage("Server is saving game in 3 minutes. Please logout.", MSG_STATUS_WARNING);
  4951. g_scheduler.addEvent(createSchedulerTask(120000, boost::bind(&Game::prepareServerSave, this)));
  4952. }
  4953. else if(!serverSaveMessage[2])
  4954. {
  4955. serverSaveMessage[2] = true;
  4956. broadcastMessage("Server is saving game in one minute. Please logout.", MSG_STATUS_WARNING);
  4957. g_scheduler.addEvent(createSchedulerTask(60000, boost::bind(&Game::prepareServerSave, this)));
  4958. }
  4959. else
  4960. serverSave();
  4961. }
  4962.  
  4963. void Game::serverSave()
  4964. {
  4965. if(g_config.getBoolean(ConfigManager::SHUTDOWN_AT_SERVERSAVE))
  4966. {
  4967. //shutdown server
  4968. setGameState(GAME_STATE_SHUTDOWN);
  4969. }
  4970. else
  4971. {
  4972. //close server
  4973. setGameState(GAME_STATE_CLOSED);
  4974.  
  4975. //clean map if configured to
  4976. if(g_config.getBoolean(ConfigManager::CLEAN_MAP_AT_SERVERSAVE))
  4977. map->clean();
  4978.  
  4979. //reload highscores
  4980. reloadHighscores();
  4981.  
  4982. //reset variables
  4983. for(int16_t i = 0; i < 3; i++)
  4984. setServerSaveMessage(i, false);
  4985.  
  4986. //prepare for next serversave after 24 hours
  4987. g_scheduler.addEvent(createSchedulerTask(86100000, boost::bind(&Game::prepareServerSave, this)));
  4988.  
  4989. //open server
  4990. setGameState(GAME_STATE_NORMAL);
  4991. }
  4992. }
  4993.  
  4994. Position Game::getClosestFreeTile(Player* player, Creature* teleportedCreature, Position toPos, bool teleport)
  4995. {
  4996. int i;
  4997. Tile* tile[9] =
  4998. {
  4999. getTile(toPos.x, toPos.y, toPos.z),
  5000. getTile(toPos.x - 1, toPos.y - 1, toPos.z), getTile(toPos.x, toPos.y - 1, toPos.z),
  5001. getTile(toPos.x + 1, toPos.y - 1, toPos.z), getTile(toPos.x - 1, toPos.y, toPos.z),
  5002. getTile(toPos.x + 1, toPos.y, toPos.z), getTile(toPos.x - 1, toPos.y + 1, toPos.z),
  5003. getTile(toPos.x, toPos.y + 1, toPos.z), getTile(toPos.x + 1, toPos.y + 1, toPos.z),
  5004. };
  5005. if(teleport)
  5006. {
  5007. if(player)
  5008. {
  5009. for(i = 0; i < 9; i++)
  5010. {
  5011. if(tile[i] && ((!tile[i]->hasProperty(IMMOVABLEBLOCKSOLID) && tile[i]->getCreatureCount() == 0) || player->getAccountType() == ACCOUNT_TYPE_GOD))
  5012. return tile[i]->getPosition();
  5013. }
  5014. }
  5015. }
  5016. else if(teleportedCreature)
  5017. {
  5018. Player* teleportedPlayer = teleportedCreature->getPlayer();
  5019. if(teleportedPlayer)
  5020. {
  5021. for(i = 0; i < 9; i++)
  5022. {
  5023. if(tile[i] && ((!tile[i]->hasProperty(IMMOVABLEBLOCKSOLID) && tile[i]->getCreatureCount() == 0) || teleportedPlayer->getAccountType() == ACCOUNT_TYPE_GOD))
  5024. return tile[i]->getPosition();
  5025. }
  5026. }
  5027. else
  5028. {
  5029. for(i = 0; i < 9; i++)
  5030. {
  5031. if(tile[i] && tile[i]->getCreatureCount() == 0 && !tile[i]->hasProperty(IMMOVABLEBLOCKSOLID))
  5032. return tile[i]->getPosition();
  5033. }
  5034. }
  5035. }
  5036. return Position(0, 0, 0);
  5037. }
  5038.  
  5039. int32_t Game::getMotdNum()
  5040. {
  5041. if(lastMotdText != g_config.getString(ConfigManager::MOTD))
  5042. {
  5043. lastMotdNum++;
  5044. lastMotdText = g_config.getString(ConfigManager::MOTD);
  5045.  
  5046. FILE* file = fopen("lastMotd.txt", "w");
  5047. if(file != NULL)
  5048. {
  5049. fprintf(file, "%d", lastMotdNum);
  5050. fprintf(file, "\n%s", lastMotdText.c_str());
  5051. fclose(file);
  5052. }
  5053. }
  5054. return lastMotdNum;
  5055. }
  5056.  
  5057. void Game::loadMotd()
  5058. {
  5059. std::ifstream file("lastMotd.txt");
  5060. if(!file)
  5061. {
  5062. std::cout << "> ERROR: Failed to load lastMotd.txt" << std::endl;
  5063. lastMotdNum = random_range(5, 500);
  5064. return;
  5065. }
  5066.  
  5067. std::string tmpStr;
  5068. getline(file, tmpStr);
  5069. getline(file, lastMotdText);
  5070. lastMotdNum = atoi(tmpStr.c_str());
  5071. file.close();
  5072. }
  5073.  
  5074. void Game::checkPlayersRecord()
  5075. {
  5076. if(getPlayersOnline() > lastPlayersRecord)
  5077. {
  5078. uint32_t tmplPlayersRecord = lastPlayersRecord;
  5079. lastPlayersRecord = getPlayersOnline();
  5080. GlobalEventMap recordEvents = g_globalEvents->getEventMap(GLOBALEVENT_RECORD);
  5081. for(GlobalEventMap::iterator it = recordEvents.begin(); it != recordEvents.end(); ++it)
  5082. it->second->executeRecord(lastPlayersRecord, tmplPlayersRecord);
  5083.  
  5084. savePlayersRecord();
  5085. }
  5086. }
  5087.  
  5088. void Game::savePlayersRecord()
  5089. {
  5090. FILE* file = fopen("playersRecord.txt", "w");
  5091. if(file == NULL)
  5092. {
  5093. std::cout << "> ERROR: Failed to save playersRecord.txt" << std::endl;
  5094. return;
  5095. }
  5096.  
  5097. int32_t tmp = fprintf(file, "%u", lastPlayersRecord);
  5098. if(tmp == EOF)
  5099. {
  5100. std::cout << "> ERROR: Failed to save playersRecord.txt" << std::endl;
  5101. return;
  5102. }
  5103.  
  5104. fclose(file);
  5105. }
  5106.  
  5107. void Game::loadPlayersRecord()
  5108. {
  5109. FILE* file = fopen("playersRecord.txt", "r");
  5110. if(file == NULL)
  5111. {
  5112. std::cout << "> ERROR: Failed to load playersRecord.txt" << std::endl;
  5113. lastPlayersRecord = 0;
  5114. return;
  5115. }
  5116.  
  5117. int32_t tmp = fscanf(file, "%u", &lastPlayersRecord);
  5118. if(tmp == EOF)
  5119. {
  5120. std::cout << "> ERROR: Failed to read playersRecord.txt" << std::endl;
  5121. lastPlayersRecord = 0;
  5122. }
  5123. fclose(file);
  5124. }
  5125.  
  5126. uint64_t Game::getExperienceStage(uint32_t level)
  5127. {
  5128. if(!stagesEnabled)
  5129. return g_config.getNumber(ConfigManager::RATE_EXPERIENCE);
  5130.  
  5131. if(useLastStageLevel && level >= lastStageLevel)
  5132. return stages[lastStageLevel];
  5133. else
  5134. return stages[level];
  5135. }
  5136.  
  5137. bool Game::loadExperienceStages()
  5138. {
  5139. std::string filename = "data/XML/stages.xml";
  5140. xmlDocPtr doc = xmlParseFile(filename.c_str());
  5141. if(doc)
  5142. {
  5143. xmlNodePtr root, p;
  5144. int32_t intVal, low, high, mult;
  5145. root = xmlDocGetRootElement(doc);
  5146. if(xmlStrcmp(root->name,(const xmlChar*)"stages"))
  5147. {
  5148. xmlFreeDoc(doc);
  5149. return false;
  5150. }
  5151. p = root->children;
  5152.  
  5153. while(p)
  5154. {
  5155. if(!xmlStrcmp(p->name, (const xmlChar*)"config"))
  5156. {
  5157. if(readXMLInteger(p, "enabled", intVal))
  5158. stagesEnabled = (intVal != 0);
  5159. }
  5160. else if(!xmlStrcmp(p->name, (const xmlChar*)"stage"))
  5161. {
  5162. if(readXMLInteger(p, "minlevel", intVal))
  5163. low = intVal;
  5164. else
  5165. low = 1;
  5166.  
  5167. if(readXMLInteger(p, "maxlevel", intVal))
  5168. high = intVal;
  5169. else
  5170. {
  5171. high = 0;
  5172. lastStageLevel = low;
  5173. useLastStageLevel = true;
  5174. }
  5175.  
  5176. if(readXMLInteger(p, "multiplier", intVal))
  5177. mult = intVal;
  5178. else
  5179. mult = 1;
  5180.  
  5181. if(useLastStageLevel)
  5182. stages[lastStageLevel] = mult;
  5183. else
  5184. {
  5185. for(int32_t iteratorValue = low; iteratorValue <= high; iteratorValue++)
  5186. stages[iteratorValue] = mult;
  5187. }
  5188. }
  5189. p = p->next;
  5190. }
  5191. xmlFreeDoc(doc);
  5192. }
  5193. return true;
  5194. }
  5195.  
  5196. bool Game::playerInviteToParty(uint32_t playerId, uint32_t invitedId)
  5197. {
  5198. Player* player = getPlayerByID(playerId);
  5199. if(!player || player->isRemoved())
  5200. return false;
  5201.  
  5202. Player* invitedPlayer = getPlayerByID(invitedId);
  5203. if(!invitedPlayer || invitedPlayer->isRemoved() || invitedPlayer->isInviting(player))
  5204. return false;
  5205.  
  5206. if(invitedPlayer->getParty())
  5207. {
  5208. std::ostringstream ss;
  5209. ss << invitedPlayer->getName() << " is already in a party.";
  5210. player->sendTextMessage(MSG_INFO_DESCR, ss.str());
  5211. return false;
  5212. }
  5213.  
  5214. Party* party = player->getParty();
  5215. if(!party)
  5216. party = new Party(player);
  5217. else if(party->getLeader() != player)
  5218. return false;
  5219.  
  5220. return party->invitePlayer(invitedPlayer);
  5221. }
  5222.  
  5223. bool Game::playerJoinParty(uint32_t playerId, uint32_t leaderId)
  5224. {
  5225. Player* player = getPlayerByID(playerId);
  5226. if(!player || player->isRemoved())
  5227. return false;
  5228.  
  5229. Player* leader = getPlayerByID(leaderId);
  5230. if(!leader || leader->isRemoved() || !leader->isInviting(player))
  5231. return false;
  5232.  
  5233. Party* party = leader->getParty();
  5234. if(!party || party->getLeader() != leader)
  5235. return false;
  5236.  
  5237. if(player->getParty())
  5238. {
  5239. player->sendTextMessage(MSG_INFO_DESCR, "You are already in a party.");
  5240. return false;
  5241. }
  5242. return party->joinParty(player);
  5243. }
  5244.  
  5245. bool Game::playerRevokePartyInvitation(uint32_t playerId, uint32_t invitedId)
  5246. {
  5247. Player* player = getPlayerByID(playerId);
  5248. if(!player || player->isRemoved())
  5249. return false;
  5250.  
  5251. Party* party = player->getParty();
  5252. if(!party || party->getLeader() != player)
  5253. return false;
  5254.  
  5255. Player* invitedPlayer = getPlayerByID(invitedId);
  5256. if(!invitedPlayer || invitedPlayer->isRemoved() || !player->isInviting(invitedPlayer))
  5257. return false;
  5258.  
  5259. party->revokeInvitation(invitedPlayer);
  5260. return true;
  5261. }
  5262.  
  5263. bool Game::playerPassPartyLeadership(uint32_t playerId, uint32_t newLeaderId)
  5264. {
  5265. Player* player = getPlayerByID(playerId);
  5266. if(!player || player->isRemoved())
  5267. return false;
  5268.  
  5269. Party* party = player->getParty();
  5270. if(!party || party->getLeader() != player)
  5271. return false;
  5272.  
  5273. Player* newLeader = getPlayerByID(newLeaderId);
  5274. if(!newLeader || newLeader->isRemoved() || !player->isPartner(newLeader))
  5275. return false;
  5276.  
  5277. return party->passPartyLeadership(newLeader);
  5278. }
  5279.  
  5280. bool Game::playerLeaveParty(uint32_t playerId)
  5281. {
  5282. Player* player = getPlayerByID(playerId);
  5283. if(!player || player->isRemoved())
  5284. return false;
  5285.  
  5286. Party* party = player->getParty();
  5287. if(!party || player->hasCondition(CONDITION_INFIGHT))
  5288. return false;
  5289.  
  5290. return party->leaveParty(player);
  5291. }
  5292.  
  5293. bool Game::playerEnableSharedPartyExperience(uint32_t playerId, bool sharedExpActive)
  5294. {
  5295. Player* player = getPlayerByID(playerId);
  5296. if(!player || player->isRemoved())
  5297. return false;
  5298.  
  5299. Party* party = player->getParty();
  5300. if(!party || player->hasCondition(CONDITION_INFIGHT))
  5301. return false;
  5302.  
  5303. return party->setSharedExperience(player, sharedExpActive);
  5304. }
  5305.  
  5306. void Game::sendGuildMotd(uint32_t playerId, uint32_t guildId)
  5307. {
  5308. Player* player = getPlayerByID(playerId);
  5309. if(!player || player->isRemoved())
  5310. return;
  5311.  
  5312. player->sendChannelMessage("Message of the Day", IOGuild::getInstance()->getMotd(guildId), SPEAK_CHANNEL_R1, CHANNEL_GUILD);
  5313. }
  5314.  
  5315. void Game::kickPlayer(uint32_t playerId, bool displayEffect)
  5316. {
  5317. Player* player = getPlayerByID(playerId);
  5318. if(!player || player->isRemoved())
  5319. return;
  5320.  
  5321. player->kickPlayer(displayEffect);
  5322. }
  5323.  
  5324. bool Game::playerReportBug(uint32_t playerId, std::string bug)
  5325. {
  5326. Player* player = getPlayerByID(playerId);
  5327. if(!player || player->isRemoved())
  5328. return false;
  5329.  
  5330. if(player->getAccountType() == ACCOUNT_TYPE_NORMAL)
  5331. return false;
  5332.  
  5333. std::string fileName = "data/reports/" + player->getName() + " report.txt";
  5334. FILE* file = fopen(fileName.c_str(), "a");
  5335. if(file)
  5336. {
  5337. const Position& position = player->getPosition();
  5338. fprintf(file, "------------------------------\nName: %s [Position X: %d Y: %d Z: %d]\nBug Report: %s\n", player->getName().c_str(), position.x, position.y, position.z, bug.c_str());
  5339. fclose(file);
  5340. }
  5341.  
  5342. player->sendTextMessage(MSG_EVENT_DEFAULT, "Your report has been sent to " + g_config.getString(ConfigManager::SERVER_NAME) + ".");
  5343. return true;
  5344. }
  5345.  
  5346. bool Game::playerDebugAssert(uint32_t playerId, std::string assertLine, std::string date, std::string description, std::string comment)
  5347. {
  5348. Player* player = getPlayerByID(playerId);
  5349. if(!player || player->isRemoved())
  5350. return false;
  5351.  
  5352. FILE* file = fopen("client_assertions.txt", "a");
  5353. if(file)
  5354. {
  5355. fprintf(file, "----- %s - %s (%s) -----\n", formatDate(time(NULL)).c_str(), player->getName().c_str(), convertIPToString(player->getIP()).c_str());
  5356. fprintf(file, "%s\n%s\n%s\n%s\n", assertLine.c_str(), date.c_str(), description.c_str(), comment.c_str());
  5357. fclose(file);
  5358. }
  5359. return true;
  5360. }
  5361.  
  5362. bool Game::playerLeaveMarket(uint32_t playerId)
  5363. {
  5364. Player* player = getPlayerByID(playerId);
  5365. if(!player || player->isRemoved())
  5366. return false;
  5367.  
  5368. player->setMarketDepotId(-1);
  5369. return true;
  5370. }
  5371.  
  5372. bool Game::playerBrowseMarket(uint32_t playerId, uint16_t spriteId)
  5373. {
  5374. Player* player = getPlayerByID(playerId);
  5375. if(!player || player->isRemoved())
  5376. return false;
  5377.  
  5378. if(player->getMarketDepotId() == -1)
  5379. return false;
  5380.  
  5381. const ItemType& it = Item::items.getItemIdByClientId(spriteId);
  5382. if(it.id == 0)
  5383. return false;
  5384.  
  5385. if(!it.ware)
  5386. return false;
  5387.  
  5388. const MarketOfferList& buyOffers = IOMarket::getInstance()->getActiveOffers(MARKETACTION_BUY, it.id);
  5389. const MarketOfferList& sellOffers = IOMarket::getInstance()->getActiveOffers(MARKETACTION_SELL, it.id);
  5390. player->sendMarketBrowseItem(it.id, buyOffers, sellOffers);
  5391. player->sendMarketDetail(it.id);
  5392. return true;
  5393. }
  5394.  
  5395. bool Game::playerBrowseMarketOwnOffers(uint32_t playerId)
  5396. {
  5397. Player* player = getPlayerByID(playerId);
  5398. if(!player || player->isRemoved())
  5399. return false;
  5400.  
  5401. if(player->getMarketDepotId() == -1)
  5402. return false;
  5403.  
  5404. const MarketOfferList& buyOffers = IOMarket::getInstance()->getOwnOffers(MARKETACTION_BUY, player->getGUID());
  5405. const MarketOfferList& sellOffers = IOMarket::getInstance()->getOwnOffers(MARKETACTION_SELL, player->getGUID());
  5406. player->sendMarketBrowseOwnOffers(buyOffers, sellOffers);
  5407. return true;
  5408. }
  5409.  
  5410. bool Game::playerBrowseMarketOwnHistory(uint32_t playerId)
  5411. {
  5412. Player* player = getPlayerByID(playerId);
  5413. if(!player || player->isRemoved())
  5414. return false;
  5415.  
  5416. if(player->getMarketDepotId() == -1)
  5417. return false;
  5418.  
  5419. const HistoryMarketOfferList& buyOffers = IOMarket::getInstance()->getOwnHistory(MARKETACTION_BUY, player->getGUID());
  5420. const HistoryMarketOfferList& sellOffers = IOMarket::getInstance()->getOwnHistory(MARKETACTION_SELL, player->getGUID());
  5421. player->sendMarketBrowseOwnHistory(buyOffers, sellOffers);
  5422. return true;
  5423. }
  5424.  
  5425. bool Game::playerCreateMarketOffer(uint32_t playerId, uint8_t type, uint16_t spriteId, uint16_t amount, uint32_t price, bool anonymous)
  5426. {
  5427. if(amount == 0 || amount > 64000)
  5428. return false;
  5429.  
  5430. if(price == 0 || price > 999999999)
  5431. return false;
  5432.  
  5433. if(type != MARKETACTION_BUY && type != MARKETACTION_SELL)
  5434. return false;
  5435.  
  5436. Player* player = getPlayerByID(playerId);
  5437. if(!player || player->isRemoved())
  5438. return false;
  5439.  
  5440. if(player->getMarketDepotId() == -1)
  5441. return false;
  5442.  
  5443. if(g_config.getBoolean(ConfigManager::MARKET_PREMIUM) && !player->isPremium())
  5444. {
  5445. player->sendMarketLeave();
  5446. return false;
  5447. }
  5448.  
  5449. const ItemType& it = Item::items.getItemIdByClientId(spriteId);
  5450. if(it.id == 0)
  5451. return false;
  5452.  
  5453. if(!it.ware)
  5454. return false;
  5455.  
  5456. const int32_t maxOfferCount = g_config.getNumber(ConfigManager::MAX_MARKET_OFFERS_AT_A_TIME_PER_PLAYER);
  5457. if(maxOfferCount > 0)
  5458. {
  5459. const int32_t offerCount = IOMarket::getInstance()->getPlayerOfferCount(player->getGUID());
  5460. if(offerCount == -1 || offerCount >= maxOfferCount)
  5461. return false;
  5462. }
  5463.  
  5464. uint64_t fee = (price / 100.) * amount;
  5465. if(fee < 20)
  5466. fee = 20;
  5467. else if(fee > 1000)
  5468. fee = 1000;
  5469.  
  5470. if(type == MARKETACTION_SELL)
  5471. {
  5472. if(fee > player->bankBalance)
  5473. return false;
  5474.  
  5475. Depot* depot = player->getDepot(player->getMarketDepotId(), false);
  5476. if(!depot)
  5477. return false;
  5478.  
  5479. ItemList itemList;
  5480. uint32_t count = 0;
  5481. std::list<Container*> containerList;
  5482. containerList.push_back(depot->getChest());
  5483. bool enough = false;
  5484. do
  5485. {
  5486. Container* container = containerList.front();
  5487. containerList.pop_front();
  5488. for(ItemList::const_iterator iter = container->getItems(), end = container->getEnd(); iter != end; ++iter)
  5489. {
  5490. Item* item = (*iter);
  5491. Container* c = item->getContainer();
  5492. if(c && !c->empty())
  5493. {
  5494. containerList.push_back(c);
  5495. continue;
  5496. }
  5497.  
  5498. if(item->getID() != it.id)
  5499. continue;
  5500.  
  5501. const ItemType& itemType = Item::items[item->getID()];
  5502. if(!itemType.isRune() && item->getCharges() != itemType.charges)
  5503. continue;
  5504.  
  5505. if(item->getDuration() != itemType.decayTime)
  5506. continue;
  5507.  
  5508. itemList.push_back(item);
  5509. count += Item::countByType(item, -1);
  5510. if(count >= amount)
  5511. {
  5512. enough = true;
  5513. break;
  5514. }
  5515. }
  5516.  
  5517. if(enough)
  5518. break;
  5519. }
  5520. while(!containerList.empty());
  5521.  
  5522. if(!enough)
  5523. return false;
  5524.  
  5525. if(it.stackable)
  5526. {
  5527. uint16_t tmpAmount = amount;
  5528. for(ItemList::const_iterator iter = itemList.begin(), end = itemList.end(); iter != end; ++iter)
  5529. {
  5530. uint16_t removeCount = std::min(tmpAmount, (*iter)->getItemCount());
  5531. tmpAmount -= removeCount;
  5532. internalRemoveItem(*iter, removeCount);
  5533. if(tmpAmount == 0)
  5534. break;
  5535. }
  5536. }
  5537. else
  5538. {
  5539. for(ItemList::const_iterator iter = itemList.begin(), end = itemList.end(); iter != end; ++iter)
  5540. internalRemoveItem(*iter);
  5541. }
  5542. player->bankBalance -= fee;
  5543. }
  5544. else
  5545. {
  5546. uint64_t totalPrice = (uint64_t)price * amount;
  5547. totalPrice += fee;
  5548. if(totalPrice > player->bankBalance)
  5549. return false;
  5550.  
  5551. player->bankBalance -= totalPrice;
  5552. }
  5553.  
  5554. IOMarket::getInstance()->createOffer(player->getGUID(), (MarketAction_t)type, it.id, amount, price, anonymous);
  5555.  
  5556. player->sendMarketEnter(player->getMarketDepotId());
  5557. const MarketOfferList& buyOffers = IOMarket::getInstance()->getActiveOffers(MARKETACTION_BUY, it.id);
  5558. const MarketOfferList& sellOffers = IOMarket::getInstance()->getActiveOffers(MARKETACTION_SELL, it.id);
  5559. player->sendMarketBrowseItem(it.id, buyOffers, sellOffers);
  5560. return true;
  5561. }
  5562.  
  5563. bool Game::playerCancelMarketOffer(uint32_t playerId, uint32_t timestamp, uint16_t counter)
  5564. {
  5565. Player* player = getPlayerByID(playerId);
  5566. if(!player || player->isRemoved())
  5567. return false;
  5568.  
  5569. if(player->getMarketDepotId() == -1)
  5570. return false;
  5571.  
  5572. uint32_t offerId = IOMarket::getInstance()->getOfferIdByCounter(timestamp, counter);
  5573. if(offerId == 0)
  5574. return false;
  5575.  
  5576. MarketOfferEx offer = IOMarket::getInstance()->getOfferById(offerId);
  5577. if(offer.playerId != player->getGUID())
  5578. return false;
  5579.  
  5580. if(offer.type == MARKETACTION_BUY)
  5581. {
  5582. player->bankBalance += (uint64_t)offer.price * offer.amount;
  5583. player->sendMarketEnter(player->getMarketDepotId());
  5584. }
  5585. else
  5586. {
  5587. const ItemType& it = Item::items[offer.itemId];
  5588. if(it.id == 0)
  5589. return false;
  5590.  
  5591. Depot* depot = player->getDepot(player->getMarketDepotId(), true);
  5592. if(it.stackable)
  5593. {
  5594. uint16_t tmpAmount = offer.amount;
  5595. while(tmpAmount > 0)
  5596. {
  5597. int32_t stackCount = std::min((int32_t)100, (int32_t)tmpAmount);
  5598. Item* item = Item::CreateItem(it.id, stackCount);
  5599. if(internalAddItem(depot->getInbox(), item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RET_NOERROR)
  5600. {
  5601. delete item;
  5602. break;
  5603. }
  5604.  
  5605. tmpAmount -= stackCount;
  5606. }
  5607. }
  5608. else
  5609. {
  5610. int32_t subType = -1;
  5611. if(it.charges != 0)
  5612. subType = it.charges;
  5613.  
  5614. for(uint16_t i = 0; i < offer.amount; ++i)
  5615. {
  5616. Item* item = Item::CreateItem(it.id, subType);
  5617. if(internalAddItem(depot->getInbox(), item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RET_NOERROR)
  5618. {
  5619. delete item;
  5620. break;
  5621. }
  5622. }
  5623. }
  5624. }
  5625.  
  5626. IOMarket::getInstance()->moveOfferToHistory(offerId, OFFERSTATE_CANCELLED);
  5627. offer.amount = 0;
  5628. offer.timestamp += g_config.getNumber(ConfigManager::MARKET_OFFER_DURATION);
  5629. player->sendMarketCancelOffer(offer);
  5630. return true;
  5631. }
  5632.  
  5633. bool Game::playerAcceptMarketOffer(uint32_t playerId, uint32_t timestamp, uint16_t counter, uint16_t amount)
  5634. {
  5635. if(amount == 0 || amount > 64000)
  5636. return false;
  5637.  
  5638. Player* player = getPlayerByID(playerId);
  5639. if(!player || player->isRemoved())
  5640. return false;
  5641.  
  5642. if(player->getMarketDepotId() == -1)
  5643. return false;
  5644.  
  5645. uint32_t offerId = IOMarket::getInstance()->getOfferIdByCounter(timestamp, counter);
  5646. if(offerId == 0)
  5647. return false;
  5648.  
  5649. MarketOfferEx offer = IOMarket::getInstance()->getOfferById(offerId);
  5650. if(amount > offer.amount)
  5651. return false;
  5652.  
  5653. const ItemType& it = Item::items[offer.itemId];
  5654. if(it.id == 0)
  5655. return false;
  5656.  
  5657. uint64_t totalPrice = (uint64_t)offer.price * amount;
  5658. if(offer.type == MARKETACTION_BUY)
  5659. {
  5660. Depot* depot = player->getDepot(player->getMarketDepotId(), false);
  5661. if(!depot)
  5662. return false;
  5663.  
  5664. ItemList itemList;
  5665. uint32_t count = 0;
  5666. std::list<Container*> containerList;
  5667. containerList.push_back(depot->getChest());
  5668. bool enough = false;
  5669. do
  5670. {
  5671. Container* container = containerList.front();
  5672. containerList.pop_front();
  5673. for(ItemList::const_iterator iter = container->getItems(), end = container->getEnd(); iter != end; ++iter)
  5674. {
  5675. Item* item = (*iter);
  5676. Container* c = item->getContainer();
  5677. if(c && !c->empty())
  5678. {
  5679. containerList.push_back(c);
  5680. continue;
  5681. }
  5682.  
  5683. if(item->getID() != it.id)
  5684. continue;
  5685.  
  5686. const ItemType& itemType = Item::items[item->getID()];
  5687. if(!itemType.isRune() && item->getCharges() != itemType.charges)
  5688. continue;
  5689.  
  5690. if(item->getDuration() != itemType.decayTime)
  5691. continue;
  5692.  
  5693. itemList.push_back(item);
  5694. count += Item::countByType(item, -1);
  5695. if(count >= amount)
  5696. {
  5697. enough = true;
  5698. break;
  5699. }
  5700. }
  5701.  
  5702. if(enough)
  5703. break;
  5704. }
  5705. while(!containerList.empty());
  5706.  
  5707. if(!enough)
  5708. return false;
  5709.  
  5710. if(it.stackable)
  5711. {
  5712. uint16_t tmpAmount = amount;
  5713. for(ItemList::const_iterator iter = itemList.begin(), end = itemList.end(); iter != end; ++iter)
  5714. {
  5715. uint16_t removeCount = std::min(tmpAmount, (*iter)->getItemCount());
  5716. tmpAmount -= removeCount;
  5717. internalRemoveItem(*iter, removeCount);
  5718. if(tmpAmount == 0)
  5719. break;
  5720. }
  5721. }
  5722. else
  5723. {
  5724. for(ItemList::const_iterator iter = itemList.begin(), end = itemList.end(); iter != end; ++iter)
  5725. internalRemoveItem(*iter);
  5726. }
  5727.  
  5728. player->bankBalance += totalPrice;
  5729.  
  5730. Player* buyerPlayer = getPlayerByGUID(offer.playerId);
  5731. if(!buyerPlayer)
  5732. {
  5733. std::string buyerName;
  5734. if(!IOLoginData::getInstance()->getNameByGuid(offer.playerId, buyerName))
  5735. return false;
  5736.  
  5737. buyerPlayer = new Player(buyerName, NULL);
  5738. if(!IOLoginData::getInstance()->loadPlayer(buyerPlayer, buyerName))
  5739. {
  5740. delete buyerPlayer;
  5741. return false;
  5742. }
  5743. }
  5744. buyerPlayer->setDepotChange(true);
  5745.  
  5746. Depot* buyerDepot = buyerPlayer->getDepot(buyerPlayer->getTown(), true);
  5747. if(it.stackable)
  5748. {
  5749. uint16_t tmpAmount = amount;
  5750. while(tmpAmount > 0)
  5751. {
  5752. uint16_t stackCount = std::min((uint16_t)100, tmpAmount);
  5753. Item* item = Item::CreateItem(it.id, stackCount);
  5754. if(internalAddItem(buyerDepot->getInbox(), item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RET_NOERROR)
  5755. {
  5756. delete item;
  5757. break;
  5758. }
  5759.  
  5760. tmpAmount -= stackCount;
  5761. }
  5762. }
  5763. else
  5764. {
  5765. int32_t subType = -1;
  5766. if(it.charges != 0)
  5767. subType = it.charges;
  5768.  
  5769. for(uint16_t i = 0; i < amount; ++i)
  5770. {
  5771. Item* item = Item::CreateItem(it.id, subType);
  5772. if(internalAddItem(buyerDepot->getInbox(), item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RET_NOERROR)
  5773. {
  5774. delete item;
  5775. break;
  5776. }
  5777. }
  5778. }
  5779.  
  5780. if(buyerPlayer->isOffline())
  5781. {
  5782. IOLoginData::getInstance()->savePlayer(buyerPlayer, true);
  5783. delete buyerPlayer;
  5784. }
  5785. }
  5786. else
  5787. {
  5788. if(totalPrice > player->bankBalance)
  5789. return false;
  5790.  
  5791. player->bankBalance -= totalPrice;
  5792.  
  5793. Depot* depot = player->getDepot(player->getMarketDepotId(), true);
  5794. if(it.stackable)
  5795. {
  5796. uint16_t tmpAmount = amount;
  5797. while(tmpAmount > 0)
  5798. {
  5799. uint16_t stackCount = std::min((uint16_t)100, tmpAmount);
  5800. Item* item = Item::CreateItem(it.id, stackCount);
  5801. if(internalAddItem(depot->getInbox(), item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RET_NOERROR)
  5802. {
  5803. delete item;
  5804. break;
  5805. }
  5806.  
  5807. tmpAmount -= stackCount;
  5808. }
  5809. }
  5810. else
  5811. {
  5812. int32_t subType = -1;
  5813. if(it.charges != 0)
  5814. subType = it.charges;
  5815.  
  5816. for(uint16_t i = 0; i < amount; ++i)
  5817. {
  5818. Item* item = Item::CreateItem(it.id, subType);
  5819. if(internalAddItem(depot->getInbox(), item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RET_NOERROR)
  5820. {
  5821. delete item;
  5822. break;
  5823. }
  5824. }
  5825. }
  5826.  
  5827. Player* sellerPlayer = getPlayerByGUID(offer.playerId);
  5828. if(sellerPlayer)
  5829. sellerPlayer->bankBalance += totalPrice;
  5830. else
  5831. IOLoginData::getInstance()->increaseBankBalance(offer.playerId, totalPrice);
  5832. }
  5833.  
  5834. const int32_t marketOfferDuration = g_config.getNumber(ConfigManager::MARKET_OFFER_DURATION);
  5835. IOMarket::getInstance()->appendHistory(player->getGUID(), (offer.type == MARKETACTION_BUY ? MARKETACTION_SELL : MARKETACTION_BUY), offer.itemId, amount, offer.price, offer.timestamp + marketOfferDuration, OFFERSTATE_ACCEPTEDEX);
  5836. IOMarket::getInstance()->appendHistory(offer.playerId, offer.type, offer.itemId, amount, offer.price, offer.timestamp + marketOfferDuration, OFFERSTATE_ACCEPTED);
  5837.  
  5838. offer.amount -= amount;
  5839. if(offer.amount == 0)
  5840. IOMarket::getInstance()->deleteOffer(offerId);
  5841. else
  5842. IOMarket::getInstance()->acceptOffer(offerId, amount);
  5843.  
  5844. player->sendMarketEnter(player->getMarketDepotId());
  5845. offer.timestamp += marketOfferDuration;
  5846. player->sendMarketAcceptOffer(offer);
  5847. return true;
  5848. }
  5849.  
  5850. void Game::checkExpiredMarketOffers()
  5851. {
  5852. IOMarket::getInstance()->clearOldHistory();
  5853.  
  5854. const ExpiredMarketOfferList& expiredBuyOffers = IOMarket::getInstance()->getExpiredOffers(MARKETACTION_BUY);
  5855. for(ExpiredMarketOfferList::const_iterator it = expiredBuyOffers.begin(), end = expiredBuyOffers.end(); it != end; ++it)
  5856. {
  5857. ExpiredMarketOffer offer = *it;
  5858.  
  5859. Player* player = getPlayerByGUID(offer.playerId);
  5860. uint64_t totalPrice = (uint64_t)offer.price * offer.amount;
  5861. if(player)
  5862. player->bankBalance += totalPrice;
  5863. else
  5864. IOLoginData::getInstance()->increaseBankBalance(offer.playerId, totalPrice);
  5865.  
  5866. IOMarket::getInstance()->moveOfferToHistory(offer.id, OFFERSTATE_EXPIRED);
  5867. }
  5868.  
  5869. const ExpiredMarketOfferList& expiredSellOffers = IOMarket::getInstance()->getExpiredOffers(MARKETACTION_SELL);
  5870. for(ExpiredMarketOfferList::const_iterator it = expiredSellOffers.begin(), end = expiredSellOffers.end(); it != end; ++it)
  5871. {
  5872. ExpiredMarketOffer offer = *it;
  5873.  
  5874. Player* player = getPlayerByGUID(offer.playerId);
  5875. if(!player)
  5876. {
  5877. std::string name;
  5878. if(!IOLoginData::getInstance()->getNameByGuid(offer.playerId, name))
  5879. continue;
  5880.  
  5881. player = new Player(name, NULL);
  5882. if(!IOLoginData::getInstance()->loadPlayer(player, name))
  5883. {
  5884. delete player;
  5885. continue;
  5886. }
  5887. }
  5888. player->setDepotChange(true);
  5889.  
  5890. const ItemType& itemType = Item::items[offer.itemId];
  5891. if(itemType.id == 0)
  5892. continue;
  5893.  
  5894. Depot* depot = player->getDepot(player->getTown(), true);
  5895. if(itemType.stackable)
  5896. {
  5897. uint16_t tmpAmount = offer.amount;
  5898. while(tmpAmount > 0)
  5899. {
  5900. uint16_t stackCount = std::min((uint16_t)100, tmpAmount);
  5901. Item* item = Item::CreateItem(itemType.id, stackCount);
  5902. if(internalAddItem(depot->getInbox(), item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RET_NOERROR)
  5903. {
  5904. delete item;
  5905. break;
  5906. }
  5907.  
  5908. tmpAmount -= stackCount;
  5909. }
  5910. }
  5911. else
  5912. {
  5913. int32_t subType = -1;
  5914. if(itemType.charges != 0)
  5915. subType = itemType.charges;
  5916.  
  5917. for(uint16_t i = 0; i < offer.amount; ++i)
  5918. {
  5919. Item* item = Item::CreateItem(itemType.id, subType);
  5920. if(internalAddItem(depot->getInbox(), item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RET_NOERROR)
  5921. {
  5922. delete item;
  5923. break;
  5924. }
  5925. }
  5926. }
  5927.  
  5928. if(player->isOffline())
  5929. {
  5930. IOLoginData::getInstance()->savePlayer(player, true);
  5931. delete player;
  5932. }
  5933.  
  5934. IOMarket::getInstance()->moveOfferToHistory(offer.id, OFFERSTATE_EXPIRED);
  5935. }
  5936.  
  5937. int32_t checkExpiredMarketOffersEachMinutes = g_config.getNumber(ConfigManager::CHECK_EXPIRED_MARKET_OFFERS_EACH_MINUTES);
  5938. if(checkExpiredMarketOffersEachMinutes <= 0)
  5939. return;
  5940.  
  5941. g_scheduler.addEvent(createSchedulerTask(checkExpiredMarketOffersEachMinutes * 60 * 1000, boost::bind(&Game::checkExpiredMarketOffers, this)));
  5942. }
  5943.  
  5944. void Game::forceAddCondition(uint32_t creatureId, Condition* condition)
  5945. {
  5946. Creature* creature = getCreatureByID(creatureId);
  5947. if(!creature || creature->isRemoved())
  5948. return;
  5949.  
  5950. creature->addCondition(condition, true);
  5951. }
  5952.  
  5953. void Game::forceRemoveCondition(uint32_t creatureId, ConditionType_t type)
  5954. {
  5955. Creature* creature = getCreatureByID(creatureId);
  5956. if(!creature || creature->isRemoved())
  5957. return;
  5958.  
  5959. creature->removeCondition(type, true);
  5960. }
  5961.  
  5962. bool Game::violationWindow(Player* player, std::string targetPlayerName, int32_t reason, int32_t action, std::string banComment, bool IPBanishment)
  5963. {
  5964. if((0 == (violationActions[player->getAccountType()] & (1 << action)))
  5965. || reason > violationReasons[player->getAccountType()]
  5966. || (IPBanishment && (violationActions[player->getAccountType()] & Action_IpBan) != Action_IpBan))
  5967. {
  5968. player->sendCancel("You do not have authorization for this action.");
  5969. return false;
  5970. }
  5971.  
  5972. //If this will be configurable, the field in the database has to be edited
  5973. //since its a VARCHAR(60).
  5974. if(banComment.size() > 60)
  5975. {
  5976. player->sendCancel("The comment may not exceed the limit of 60 characters.");
  5977. return false;
  5978. }
  5979.  
  5980. bool playerExists = false;
  5981. if(IOLoginData::getInstance()->playerExists(targetPlayerName))
  5982. playerExists = true;
  5983.  
  5984. toLowerCaseString(targetPlayerName);
  5985. if(!playerExists || (g_config.getBoolean(ConfigManager::ACCOUNT_MANAGER) && targetPlayerName == "account manager"))
  5986. {
  5987. player->sendCancel("A player with this name does not exist.");
  5988. return false;
  5989. }
  5990.  
  5991. AccountType_t targetAccountType = ACCOUNT_TYPE_NORMAL;
  5992. Account account;
  5993. uint32_t guid;
  5994. Player* targetPlayer = getPlayerByName(targetPlayerName);
  5995. if(targetPlayer)
  5996. {
  5997. targetAccountType = targetPlayer->getAccountType();
  5998. guid = targetPlayer->getGUID();
  5999. account = IOLoginData::getInstance()->loadAccount(targetPlayer->getAccount());
  6000. targetPlayerName = targetPlayer->getName();
  6001. }
  6002. else
  6003. {
  6004. targetAccountType = IOLoginData::getInstance()->getAccountType(targetPlayerName);
  6005. IOLoginData::getInstance()->getGuidByName(guid, targetPlayerName);
  6006. account = IOLoginData::getInstance()->loadAccount(IOLoginData::getInstance()->getAccountNumberByName(targetPlayerName));
  6007. }
  6008.  
  6009. if(targetAccountType >= player->getAccountType())
  6010. {
  6011. player->sendCancel("You do not have authorization for this action.");
  6012. return false;
  6013. }
  6014.  
  6015. bool isNotation = false;
  6016. switch(action)
  6017. {
  6018. case 0:
  6019. {
  6020. IOBan::getInstance()->addAccountNotation(account.id, time(NULL), reason, action, banComment, player->getGUID());
  6021. if(IOBan::getInstance()->getNotationsCount(account.id) > 2)
  6022. {
  6023. account.warnings++;
  6024. if(account.warnings > 3)
  6025. {
  6026. action = 7;
  6027. IOBan::getInstance()->addAccountDeletion(account.id, time(NULL), reason, action, banComment, player->getGUID());
  6028. }
  6029. else if(account.warnings == 3)
  6030. IOBan::getInstance()->addAccountBan(account.id, (time(NULL) + (g_config.getNumber(ConfigManager::FINAL_BAN_DAYS) * 86400)), reason, action, banComment, player->getGUID());
  6031. else
  6032. IOBan::getInstance()->addAccountBan(account.id, (time(NULL) + (g_config.getNumber(ConfigManager::BAN_DAYS) * 86400)), reason, action, "4 notations received, auto banishment.", player->getGUID());
  6033. }
  6034. else
  6035. isNotation = true;
  6036.  
  6037. break;
  6038. }
  6039.  
  6040. case 1:
  6041. {
  6042. IOBan::getInstance()->addPlayerNamelock(guid, time(NULL), reason, action, banComment, player->getGUID());
  6043. break;
  6044. }
  6045.  
  6046. case 3:
  6047. {
  6048. account.warnings++;
  6049. if(account.warnings > 3)
  6050. {
  6051. action = 7;
  6052. IOBan::getInstance()->addAccountDeletion(account.id, time(NULL), reason, action, banComment, player->getGUID());
  6053. }
  6054. else
  6055. {
  6056. if(account.warnings == 3)
  6057. IOBan::getInstance()->addAccountBan(account.id, (time(NULL) + (g_config.getNumber(ConfigManager::FINAL_BAN_DAYS) * 86400)), reason, action, banComment, player->getGUID());
  6058. else
  6059. IOBan::getInstance()->addAccountBan(account.id, (time(NULL) + (g_config.getNumber(ConfigManager::BAN_DAYS) * 86400)), reason, action, banComment, player->getGUID());
  6060.  
  6061. IOBan::getInstance()->addPlayerNamelock(guid, time(NULL), reason, action, banComment, player->getGUID());
  6062. }
  6063. break;
  6064. }
  6065.  
  6066. case 4:
  6067. {
  6068. if(account.warnings < 3)
  6069. {
  6070. account.warnings = 3;
  6071. IOBan::getInstance()->addAccountBan(account.id, (time(NULL) + (g_config.getNumber(ConfigManager::FINAL_BAN_DAYS) * 86400)), reason, action, banComment, player->getGUID());
  6072. }
  6073. else
  6074. {
  6075. action = 7;
  6076. account.warnings++;
  6077. IOBan::getInstance()->addAccountDeletion(account.id, time(NULL), reason, action, banComment, player->getGUID());
  6078. }
  6079. break;
  6080. }
  6081.  
  6082. case 5:
  6083. {
  6084. if(account.warnings < 3)
  6085. {
  6086. account.warnings = 3;
  6087. IOBan::getInstance()->addAccountBan(account.id, (time(NULL) + (g_config.getNumber(ConfigManager::FINAL_BAN_DAYS) * 86400)), reason, action, banComment, player->getGUID());
  6088. IOBan::getInstance()->addPlayerNamelock(guid, time(NULL), reason, action, banComment, player->getGUID());
  6089. }
  6090. else
  6091. {
  6092. action = 7;
  6093. account.warnings++;
  6094. IOBan::getInstance()->addAccountDeletion(account.id, time(NULL), reason, action, banComment, player->getGUID());
  6095. }
  6096. break;
  6097. }
  6098.  
  6099. default:
  6100. {
  6101. account.warnings++;
  6102. if(account.warnings > 3)
  6103. {
  6104. action = 7;
  6105. IOBan::getInstance()->addAccountDeletion(account.id, time(NULL), reason, action, banComment, player->getGUID());
  6106. }
  6107. else
  6108. {
  6109. if(account.warnings == 3)
  6110. IOBan::getInstance()->addAccountBan(account.id, (time(NULL) + (g_config.getNumber(ConfigManager::FINAL_BAN_DAYS) * 86400)), reason, action, banComment, player->getGUID());
  6111. else
  6112. IOBan::getInstance()->addAccountBan(account.id, (time(NULL) + (g_config.getNumber(ConfigManager::BAN_DAYS) * 86400)), reason, action, banComment, player->getGUID());
  6113. }
  6114. break;
  6115. }
  6116. }
  6117.  
  6118. if(g_config.getBoolean(ConfigManager::BROADCAST_BANISHMENTS))
  6119. {
  6120. std::ostringstream ss;
  6121. if(isNotation)
  6122. ss << targetPlayerName << " has received a notation by " << player->getName() << " (" << (3 - IOBan::getInstance()->getNotationsCount(account.id)) << " more to ban).";
  6123. else
  6124. ss << player->getName() << " has taken the action \"" << getAction(action, IPBanishment) << "\" against: " << targetPlayerName << " (Warnings: " << account.warnings << "), with reason: \"" << getReason(reason) << "\", and comment: \"" << banComment << "\".";
  6125.  
  6126. broadcastMessage(ss.str(), MSG_STATUS_WARNING);
  6127. }
  6128. else
  6129. {
  6130. std::ostringstream ss;
  6131. if(isNotation)
  6132. ss << "You have taken the action notation against " << targetPlayerName << " (" << (3 - IOBan::getInstance()->getNotationsCount(account.id)) << " more to ban).";
  6133. else
  6134. ss << "You have taken the action \"" << getAction(action, IPBanishment) << "\" against: " << targetPlayerName << " (Warnings: " << account.warnings << "), with reason: \"" << getReason(reason) << "\", and comment: \"" << banComment << "\".";
  6135.  
  6136. player->sendTextMessage(MSG_STATUS_CONSOLE_RED, ss.str());
  6137. }
  6138.  
  6139. if(targetPlayer)
  6140. {
  6141. if(IPBanishment)
  6142. {
  6143. uint32_t ip = targetPlayer->lastIP;
  6144. if(ip > 0)
  6145. IOBan::getInstance()->addIpBan(ip, 0xFFFFFFFF, (time(NULL) + 86400));
  6146. }
  6147.  
  6148. if(!isNotation)
  6149. {
  6150. addMagicEffect(targetPlayer->getPosition(), NM_ME_MAGIC_POISON);
  6151.  
  6152. uint32_t playerId = targetPlayer->getID();
  6153. g_scheduler.addEvent(createSchedulerTask(1000, boost::bind(&Game::kickPlayer, this, playerId, false)));
  6154. }
  6155. }
  6156. else if(IPBanishment)
  6157. {
  6158. uint32_t lastip = IOLoginData::getInstance()->getLastIPByName(targetPlayerName);
  6159. if(lastip != 0)
  6160. IOBan::getInstance()->addIpBan(lastip, 0xFFFFFFFF, (time(NULL) + 86400));
  6161. }
  6162.  
  6163. if(!isNotation)
  6164. IOBan::getInstance()->removeAccountNotations(account.id);
  6165.  
  6166. IOLoginData::getInstance()->saveAccount(account);
  6167. return true;
  6168. }
  6169.  
  6170. bool Game::loadStatuslist()
  6171. {
  6172. xmlDocPtr doc = xmlParseFile("http://forgottenserver.otland.net/statuslist.xml");
  6173. if(!doc)
  6174. return false;
  6175.  
  6176. xmlNodePtr p, root = xmlDocGetRootElement(doc);
  6177. if(!xmlStrcmp(root->name, (const xmlChar*)"statuslist"))
  6178. {
  6179. p = root->children;
  6180. while(p)
  6181. {
  6182. if(!xmlStrcmp(p->name, (const xmlChar*)"blacklist"))
  6183. {
  6184. std::string ip;
  6185. if(readXMLString(p, "ip", ip))
  6186. blacklist.push_back(ip);
  6187. }
  6188. else if(!xmlStrcmp(p->name, (const xmlChar*)"whitelist"))
  6189. {
  6190. std::string ip;
  6191. if(readXMLString(p, "ip", ip))
  6192. whitelist.push_back(ip);
  6193. }
  6194.  
  6195. p = p->next;
  6196. }
  6197. }
  6198.  
  6199. xmlFreeDoc(doc);
  6200. return true;
  6201. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement