Advertisement
Guest User

Game.cpp

a guest
Aug 21st, 2021
217
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 197.24 KB | None | 0 0
  1. ////////////////////////////////////////////////////////////////////////
  2. // OpenTibia - an opensource roleplaying game
  3. ////////////////////////////////////////////////////////////////////////
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16. ////////////////////////////////////////////////////////////////////////
  17. #include "otpch.h"
  18. #include "game.h"
  19.  
  20. #include "configmanager.h"
  21. #ifdef __LOGIN_SERVER__
  22. #include "gameservers.h"
  23. #endif
  24. #include "server.h"
  25. #include "chat.h"
  26.  
  27. #include "luascript.h"
  28. #include "creature.h"
  29. #include "combat.h"
  30. #include "tile.h"
  31.  
  32. #include "database.h"
  33. #include "iologindata.h"
  34. #include "ioban.h"
  35. #include "ioguild.h"
  36.  
  37. #include "items.h"
  38. #include "trashholder.h"
  39. #include "container.h"
  40. #include "monsters.h"
  41.  
  42. #include "house.h"
  43. #include "quests.h"
  44.  
  45. #include "actions.h"
  46. #include "globalevent.h"
  47. #include "movement.h"
  48. #include "raids.h"
  49. #include "scriptmanager.h"
  50. #include "spells.h"
  51. #include "talkaction.h"
  52. #include "weapons.h"
  53.  
  54. #include "teleport.h"
  55. #include "textlogger.h"
  56. #include "vocation.h"
  57. #include "group.h"
  58.  
  59. #ifdef __EXCEPTION_TRACER__
  60. #include "exception.h"
  61. #endif
  62.  
  63. extern ConfigManager g_config;
  64. extern Actions* g_actions;
  65. extern Monsters g_monsters;
  66. extern Npcs g_npcs;
  67. extern Chat g_chat;
  68. extern TalkActions* g_talkActions;
  69. extern Spells* g_spells;
  70. extern MoveEvents* g_moveEvents;
  71. extern Weapons* g_weapons;
  72. extern CreatureEvents* g_creatureEvents;
  73. extern GlobalEvents* g_globalEvents;
  74.  
  75. Game::Game()
  76. {
  77.     gameState = GAMESTATE_NORMAL;
  78.     worldType = WORLDTYPE_OPEN;
  79.     map = NULL;
  80.     playersRecord = lastStageLevel = 0;
  81.  
  82.     //(1440 minutes/day) * 10 seconds event interval / (3600 seconds/day)
  83.     lightHourDelta = 1440 * 10 / 3600;
  84.     lightHour = SUNRISE + (SUNSET - SUNRISE) / 2;
  85.     lightLevel = LIGHT_LEVEL_DAY;
  86.     lightState = LIGHT_STATE_DAY;
  87.  
  88.     lastBucket = checkCreatureLastIndex = checkLightEvent = checkCreatureEvent = checkDecayEvent = saveEvent = 0;
  89.     checkWarsEvent = 0;
  90.     checkEndingWars = false;
  91. }
  92.  
  93. Game::~Game()
  94. {
  95.     delete map;
  96. }
  97.  
  98. WorldType_t Game::getWorldType(const Player* player, const Player* target/* = NULL*/) const
  99. {
  100.     std::string value;
  101.     return g_config.getBool(ConfigManager::OPTIONAL_PROTECTION) && ((player && player->getStorage("protected", value)
  102.         && booleanString(value)) || (player && target && target->getStorage("protected", value)
  103.         && booleanString(value) && !player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges)))
  104.         ? WORLDTYPE_OPTIONAL : worldType;
  105. }
  106.  
  107. void Game::start(ServiceManager* servicer)
  108. {
  109.     checkDecayEvent = Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_DECAYINTERVAL,
  110.         boost::bind(&Game::checkDecay, this)));
  111.     checkCreatureEvent = Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_CREATURE_THINK_INTERVAL,
  112.         boost::bind(&Game::checkCreatures, this)));
  113.     checkLightEvent = Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_LIGHTINTERVAL,
  114.         boost::bind(&Game::checkLight, this)));
  115.     checkWarsEvent = Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_WARSINTERVAL,
  116.         boost::bind(&Game::checkWars, this)));
  117.  
  118.     services = servicer;
  119.     if(!g_config.getBool(ConfigManager::GLOBALSAVE_ENABLED))
  120.         return;
  121.  
  122.     int32_t prepareHour = g_config.getNumber(ConfigManager::GLOBALSAVE_H),
  123.         prepareMinute = g_config.getNumber(ConfigManager::GLOBALSAVE_M);
  124.  
  125.     if(prepareHour < 0 || prepareHour > 24)
  126.     {
  127.         std::clog << "> WARNING: No valid hour (" << prepareHour << ") for a global save, should be between 0-23. Global save disabled." << std::endl;
  128.         return;
  129.     }
  130.  
  131.     if(prepareMinute < 0 || prepareMinute > 59)
  132.     {
  133.         std::clog << "> WARNING: No valid minute (" << prepareMinute << ") for a global save, should be between 0-59. Global save disabled." << std::endl;
  134.         return;
  135.     }
  136.  
  137.     time_t timeNow = time(NULL);
  138.     const tm* theTime = localtime(&timeNow);
  139.  
  140.     int32_t hour = theTime->tm_hour, minute = theTime->tm_min, second = theTime->tm_sec,
  141.         hoursLeft = 0, minutesLeft = 0, broadcast = 5;
  142.  
  143.     if(!prepareHour)
  144.         prepareHour = 24;
  145.  
  146.     if(hour != prepareHour)
  147.     {
  148.         if(prepareMinute >= 5)
  149.             prepareMinute -= 5;
  150.         else
  151.         {
  152.             prepareHour--;
  153.             prepareMinute = 55 + prepareMinute;
  154.         }
  155.  
  156.         if(hour > prepareHour)
  157.             hoursLeft = 24 - (hour - prepareHour);
  158.         else
  159.             hoursLeft = prepareHour - hour;
  160.  
  161.         if(minute > prepareMinute)
  162.         {
  163.             minutesLeft = 60 - (minute - prepareMinute);
  164.             hoursLeft--;
  165.         }
  166.         else if(minute != prepareMinute)
  167.             minutesLeft = prepareMinute - minute;
  168.     }
  169.     else
  170.     {
  171.         if(minute > prepareMinute)
  172.         {
  173.             minutesLeft = 55 - (minute - prepareMinute);
  174.             hoursLeft = 23;
  175.         }
  176.         else
  177.         {
  178.             minutesLeft = prepareMinute - minute;
  179.             if(minutesLeft >= 5)
  180.                 minutesLeft = minutesLeft - 5;
  181.             else if(minutesLeft == 3 || minutesLeft == 1)
  182.             {
  183.                 prepareGlobalSave(minutesLeft);
  184.                 return;
  185.             }
  186.             else if(minutesLeft > 0)
  187.             {
  188.                 broadcast = (minutesLeft == 2 ? 1 : 3);
  189.                 minutesLeft = 1;
  190.             }
  191.         }
  192.     }
  193.  
  194.     uint32_t timeLeft = (hoursLeft * 60 * 60 * 1000) + (minutesLeft * 60 * 1000);
  195.     if(timeLeft > 0)
  196.     {
  197.         timeLeft -= second * 1000;
  198.         saveEvent = Scheduler::getInstance().addEvent(createSchedulerTask(timeLeft,
  199.             boost::bind(&Game::prepareGlobalSave, this, broadcast)));
  200.     }
  201. }
  202.  
  203. void Game::loadGameState()
  204. {
  205.     ScriptEnviroment::loadGameState();
  206.     loadPlayersRecord();
  207.     loadMotd();
  208.     checkHighscores();
  209. }
  210.  
  211. void Game::setGameState(GameState_t newState)
  212. {
  213.     if(gameState == GAMESTATE_SHUTDOWN)
  214.         return; //this cannot be stopped
  215.  
  216.     if(gameState != newState)
  217.     {
  218.         gameState = newState;
  219.         switch(newState)
  220.         {
  221.             case GAMESTATE_INIT:
  222.             {
  223.                 Spawns::getInstance()->startup();
  224.                 Raids::getInstance()->startup();
  225.  
  226.                 loadGameState();
  227.  
  228.                 g_globalEvents->startup();
  229.                 if(g_config.getBool(ConfigManager::INIT_PREMIUM_UPDATE))
  230.                     IOLoginData::getInstance()->updatePremiumDays();
  231.  
  232.                 IOGuild::getInstance()->checkWars();
  233.                 IOGuild::getInstance()->checkEndingWars();
  234.                 break;
  235.             }
  236.  
  237.             case GAMESTATE_SHUTDOWN:
  238.             {
  239.                 g_globalEvents->execute(GLOBALEVENT_SHUTDOWN);
  240.                 AutoList<Player>::iterator it = Player::autoList.begin();
  241.                 while(it != Player::autoList.end()) //kick all players that are still online
  242.                 {
  243.                     it->second->kick(true, true);
  244.                     it = Player::autoList.begin();
  245.                 }
  246.  
  247.                 Houses::getInstance()->check();
  248.                 saveGameState((uint8_t)SAVE_PLAYERS | (uint8_t)SAVE_MAP | (uint8_t)SAVE_STATE);
  249.                 Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::shutdown, this)));
  250.  
  251.                 Scheduler::getInstance().stop();
  252.                 Dispatcher::getInstance().stop();
  253.                 break;
  254.             }
  255.  
  256.             case GAMESTATE_CLOSED:
  257.             {
  258.                 AutoList<Player>::iterator it = Player::autoList.begin();
  259.                 while(it != Player::autoList.end()) //kick all players who not allowed to stay
  260.                 {
  261.                     if(!it->second->hasFlag(PlayerFlag_CanAlwaysLogin))
  262.                     {
  263.                         it->second->kick(true, true);
  264.                         it = Player::autoList.begin();
  265.                     }
  266.                     else
  267.                         ++it;
  268.                 }
  269.  
  270.                 map->updateAuctions();
  271.                 saveGameState((uint8_t)SAVE_PLAYERS | (uint8_t)SAVE_MAP | (uint8_t)SAVE_STATE);
  272.                 break;
  273.             }
  274.  
  275.             case GAMESTATE_NORMAL:
  276.             case GAMESTATE_MAINTAIN:
  277.             case GAMESTATE_STARTUP:
  278.             case GAMESTATE_CLOSING:
  279.             default:
  280.                 break;
  281.         }
  282.     }
  283. }
  284.  
  285. void Game::saveGameState(uint8_t flags)
  286. {
  287.     std::clog << "> Saving server..." << std::endl;
  288.     uint64_t start = OTSYS_TIME();
  289.     if(gameState == GAMESTATE_NORMAL)
  290.         setGameState(GAMESTATE_MAINTAIN);
  291.  
  292.     if(hasBitSet(SAVE_PLAYERS, flags))
  293.     {
  294.         IOLoginData* io = IOLoginData::getInstance();
  295.         for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
  296.         {
  297.             it->second->loginPosition = it->second->getPosition();
  298.             io->savePlayer(it->second, false, hasBitSet(SAVE_PLAYERS_SHALLOW, flags));
  299.         }
  300.     }
  301.  
  302.     if(hasBitSet(SAVE_MAP, flags))
  303.         map->saveMap();
  304.  
  305.     if(hasBitSet(SAVE_STATE, flags))
  306.         ScriptEnviroment::saveGameState();
  307.  
  308.     if(gameState == GAMESTATE_MAINTAIN)
  309.         setGameState(GAMESTATE_NORMAL);
  310.  
  311.     std::clog << "> SAVE: Complete in " << (OTSYS_TIME() - start) / (1000.) << " seconds using "
  312.         << asLowerCaseString(g_config.getString(ConfigManager::HOUSE_STORAGE))
  313.         << " house storage." << std::endl;
  314. }
  315.  
  316. int32_t Game::loadMap(std::string filename)
  317. {
  318.     if(!map)
  319.         map = new Map;
  320.  
  321.     std::string file = getFilePath(FILE_TYPE_CONFIG, "world/" + filename);
  322.     if(!fileExists(file))
  323.         file = getFilePath(FILE_TYPE_OTHER, "world/" + filename);
  324.  
  325.     return map->loadMap(file);
  326. }
  327.  
  328. void Game::cleanMapEx(uint32_t& count)
  329. {
  330.     uint64_t start = OTSYS_TIME();
  331.     uint32_t tiles = 0; count = 0;
  332.  
  333.     int32_t marked = -1;
  334.     if(gameState == GAMESTATE_NORMAL)
  335.         setGameState(GAMESTATE_MAINTAIN);
  336.  
  337.     Tile* tile = NULL;
  338.     ItemVector::iterator tit;
  339.     if(g_config.getBool(ConfigManager::STORE_TRASH))
  340.     {
  341.         marked = trash.size();
  342.         Trash::iterator it = trash.begin();
  343.         if(g_config.getBool(ConfigManager::CLEAN_PROTECTED_ZONES))
  344.         {
  345.             for(; it != trash.end(); ++it)
  346.             {
  347.                 if(!(tile = getTile(*it)))
  348.                     continue;
  349.  
  350.                 tile->resetFlag(TILESTATE_TRASHED);
  351.                 if(tile->hasFlag(TILESTATE_HOUSE) || !tile->getItemList())
  352.                     continue;
  353.  
  354.                 ++tiles;
  355.                 tit = tile->getItemList()->begin();
  356.                 while(tile->getItemList() && tit != tile->getItemList()->end())
  357.                 {
  358.                     if((*tit)->isMovable() && !(*tit)->isLoadedFromMap()
  359.                         && !(*tit)->isScriptProtected())
  360.                     {
  361.                         internalRemoveItem(NULL, *tit);
  362.                         if(tile->getItemList())
  363.                             tit = tile->getItemList()->begin();
  364.  
  365.                         ++count;
  366.                     }
  367.                     else
  368.                         ++tit;
  369.                 }
  370.             }
  371.         }
  372.         else
  373.         {
  374.             for(; it != trash.end(); ++it)
  375.             {
  376.                 if(!(tile = getTile(*it)))
  377.                     continue;
  378.  
  379.                 tile->resetFlag(TILESTATE_TRASHED);
  380.                 if(tile->hasFlag(TILESTATE_PROTECTIONZONE) || !tile->getItemList())
  381.                     continue;
  382.  
  383.                 ++tiles;
  384.                 tit = tile->getItemList()->begin();
  385.                 while(tile->getItemList() && tit != tile->getItemList()->end())
  386.                 {
  387.                     if((*tit)->isMovable() && !(*tit)->isLoadedFromMap()
  388.                         && !(*tit)->isScriptProtected())
  389.                     {
  390.                         internalRemoveItem(NULL, *tit);
  391.                         if(tile->getItemList())
  392.                             tit = tile->getItemList()->begin();
  393.  
  394.                         ++count;
  395.                     }
  396.                     else
  397.                         ++tit;
  398.                 }
  399.             }
  400.         }
  401.  
  402.         trash.clear();
  403.     }
  404.     else if(g_config.getBool(ConfigManager::CLEAN_PROTECTED_ZONES))
  405.     {
  406.         for(uint16_t z = 0; z < (uint16_t)MAP_MAX_LAYERS; z++)
  407.         {
  408.             for(uint16_t y = 1; y <= map->mapHeight; y++)
  409.             {
  410.                 for(uint16_t x = 1; x <= map->mapWidth; x++)
  411.                 {
  412.                     if(!(tile = getTile(x, y, z)) || tile->hasFlag(TILESTATE_HOUSE) || !tile->getItemList())
  413.                         continue;
  414.  
  415.                     ++tiles;
  416.                     tit = tile->getItemList()->begin();
  417.                     while(tile->getItemList() && tit != tile->getItemList()->end())
  418.                     {
  419.                         if((*tit)->isMovable() && !(*tit)->isLoadedFromMap()
  420.                             && !(*tit)->isScriptProtected())
  421.                         {
  422.                             internalRemoveItem(NULL, *tit);
  423.                             if(tile->getItemList())
  424.                                 tit = tile->getItemList()->begin();
  425.  
  426.                             ++count;
  427.                         }
  428.                         else
  429.                             ++tit;
  430.                     }
  431.                 }
  432.             }
  433.         }
  434.     }
  435.     else
  436.     {
  437.         for(uint16_t z = 0; z < (uint16_t)MAP_MAX_LAYERS; z++)
  438.         {
  439.             for(uint16_t y = 1; y <= map->mapHeight; y++)
  440.             {
  441.                 for(uint16_t x = 1; x <= map->mapWidth; x++)
  442.                 {
  443.                     if(!(tile = getTile(x, y, z)) || tile->hasFlag(TILESTATE_PROTECTIONZONE) || !tile->getItemList())
  444.                         continue;
  445.  
  446.                     ++tiles;
  447.                     tit = tile->getItemList()->begin();
  448.                     while(tile->getItemList() && tit != tile->getItemList()->end())
  449.                     {
  450.                         if((*tit)->isMovable() && !(*tit)->isLoadedFromMap()
  451.                             && !(*tit)->isScriptProtected())
  452.                         {
  453.                             internalRemoveItem(NULL, *tit);
  454.                             if(tile->getItemList())
  455.                                 tit = tile->getItemList()->begin();
  456.  
  457.                             ++count;
  458.                         }
  459.                         else
  460.                             ++tit;
  461.                     }
  462.                 }
  463.             }
  464.         }
  465.     }
  466.  
  467.     if(gameState == GAMESTATE_MAINTAIN)
  468.         setGameState(GAMESTATE_NORMAL);
  469.  
  470.     std::clog << "> CLEAN: Removed " << count << " item" << (count != 1 ? "s" : "")
  471.         << " from " << tiles << " tile" << (tiles != 1 ? "s" : "");
  472.     if(marked >= 0)
  473.         std::clog << " (" << marked << " were marked)";
  474.  
  475.     std::clog << " in " << (OTSYS_TIME() - start) / (1000.) << " seconds." << std::endl;
  476. }
  477.  
  478. void Game::cleanMap()
  479. {
  480.     uint32_t dummy;
  481.     cleanMapEx(dummy);
  482. }
  483.  
  484. void Game::proceduralRefresh(RefreshTiles::iterator* it/* = NULL*/)
  485. {
  486.     if(!it)
  487.         it = new RefreshTiles::iterator(refreshTiles.begin());
  488.  
  489.     // Refresh 250 tiles each cycle
  490.     refreshMap(it, 250);
  491.     if((*it) != refreshTiles.end())
  492.     {
  493.         delete it;
  494.         return;
  495.     }
  496.  
  497.     // Refresh some items every 100 ms until all tiles has been checked
  498.     // For 100k tiles, this would take 100000/2500 = 40s = half a minute
  499.     Scheduler::getInstance().addEvent(createSchedulerTask(SCHEDULER_MINTICKS,
  500.         boost::bind(&Game::proceduralRefresh, this, it)));
  501. }
  502.  
  503. void Game::refreshMap(RefreshTiles::iterator* it/* = NULL*/, uint32_t limit/* = 0*/)
  504. {
  505.     RefreshTiles::iterator end = refreshTiles.end();
  506.     if(!it)
  507.     {
  508.         RefreshTiles::iterator begin = refreshTiles.begin();
  509.         it = &begin;
  510.     }
  511.  
  512.     Tile* tile = NULL;
  513.     TileItemVector* items = NULL;
  514.  
  515.     Item* item = NULL;
  516.     for(uint32_t cleaned = 0, downItemsSize = 0; (*it) != end &&
  517.         (limit ? (cleaned < limit) : true); ++(*it), ++cleaned)
  518.     {
  519.         if(!(tile = (*it)->first))
  520.             continue;
  521.  
  522.         if((items = tile->getItemList()))
  523.         {
  524.             downItemsSize = tile->getDownItemCount();
  525.             for(uint32_t i = downItemsSize - 1; i; --i)
  526.             {
  527.                 if((item = items->at(i)))
  528.                 {
  529.                     #ifndef __DEBUG__
  530.                     internalRemoveItem(NULL, item);
  531.                     #else
  532.                     if(internalRemoveItem(NULL, item) != RET_NOERROR)
  533.                     {
  534.                         std::clog << "> WARNING: Could not refresh item: " << item->getID();
  535.                         std::clog << " at position: " << tile->getPosition() << std::endl;
  536.                     }
  537.                     #endif
  538.                 }
  539.             }
  540.         }
  541.  
  542.         cleanup();
  543.         TileItemVector list = (*it)->second.list;
  544.         for(ItemVector::reverse_iterator it = list.rbegin(); it != list.rend(); ++it)
  545.         {
  546.             Item* item = (*it)->clone();
  547.             if(internalAddItem(NULL, tile, item, INDEX_WHEREEVER, FLAG_NOLIMIT) == RET_NOERROR)
  548.             {
  549.                 if(item->getUniqueId())
  550.                     ScriptEnviroment::addUniqueThing(item);
  551.  
  552.                 startDecay(item);
  553.             }
  554.             else
  555.             {
  556.                 std::clog << "> WARNING: Could not refresh item: " << item->getID()
  557.                     << " at position: " << tile->getPosition() << std::endl;
  558.                 delete item;
  559.             }
  560.         }
  561.     }
  562. }
  563.  
  564. bool Game::isSwimmingPool(Item* item, const Tile* tile, bool checkProtection) const
  565. {
  566.     if(!tile)
  567.         return false;
  568.  
  569.     TrashHolder* trashHolder = NULL;
  570.     if(!item)
  571.         trashHolder = tile->getTrashHolder();
  572.     else
  573.         trashHolder = item->getTrashHolder();
  574.  
  575.     return trashHolder && trashHolder->getEffect() == MAGIC_EFFECT_LOSE_ENERGY && (!checkProtection
  576.         || tile->getZone() == ZONE_PROTECTION || tile->getZone() == ZONE_OPTIONAL);
  577. }
  578.  
  579. Cylinder* Game::internalGetCylinder(Player* player, const Position& pos)
  580. {
  581.     if(pos.x != 0xFFFF)
  582.         return getTile(pos);
  583.  
  584.     //container
  585.     if(pos.y & 0x40)
  586.         return player->getContainer((uint8_t)(pos.y & 0x0F));
  587.  
  588.     return player;
  589. }
  590.  
  591. Thing* Game::internalGetThing(Player* player, const Position& pos, int32_t index,
  592.     uint32_t spriteId/* = 0*/, stackposType_t type/* = STACKPOS_NORMAL*/)
  593. {
  594.     if(pos.x != 0xFFFF)
  595.     {
  596.         Tile* tile = getTile(pos);
  597.         if(!tile)
  598.             return NULL;
  599.  
  600.         if(type == STACKPOS_LOOK)
  601.             return tile->getTopVisibleThing(player);
  602.  
  603.         Thing* thing = NULL;
  604.         switch(type)
  605.         {
  606.             case STACKPOS_MOVE:
  607.             {
  608.                 Item* item = tile->getTopDownItem();
  609.                 if(item && item->isMovable())
  610.                     thing = item;
  611.                 else
  612.                     thing = tile->getTopVisibleCreature(player);
  613.  
  614.                 break;
  615.             }
  616.  
  617.             case STACKPOS_USE:
  618.             {
  619.                 thing = tile->getTopDownItem();
  620.                 break;
  621.             }
  622.  
  623.             case STACKPOS_USEITEM:
  624.             {
  625.                 thing = tile->getTopDownItem();
  626.                 Item* item = tile->getItemByTopOrder(2);
  627.                 if(item && g_actions->hasAction(item))
  628.                 {
  629.                     const ItemType& it = Item::items[item->getID()];
  630.                     if(!thing || (!it.hasHeight && !it.allowPickupable))
  631.                         thing = item;
  632.                 }
  633.  
  634.                 if(!thing)
  635.                     thing = tile->getTopTopItem();
  636.  
  637.                 if(!thing)
  638.                     thing = tile->ground;
  639.  
  640.                 break;
  641.             }
  642.  
  643.             default:
  644.                 thing = tile->__getThing(index);
  645.                 break;
  646.         }
  647.  
  648.         if(player && thing && thing->getItem())
  649.         {
  650.             if(tile->hasProperty(ISVERTICAL))
  651.             {
  652.                 if(player->getPosition().x + 1 == tile->getPosition().x)
  653.                     thing = NULL;
  654.             }
  655.             else if(tile->hasProperty(ISHORIZONTAL) && player->getPosition().y + 1 == tile->getPosition().y)
  656.                 thing = NULL;
  657.         }
  658.  
  659.         return thing;
  660.     }
  661.     else if(pos.y & 0x40)
  662.     {
  663.         uint8_t fromCid = pos.y & 0x0F, slot = pos.z;
  664.         if(Container* parentcontainer = player->getContainer(fromCid))
  665.             return parentcontainer->getItem(slot);
  666.     }
  667.     else if(!pos.y && !pos.z)
  668.     {
  669.         const ItemType& it = Item::items.getItemIdByClientId(spriteId);
  670.         if(!it.id)
  671.             return NULL;
  672.  
  673.         int32_t subType = -1;
  674.         if(it.isFluidContainer() && index < int32_t(sizeof(reverseFluidMap) / sizeof(int8_t)))
  675.             subType = reverseFluidMap[index];
  676.  
  677.         return findItemOfType(player, it.id, true, subType);
  678.     }
  679.  
  680.     return player->getInventoryItem((slots_t)static_cast<uint8_t>(pos.y));
  681. }
  682.  
  683. void Game::internalGetPosition(Item* item, Position& pos, int16_t& stackpos)
  684. {
  685.     if(!item)
  686.         return;
  687.  
  688.     pos.x = pos.y = pos.z = stackpos = 0;
  689.     if(Cylinder* topParent = item->getTopParent())
  690.     {
  691.         if(Player* player = dynamic_cast<Player*>(topParent))
  692.         {
  693.             pos.x = 0xFFFF;
  694.  
  695.             Container* container = dynamic_cast<Container*>(item->getParent());
  696.             if(container)
  697.             {
  698.                 pos.y = ((uint16_t) ((uint16_t)0x40) | ((uint16_t)player->getContainerID(container)) );
  699.                 pos.z = container->__getIndexOfThing(item);
  700.                 stackpos = pos.z;
  701.             }
  702.             else
  703.             {
  704.                 pos.y = player->__getIndexOfThing(item);
  705.                 stackpos = pos.y;
  706.             }
  707.         }
  708.         else if(Tile* tile = topParent->getTile())
  709.         {
  710.             pos = tile->getPosition();
  711.             stackpos = tile->__getIndexOfThing(item);
  712.         }
  713.     }
  714. }
  715.  
  716. Creature* Game::getCreatureByID(uint32_t id)
  717. {
  718.     if(!id)
  719.         return NULL;
  720.  
  721.     AutoList<Creature>::iterator it = autoList.find(id);
  722.     if(it != autoList.end() && !it->second->isRemoved())
  723.         return it->second;
  724.  
  725.     return NULL; //just in case the player doesnt exist
  726. }
  727.  
  728. Player* Game::getPlayerByID(uint32_t id)
  729. {
  730.     if(!id)
  731.         return NULL;
  732.  
  733.     AutoList<Player>::iterator it = Player::autoList.find(id);
  734.     if(it != Player::autoList.end() && !it->second->isRemoved())
  735.         return it->second;
  736.  
  737.     return NULL; //just in case the player doesnt exist
  738. }
  739.  
  740. Player* Game::getPlayerByGUID(const uint32_t& guid)
  741. {
  742.     if(!guid)
  743.         return NULL;
  744.  
  745.     for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
  746.     {
  747.         Player* player = (*it).second;
  748.         if(!player->isRemoved())
  749.         {
  750.             if(guid == player->getGUID())
  751.                 return player;
  752.         }
  753.     }
  754.     return NULL;
  755. }
  756.  
  757. Creature* Game::getCreatureByName(std::string s)
  758. {
  759.     if(s.empty())
  760.         return NULL;
  761.  
  762.     toLowerCaseString(s);
  763.     for(AutoList<Creature>::iterator it = autoList.begin(); it != autoList.end(); ++it)
  764.     {
  765.         if(!it->second->isRemoved() && asLowerCaseString(it->second->getName()) == s)
  766.             return it->second;
  767.     }
  768.  
  769.     return NULL; //just in case the creature doesnt exist
  770. }
  771.  
  772. Player* Game::getPlayerByName(std::string s)
  773. {
  774.     if(s.empty())
  775.         return NULL;
  776.  
  777.     toLowerCaseString(s);
  778.     for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
  779.     {
  780.         if(!it->second->isRemoved() && asLowerCaseString(it->second->getName()) == s)
  781.             return it->second;
  782.     }
  783.  
  784.     return NULL;
  785. }
  786.  
  787. Player* Game::getPlayerByNameEx(const std::string& s)
  788. {
  789.     Player* player = getPlayerByName(s);
  790.     if(player)
  791.         return player;
  792.  
  793.     std::string name = s;
  794.     if(!IOLoginData::getInstance()->playerExists(name))
  795.         return NULL;
  796.  
  797.     player = new Player(name, NULL);
  798.     if(IOLoginData::getInstance()->loadPlayer(player, name))
  799.         return player;
  800.  
  801. #ifdef __DEBUG__
  802.     std::clog << "[Failure - Game::getPlayerByNameEx] Cannot load player: " << name << std::endl;
  803. #endif
  804.     delete player;
  805.     return NULL;
  806. }
  807.  
  808. Player* Game::getPlayerByGuid(uint32_t guid)
  809. {
  810.     if(!guid)
  811.         return NULL;
  812.  
  813.     for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
  814.     {
  815.         if(!it->second->isRemoved() && it->second->getGUID() == guid)
  816.             return it->second;
  817.     }
  818.  
  819.     return NULL;
  820. }
  821.  
  822. Player* Game::getPlayerByGuidEx(uint32_t guid)
  823. {
  824.     Player* player = getPlayerByGuid(guid);
  825.     if(player)
  826.         return player;
  827.  
  828.     std::string name;
  829.     if(!IOLoginData::getInstance()->getNameByGuid(guid, name))
  830.         return NULL;
  831.  
  832.     player = new Player(name, NULL);
  833.     if(IOLoginData::getInstance()->loadPlayer(player, name))
  834.         return player;
  835.  
  836. #ifdef __DEBUG__
  837.     std::clog << "[Failure - Game::getPlayerByGuidEx] Cannot load player: " << name << std::endl;
  838. #endif
  839.     delete player;
  840.     return NULL;
  841. }
  842.  
  843. ReturnValue Game::getPlayerByNameWildcard(std::string s, Player*& player)
  844. {
  845.     player = NULL;
  846.     if(s.empty())
  847.         return RET_PLAYERWITHTHISNAMEISNOTONLINE;
  848.  
  849.     char tmp = *s.rbegin();
  850.     if(tmp != '~' && tmp != '*')
  851.     {
  852.         player = getPlayerByName(s);
  853.         if(!player)
  854.             return RET_PLAYERWITHTHISNAMEISNOTONLINE;
  855.  
  856.         return RET_NOERROR;
  857.     }
  858.  
  859.     Player* last = NULL;
  860.     s = s.substr(0, s.length() - 1);
  861.  
  862.     toLowerCaseString(s);
  863.     for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
  864.     {
  865.         if(it->second->isRemoved())
  866.             continue;
  867.  
  868.         std::string name = asLowerCaseString(it->second->getName());
  869.         if(name.substr(0, s.length()) != s)
  870.             continue;
  871.  
  872.         if(last)
  873.             return RET_NAMEISTOOAMBIGUOUS;
  874.  
  875.         last = it->second;
  876.     }
  877.  
  878.     if(!last)
  879.         return RET_PLAYERWITHTHISNAMEISNOTONLINE;
  880.  
  881.     player = last;
  882.     return RET_NOERROR;
  883. }
  884.  
  885. Player* Game::getPlayerByAccount(uint32_t acc)
  886. {
  887.     for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
  888.     {
  889.         if(!it->second->isRemoved() && it->second->getAccount() == acc)
  890.             return it->second;
  891.     }
  892.  
  893.     return NULL;
  894. }
  895.  
  896. PlayerVector Game::getPlayersByName(std::string s)
  897. {
  898.     toLowerCaseString(s);
  899.     PlayerVector players;
  900.     for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
  901.     {
  902.         if(!it->second->isRemoved() && asLowerCaseString(it->second->getName()) == s)
  903.             players.push_back(it->second);
  904.     }
  905.  
  906.     return players;
  907. }
  908.  
  909. PlayerVector Game::getPlayersByAccount(uint32_t acc)
  910. {
  911.     PlayerVector players;
  912.     for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
  913.     {
  914.         if(!it->second->isRemoved() && it->second->getAccount() == acc)
  915.             players.push_back(it->second);
  916.     }
  917.  
  918.     return players;
  919. }
  920.  
  921. PlayerVector Game::getPlayersByIP(uint32_t ip, uint32_t mask)
  922. {
  923.     PlayerVector players;
  924.     for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
  925.     {
  926.         if(!it->second->isRemoved() && (it->second->getIP() & mask) == (ip & mask))
  927.             players.push_back(it->second);
  928.     }
  929.  
  930.     return players;
  931. }
  932.  
  933. bool Game::internalPlaceCreature(Creature* creature, const Position& pos, bool extendedPos /*= false*/, bool forced /*= false*/)
  934. {
  935.     if(creature->getParent())
  936.         return false;
  937.  
  938.     if(!map->placeCreature(pos, creature, extendedPos, forced))
  939.         return false;
  940.  
  941.     creature->addRef();
  942.     creature->setID();
  943.  
  944.     autoList[creature->getID()] = creature;
  945.     creature->addList();
  946.     return true;
  947. }
  948.  
  949. bool Game::placeCreature(Creature* creature, const Position& pos, bool extendedPos /*= false*/, bool forced /*= false*/)
  950. {
  951.     if(!internalPlaceCreature(creature, pos, extendedPos, forced))
  952.         return false;
  953.  
  954.     Player* tmpPlayer = NULL;
  955.     if((tmpPlayer = creature->getPlayer()) && !tmpPlayer->storedConditionList.empty())
  956.     {
  957.         for(ConditionList::iterator it = tmpPlayer->storedConditionList.begin(); it != tmpPlayer->storedConditionList.end(); ++it)
  958.         {
  959.             if((*it)->getType() == CONDITION_MUTED && (*it)->getTicks() != -1 &&
  960.                 (*it)->getTicks() - ((time(NULL) - tmpPlayer->getLastLogout()) * 1000) <= 0)
  961.                 continue;
  962.  
  963.             tmpPlayer->addCondition(*it);
  964.         }
  965.  
  966.         tmpPlayer->storedConditionList.clear();
  967.     }
  968.  
  969.     SpectatorVec::iterator it;
  970.     SpectatorVec list;
  971.  
  972.     getSpectators(list, creature->getPosition(), true, false);
  973.     for(it = list.begin(); it != list.end(); ++it)
  974.     {
  975.         if((tmpPlayer = (*it)->getPlayer()))
  976.             tmpPlayer->sendCreatureAppear(creature);
  977.     }
  978.  
  979.     for(it = list.begin(); it != list.end(); ++it)
  980.         (*it)->onCreatureAppear(creature);
  981.  
  982.     creature->setLastPosition(pos);
  983.     creature->getParent()->postAddNotification(NULL, creature, NULL, creature->getParent()->__getIndexOfThing(creature));
  984.  
  985.     addCreatureCheck(creature);
  986.     creature->onPlacedCreature();
  987.     return true;
  988. }
  989.  
  990. ReturnValue Game::placeSummon(Creature* creature, const std::string& name)
  991. {
  992.     Monster* monster = Monster::createMonster(name);
  993.     if(!monster)
  994.         return RET_NOTPOSSIBLE;
  995.  
  996.     // Place the monster
  997.     creature->addSummon(monster);
  998.     if(placeCreature(monster, creature->getPosition(), true))
  999.     {
  1000.         addMagicEffect(monster->getPosition(), MAGIC_EFFECT_TELEPORT);
  1001.         return RET_NOERROR;
  1002.     }
  1003.  
  1004.     creature->removeSummon(monster);
  1005.     return RET_NOTENOUGHROOM;
  1006. }
  1007.  
  1008. bool Game::removeCreature(Creature* creature, bool isLogout /*= true*/)
  1009. {
  1010.     if(creature->isRemoved())
  1011.         return false;
  1012.  
  1013.     Tile* tile = creature->getTile();
  1014.     SpectatorVec list;
  1015.     getSpectators(list, tile->getPosition(), true, false);
  1016.  
  1017.     SpectatorVec::iterator it;
  1018.     for(it = list.begin(); it != list.end(); ++it)
  1019.         (*it)->onCreatureDisappear(creature, isLogout);
  1020.  
  1021.     if(tile != creature->getTile())
  1022.     {
  1023.         list.clear();
  1024.         tile = creature->getTile();
  1025.         getSpectators(list, tile->getPosition(), true, false);
  1026.     }
  1027.  
  1028.     Player* player = NULL;
  1029.     std::vector<uint32_t> oldStackPosVector;
  1030.     for(it = list.begin(); it != list.end(); ++it)
  1031.     {
  1032.         if((player = (*it)->getPlayer()) && player->canSeeCreature(creature))
  1033.             oldStackPosVector.push_back(tile->getClientIndexOfThing(player, creature));
  1034.     }
  1035.  
  1036.     int32_t oldIndex = tile->__getIndexOfThing(creature);
  1037.     if(!map->removeCreature(creature))
  1038.         return false;
  1039.  
  1040.     //send to client
  1041.     uint32_t i = 0;
  1042.     for(it = list.begin(); it != list.end(); ++it)
  1043.     {
  1044.         if(creature != (*it))
  1045.             (*it)->updateTileCache(tile);
  1046.  
  1047.         if(!(player = (*it)->getPlayer()) || !player->canSeeCreature(creature))
  1048.             continue;
  1049.  
  1050.         player->setWalkthrough(creature, false);
  1051.         player->sendCreatureDisappear(creature, oldStackPosVector[i]);
  1052.         ++i;
  1053.     }
  1054.  
  1055.     creature->getParent()->postRemoveNotification(NULL, creature, NULL, oldIndex, true);
  1056.     creature->onRemovedCreature();
  1057.  
  1058.     autoList.erase(creature->getID());
  1059.     freeThing(creature);
  1060.  
  1061.     removeCreatureCheck(creature);
  1062.     for(std::list<Creature*>::iterator it = creature->summons.begin(); it != creature->summons.end(); ++it)
  1063.         removeCreature(*it);
  1064.  
  1065.     return true;
  1066. }
  1067.  
  1068. bool Game::playerMoveThing(uint32_t playerId, const Position& fromPos,
  1069.     uint16_t spriteId, int16_t fromStackpos, const Position& toPos, uint8_t count)
  1070. {
  1071.     Player* player = getPlayerByID(playerId);
  1072.     if(!player || player->isRemoved())
  1073.         return false;
  1074.  
  1075.     if(player->getNoMove())
  1076.     {
  1077.         player->sendCancelMessage(RET_NOTPOSSIBLE);
  1078.         return false;
  1079.     }
  1080.  
  1081.     uint8_t fromIndex = 0;
  1082.     if(fromPos.x == 0xFFFF)
  1083.     {
  1084.         if(fromPos.y & 0x40)
  1085.             fromIndex = static_cast<uint8_t>(fromPos.z);
  1086.         else
  1087.             fromIndex = static_cast<uint8_t>(fromPos.y);
  1088.     }
  1089.     else
  1090.         fromIndex = fromStackpos;
  1091.  
  1092.     Thing* thing = internalGetThing(player, fromPos, fromIndex, spriteId, STACKPOS_MOVE);
  1093.     Cylinder* toCylinder = internalGetCylinder(player, toPos);
  1094.     if(!thing || !toCylinder)
  1095.     {
  1096.         player->sendCancelMessage(RET_NOTPOSSIBLE);
  1097.         return false;
  1098.     }
  1099.  
  1100.     if(Creature* movingCreature = thing->getCreature())
  1101.         playerMoveCreature(playerId, movingCreature->getID(), movingCreature->getPosition(), toCylinder->getPosition(), true);
  1102.     else if(thing->getItem())
  1103.         playerMoveItem(playerId, fromPos, spriteId, fromStackpos, toPos, count);
  1104.  
  1105.     return true;
  1106. }
  1107.  
  1108. bool Game::playerMoveCreature(uint32_t playerId, uint32_t movingCreatureId,
  1109.     const Position& movingCreaturePos, const Position& toPos, bool delay)
  1110. {
  1111.     Player* player = getPlayerByID(playerId);
  1112.     if(!player || player->isRemoved() || player->hasFlag(PlayerFlag_CannotMoveCreatures))
  1113.         return false;
  1114.  
  1115.     if(!player->canDoAction() && !g_config.getBool(ConfigManager::ALLOW_INDEPENDENT_PUSH))
  1116.     {
  1117.         SchedulerTask* task = createSchedulerTask(1500,
  1118.             boost::bind(&Game::playerMoveCreature, this, playerId, movingCreatureId, movingCreaturePos, toPos, false));
  1119.         player->setNextActionTask(task);
  1120.         return false;
  1121.     }
  1122.  
  1123.     Creature* movingCreature = getCreatureByID(movingCreatureId);
  1124.     if(!movingCreature || movingCreature->isRemoved() || !player->canSeeCreature(movingCreature))
  1125.         return false;
  1126.  
  1127.     player->setNextActionTask(NULL);
  1128.     if(!Position::areInRange<1,1,0>(movingCreaturePos, player->getPosition()) && !player->hasCustomFlag(PlayerCustomFlag_CanMoveFromFar))
  1129.     {
  1130.         //need to walk to the creature first before moving it
  1131.         std::list<Direction> listDir;
  1132.         if(getPathToEx(player, movingCreaturePos, listDir, 0, 1, true, true))
  1133.         {
  1134.             Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
  1135.                 this, player->getID(), listDir)));
  1136.             SchedulerTask* task = createSchedulerTask(100,
  1137.                 boost::bind(&Game::playerMoveCreature, this, playerId, movingCreatureId, movingCreaturePos, toPos, false));
  1138.  
  1139.             player->setNextWalkActionTask(task);
  1140.             return true;
  1141.         }
  1142.  
  1143.         player->sendCancelMessage(RET_THEREISNOWAY);
  1144.         return false;
  1145.     }
  1146.     else if(delay)
  1147.     {
  1148.         uint32_t delayTime = g_config.getNumber(ConfigManager::PUSH_CREATURE_DELAY);
  1149.         if(delayTime > 0)
  1150.         {
  1151.             SchedulerTask* task = createSchedulerTask(delayTime,
  1152.                 boost::bind(&Game::playerMoveCreature, this, playerId, movingCreatureId, movingCreaturePos, toPos, false));
  1153.             player->setNextActionTask(task);
  1154.             return true;
  1155.         }
  1156.     }
  1157.  
  1158.     Tile* toTile = map->getTile(toPos);
  1159.     if(!toTile)
  1160.     {
  1161.         player->sendCancelMessage(RET_NOTPOSSIBLE);
  1162.         return false;
  1163.     }
  1164.  
  1165.     if(!player->hasFlag(PlayerFlag_CanPushAllCreatures))
  1166.     {
  1167.         if(!movingCreature->isPushable())
  1168.         {
  1169.             player->sendCancelMessage(RET_NOTMOVABLE);
  1170.             return false;
  1171.         }
  1172.  
  1173.         if(movingCreature->getNoMove())
  1174.         {
  1175.             player->sendCancelMessage(RET_NOTPOSSIBLE);
  1176.             return false;
  1177.         }
  1178.  
  1179.         if(toTile->hasProperty(BLOCKPATH))
  1180.         {
  1181.             player->sendCancelMessage(RET_NOTENOUGHROOM);
  1182.             return false;
  1183.         }
  1184.     }
  1185.  
  1186.     //check throw distance
  1187.     const Position& pos = movingCreature->getPosition();
  1188.     if(!player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere) && ((std::abs(pos.x - toPos.x) > movingCreature->getThrowRange()) ||
  1189.         (std::abs(pos.y - toPos.y) > movingCreature->getThrowRange()) || (std::abs(pos.z - toPos.z) * 4 > movingCreature->getThrowRange())))
  1190.     {
  1191.         player->sendCancelMessage(RET_DESTINATIONOUTOFREACH);
  1192.         return false;
  1193.     }
  1194.  
  1195.     if(player != movingCreature)
  1196.     {
  1197.         if(!player->hasFlag(PlayerFlag_IgnoreProtectionZone) && (movingCreature->getZone() == ZONE_PROTECTION
  1198.             || movingCreature->getZone() == ZONE_OPTIONAL) && !toTile->hasFlag(TILESTATE_OPTIONALZONE)
  1199.             && !toTile->hasFlag(TILESTATE_PROTECTIONZONE))
  1200.         {
  1201.             player->sendCancelMessage(RET_ACTIONNOTPERMITTEDINANOPVPZONE);
  1202.             return false;
  1203.         }
  1204.  
  1205.         if(!player->hasFlag(PlayerFlag_CanPushAllCreatures))
  1206.         {
  1207.             if(toTile->getCreatureCount() && !Item::items[
  1208.                 movingCreature->getTile()->ground->getID()].walkStack)
  1209.             {
  1210.                 player->sendCancelMessage(RET_NOTENOUGHROOM);
  1211.                 return false;
  1212.             }
  1213.  
  1214.             if(MagicField* field = toTile->getFieldItem())
  1215.             {
  1216.                 if(field->isUnstepable() || field->isBlocking(movingCreature)
  1217.                     || !movingCreature->isImmune(field->getCombatType()))
  1218.                 {
  1219.                     player->sendCancelMessage(RET_NOTPOSSIBLE);
  1220.                     return false;
  1221.                 }
  1222.             }
  1223.  
  1224.             if(Player* movingPlayer = movingCreature->getPlayer())
  1225.             {
  1226.                 if((player->isProtected() && !movingPlayer->isProtected()) || (getWorldType(player) == WORLDTYPE_OPTIONAL
  1227.                     && getWorldType(movingPlayer) != WORLDTYPE_OPTIONAL && !player->isEnemy(movingPlayer, true)
  1228.                     && !player->isAlly(movingPlayer)))
  1229.                 {
  1230.                     player->sendCancelMessage(RET_NOTMOVABLE);
  1231.                     return false;
  1232.                 }
  1233.             }
  1234.         }
  1235.     }
  1236.  
  1237.     bool deny = false;
  1238.     CreatureEventList pushEvents = player->getCreatureEvents(CREATURE_EVENT_PUSH);
  1239.     for(CreatureEventList::iterator it = pushEvents.begin(); it != pushEvents.end(); ++it)
  1240.     {
  1241.         if(!(*it)->executePush(player, movingCreature, toTile) && !deny)
  1242.             deny = true;
  1243.     }
  1244.  
  1245.     if(deny)
  1246.         return false;
  1247.  
  1248.     ReturnValue ret = internalMoveCreature(player, movingCreature, movingCreature->getTile(), toTile);
  1249.     if(ret != RET_NOERROR)
  1250.     {
  1251.         if(!player->hasCustomFlag(PlayerCustomFlag_CanMoveAnywhere))
  1252.         {
  1253.             player->sendCancelMessage(ret);
  1254.             return false;
  1255.         }
  1256.  
  1257.         if(!toTile->ground)
  1258.         {
  1259.             player->sendCancelMessage(RET_NOTPOSSIBLE);
  1260.             return false;
  1261.         }
  1262.  
  1263.         internalTeleport(movingCreature, toTile->getPosition(), false);
  1264.     }
  1265.     else if(Player* movingPlayer = movingCreature->getPlayer())
  1266.     {
  1267.         uint64_t delay = OTSYS_TIME() + movingPlayer->getStepDuration();
  1268.         if(delay > movingPlayer->getNextActionTime(false))
  1269.             movingPlayer->setNextAction(delay);
  1270.     }
  1271.  
  1272.     return true;
  1273. }
  1274.  
  1275. ReturnValue Game::internalMoveCreature(Creature* creature, Direction direction, uint32_t flags/* = 0*/)
  1276. {
  1277.     const Position& currentPos = creature->getPosition();
  1278.     Cylinder* fromTile = creature->getTile();
  1279.     Cylinder* toTile = NULL;
  1280.  
  1281.     Position destPos = getNextPosition(direction, currentPos);
  1282.     if(direction < SOUTHWEST && creature->getPlayer())
  1283.     {
  1284.         Tile* tmpTile = NULL;
  1285.         if(currentPos.z != 8 && creature->getTile()->hasHeight(3)) //try go up
  1286.         {
  1287.             if((!(tmpTile = map->getTile(Position(currentPos.x, currentPos.y, currentPos.z - 1)))
  1288.                 || (!tmpTile->ground && !tmpTile->hasProperty(BLOCKSOLID))) &&
  1289.                 (tmpTile = map->getTile(Position(destPos.x, destPos.y, destPos.z - 1)))
  1290.                 && tmpTile->ground && !tmpTile->hasProperty(BLOCKSOLID) && !tmpTile->hasProperty(FLOORCHANGEDOWN))
  1291.             {
  1292.                 flags = flags | FLAG_IGNOREBLOCKITEM | FLAG_IGNOREBLOCKCREATURE;
  1293.                 destPos.z--;
  1294.             }
  1295.         }
  1296.         else if(currentPos.z != 7 && (!(tmpTile = map->getTile(destPos)) || (!tmpTile->ground &&
  1297.             !tmpTile->hasProperty(BLOCKSOLID))) && (tmpTile = map->getTile(Position(
  1298.             destPos.x, destPos.y, destPos.z + 1))) && tmpTile->hasHeight(3)) //try go down
  1299.         {
  1300.             flags = flags | FLAG_IGNOREBLOCKITEM | FLAG_IGNOREBLOCKCREATURE;
  1301.             destPos.z++;
  1302.         }
  1303.     }
  1304.  
  1305.     ReturnValue ret = RET_NOTPOSSIBLE;
  1306.     if((toTile = map->getTile(destPos)))
  1307.         ret = internalMoveCreature(NULL, creature, fromTile, toTile, flags);
  1308.  
  1309.     if(ret == RET_NOERROR)
  1310.         return RET_NOERROR;
  1311.  
  1312.     Player* player = creature->getPlayer();
  1313.     if(!player)
  1314.         return ret;
  1315.  
  1316.     player->sendCancelMessage(ret);
  1317.     player->sendCancelWalk();
  1318.     return ret;
  1319. }
  1320.  
  1321. ReturnValue Game::internalMoveCreature(Creature* actor, Creature* creature, Cylinder* fromCylinder,
  1322.     Cylinder* toCylinder, uint32_t flags/* = 0*/, bool forceTeleport/* = false*/)
  1323. {
  1324.     //check if we can move the creature to the destination
  1325.     ReturnValue ret = toCylinder->__queryAdd(0, creature, 1, flags, actor);
  1326.     if(ret != RET_NOERROR)
  1327.         return ret;
  1328.  
  1329.     fromCylinder->getTile()->moveCreature(actor, creature, toCylinder, forceTeleport);
  1330.     if(creature->getParent() != toCylinder)
  1331.         return RET_NOERROR;
  1332.  
  1333.     Item* toItem = NULL;
  1334.     Cylinder* subCylinder = NULL;
  1335.  
  1336.     int32_t n = 0, tmp = 0;
  1337.     while((subCylinder = toCylinder->__queryDestination(tmp, creature, &toItem, flags)) != toCylinder)
  1338.     {
  1339.         internalCreatureTurn(creature, getDirectionTo(toCylinder->getTile()->getPosition(), subCylinder->getTile()->getPosition(), false));
  1340.         toCylinder->getTile()->moveCreature(actor, creature, subCylinder);
  1341.         if(creature->getParent() != subCylinder) //could happen if a script move the creature
  1342.             break;
  1343.  
  1344.         toCylinder = subCylinder;
  1345.         flags = 0;
  1346.         if(++n >= MAP_MAX_LAYERS) //to prevent infinite loop
  1347.             break;
  1348.     }
  1349.  
  1350.     return RET_NOERROR;
  1351. }
  1352.  
  1353. bool Game::playerMoveItem(uint32_t playerId, const Position& fromPos,
  1354.     uint16_t spriteId, int16_t fromStackpos, const Position& toPos, uint8_t count)
  1355. {
  1356.     Player* player = getPlayerByID(playerId);
  1357.     if(!player || player->isRemoved() || player->hasFlag(PlayerFlag_CannotMoveItems))
  1358.         return false;
  1359.  
  1360.     if(!player->canDoAction())
  1361.     {
  1362.         SchedulerTask* task = createSchedulerTask(player->getNextActionTime(),
  1363.             boost::bind(&Game::playerMoveItem, this, playerId, fromPos, spriteId, fromStackpos, toPos, count));
  1364.         player->setNextActionTask(task);
  1365.         return false;
  1366.     }
  1367.  
  1368.     player->setNextActionTask(NULL);
  1369.     Cylinder* fromCylinder = internalGetCylinder(player, fromPos);
  1370.  
  1371.     uint8_t fromIndex = 0;
  1372.     if(fromPos.x == 0xFFFF)
  1373.     {
  1374.         if(fromPos.y & 0x40)
  1375.             fromIndex = static_cast<uint8_t>(fromPos.z);
  1376.         else
  1377.             fromIndex = static_cast<uint8_t>(fromPos.y);
  1378.     }
  1379.     else
  1380.         fromIndex = fromStackpos;
  1381.  
  1382.     Thing* thing = internalGetThing(player, fromPos, fromIndex, spriteId, STACKPOS_MOVE);
  1383.     if(!thing || !thing->getItem())
  1384.     {
  1385.         player->sendCancelMessage(RET_NOTPOSSIBLE);
  1386.         return false;
  1387.     }
  1388.  
  1389.     Item* item = thing->getItem();
  1390.     Cylinder* toCylinder = internalGetCylinder(player, toPos);
  1391.  
  1392.     uint8_t toIndex = 0;
  1393.     if(toPos.x == 0xFFFF)
  1394.     {
  1395.         if(toPos.y & 0x40)
  1396.             toIndex = static_cast<uint8_t>(toPos.z);
  1397.         else
  1398.             toIndex = static_cast<uint8_t>(toPos.y);
  1399.     }
  1400.  
  1401.     if(!fromCylinder || !toCylinder || !item || item->getClientID() != spriteId)
  1402.     {
  1403.         player->sendCancelMessage(RET_NOTPOSSIBLE);
  1404.         return false;
  1405.     }
  1406.  
  1407.     if(!player->hasCustomFlag(PlayerCustomFlag_CanPushAllItems) && (!item->isPushable() || (item->isLoadedFromMap() &&
  1408.         (item->getUniqueId() || (item->getActionId() && item->getContainer())))))
  1409.     {
  1410.         player->sendCancelMessage(RET_NOTMOVABLE);
  1411.         return false;
  1412.     }
  1413.  
  1414.     const Position &mapToPos = toCylinder->getTile()->getPosition(), &playerPos = player->getPosition(),
  1415.         &mapFromPos = fromCylinder->getTile()->getPosition();
  1416.     if(playerPos.z > mapFromPos.z && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
  1417.     {
  1418.         player->sendCancelMessage(RET_FIRSTGOUPSTAIRS);
  1419.         return false;
  1420.     }
  1421.  
  1422.     if(playerPos.z < mapFromPos.z && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
  1423.     {
  1424.         player->sendCancelMessage(RET_FIRSTGODOWNSTAIRS);
  1425.         return false;
  1426.     }
  1427.  
  1428.     if(!Position::areInRange<1,1,0>(playerPos, mapFromPos) && !player->hasCustomFlag(PlayerCustomFlag_CanMoveFromFar))
  1429.     {
  1430.         //need to walk to the item first before using it
  1431.         std::list<Direction> listDir;
  1432.         if(getPathToEx(player, item->getPosition(), listDir, 0, 1, true, true))
  1433.         {
  1434.             Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
  1435.                 this, player->getID(), listDir)));
  1436.             SchedulerTask* task = createSchedulerTask(std::max((int64_t)SCHEDULER_MINTICKS, player->getStepDuration()),
  1437.                 boost::bind(&Game::playerMoveItem, this, playerId, fromPos, spriteId, fromStackpos, toPos, count));
  1438.  
  1439.             player->setNextWalkActionTask(task);
  1440.             return true;
  1441.         }
  1442.  
  1443.         player->sendCancelMessage(RET_THEREISNOWAY);
  1444.         return false;
  1445.     }
  1446.  
  1447.     //hangable item specific code
  1448.     if(item->isHangable() && toCylinder->getTile()->hasProperty(SUPPORTHANGABLE))
  1449.     {
  1450.         //destination supports hangable objects so need to move there first
  1451.         if(toCylinder->getTile()->hasProperty(ISVERTICAL))
  1452.         {
  1453.             if(player->getPosition().x + 1 == mapToPos.x)
  1454.             {
  1455.                 player->sendCancelMessage(RET_NOTPOSSIBLE);
  1456.                 return false;
  1457.             }
  1458.         }
  1459.         else if(toCylinder->getTile()->hasProperty(ISHORIZONTAL))
  1460.         {
  1461.             if(player->getPosition().y + 1 == mapToPos.y)
  1462.             {
  1463.                 player->sendCancelMessage(RET_NOTPOSSIBLE);
  1464.                 return false;
  1465.             }
  1466.         }
  1467.  
  1468.         if(!Position::areInRange<1,1,0>(playerPos, mapToPos) && !player->hasCustomFlag(PlayerCustomFlag_CanMoveFromFar))
  1469.         {
  1470.             Position walkPos = mapToPos;
  1471.             if(toCylinder->getTile()->hasProperty(ISVERTICAL))
  1472.                 walkPos.x -= -1;
  1473.  
  1474.             if(toCylinder->getTile()->hasProperty(ISHORIZONTAL))
  1475.                 walkPos.y -= -1;
  1476.  
  1477.             Position itemPos = fromPos;
  1478.             int16_t itemStackpos = fromStackpos;
  1479.             if(fromPos.x != 0xFFFF && Position::areInRange<1,1,0>(mapFromPos, player->getPosition())
  1480.                 && !Position::areInRange<1,1,0>(mapFromPos, walkPos))
  1481.             {
  1482.                 //need to pickup the item first
  1483.                 Item* moveItem = NULL;
  1484.                 ReturnValue ret = internalMoveItem(player, fromCylinder, player, INDEX_WHEREEVER, item, count, &moveItem);
  1485.                 if(ret != RET_NOERROR)
  1486.                 {
  1487.                     player->sendCancelMessage(ret);
  1488.                     return false;
  1489.                 }
  1490.  
  1491.                 //changing the position since its now in the inventory of the player
  1492.                 internalGetPosition(moveItem, itemPos, itemStackpos);
  1493.             }
  1494.  
  1495.             std::list<Direction> listDir;
  1496.             if(map->getPathTo(player, walkPos, listDir))
  1497.             {
  1498.                 Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
  1499.                     this, player->getID(), listDir)));
  1500.                 SchedulerTask* task = createSchedulerTask(std::max((int64_t)SCHEDULER_MINTICKS, player->getStepDuration()),
  1501.                     boost::bind(&Game::playerMoveItem, this, playerId, itemPos, spriteId, itemStackpos, toPos, count));
  1502.  
  1503.                 player->setNextWalkActionTask(task);
  1504.                 return true;
  1505.             }
  1506.  
  1507.             player->sendCancelMessage(RET_THEREISNOWAY);
  1508.             return false;
  1509.         }
  1510.     }
  1511.  
  1512.     if(!player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
  1513.     {
  1514.         if((std::abs(playerPos.x - mapToPos.x) > item->getThrowRange()) ||
  1515.             (std::abs(playerPos.y - mapToPos.y) > item->getThrowRange()) ||
  1516.             (std::abs(mapFromPos.z - mapToPos.z) * 4 > item->getThrowRange()))
  1517.         {
  1518.             player->sendCancelMessage(RET_DESTINATIONOUTOFREACH);
  1519.             return false;
  1520.         }
  1521.     }
  1522.  
  1523.     if(!canThrowObjectTo(mapFromPos, mapToPos) && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
  1524.     {
  1525.         player->sendCancelMessage(RET_CANNOTTHROW);
  1526.         return false;
  1527.     }
  1528.  
  1529.     if(!g_creatureEvents->executeMoveItems(player, item, mapFromPos, mapToPos))
  1530.         return false;
  1531.  
  1532.     bool deny = false;
  1533.     CreatureEventList throwEvents = player->getCreatureEvents(CREATURE_EVENT_THROW);
  1534.     for(CreatureEventList::iterator it = throwEvents.begin(); it != throwEvents.end(); ++it)
  1535.     {
  1536.         if(!(*it)->executeThrow(player, item, fromPos, toPos) && !deny)
  1537.             deny = true;
  1538.     }
  1539.  
  1540.     if(deny)
  1541.         return false;
  1542.  
  1543.     ReturnValue ret = internalMoveItem(player, fromCylinder, toCylinder, toIndex, item, count, NULL);
  1544.     if(ret != RET_NOERROR)
  1545.     {
  1546.         player->sendCancelMessage(ret);
  1547.         return false;
  1548.     }
  1549.  
  1550.     player->setNextAction(OTSYS_TIME() + g_config.getNumber(ConfigManager::ACTIONS_DELAY_INTERVAL) - 10);
  1551.     return true;
  1552. }
  1553.  
  1554. ReturnValue Game::internalMoveItem(Creature* actor, Cylinder* fromCylinder, Cylinder* toCylinder,
  1555.     int32_t index, Item* item, uint32_t count, Item** _moveItem, uint32_t flags /*= 0*/, Item* tradeItem/* = NULL*/)
  1556. {
  1557.     if(!toCylinder)
  1558.         return RET_NOTPOSSIBLE;
  1559.  
  1560.     if(!item->getParent())
  1561.     {
  1562.         assert(fromCylinder == item->getParent());
  1563.         return internalAddItem(actor, toCylinder, item, INDEX_WHEREEVER, FLAG_NOLIMIT);
  1564.     }
  1565.  
  1566.     Item* toItem = NULL;
  1567.     Cylinder* subCylinder = NULL;
  1568.  
  1569.     int32_t floor = 0;
  1570.     while((subCylinder = toCylinder->__queryDestination(index, item, &toItem, flags)) != toCylinder)
  1571.     {
  1572.         flags = 0;
  1573.         toCylinder = subCylinder;
  1574.         //to prevent infinite loop
  1575.         if(++floor >= MAP_MAX_LAYERS)
  1576.             break;
  1577.     }
  1578.  
  1579.     //destination is the same as the source?
  1580.     if(item == toItem)
  1581.         return RET_NOERROR; //silently ignore move
  1582.    
  1583.     if(toCylinder->getTile())
  1584.     {
  1585.         if(toCylinder->getTile()->hasFlag(TILESTATE_TELEPORT))
  1586.         {
  1587.             Teleport* teleport = toCylinder->getTile()->getTeleportItem();
  1588.             Position dest = teleport->getDestination();
  1589.             if(dest.x != 0 && dest.y != 0) //checks if the portal has a destination set
  1590.             {
  1591.                 Tile* tile = map->getTile(dest);
  1592.                 if(tile)
  1593.                 {
  1594.                     if((tile->hasFlag(TILESTATE_BLOCKSOLID) || tile->getTopCreature()) && item->hasProperty(BLOCKSOLID))
  1595.                         return RET_NOTPOSSIBLE;
  1596.                 }
  1597.             }
  1598.         }
  1599.     }
  1600.  
  1601.     //check if we can add this item
  1602.     ReturnValue ret = toCylinder->__queryAdd(index, item, count, flags, actor);
  1603.     if(ret == RET_NEEDEXCHANGE)
  1604.     {
  1605.         //check if we can add it to source cylinder
  1606.         int32_t fromIndex = fromCylinder->__getIndexOfThing(item);
  1607.         if((ret = fromCylinder->__queryAdd(fromIndex, toItem, toItem->getItemCount(), 0, actor)) == RET_NOERROR)
  1608.         {
  1609.             //check how much we can move
  1610.             uint32_t maxExchangeQueryCount = 0;
  1611.             ReturnValue retExchangeMaxCount = fromCylinder->__queryMaxCount(INDEX_WHEREEVER, toItem, toItem->getItemCount(), maxExchangeQueryCount, 0);
  1612.             if(retExchangeMaxCount != RET_NOERROR && !maxExchangeQueryCount)
  1613.                 return retExchangeMaxCount;
  1614.  
  1615.             if((toCylinder->__queryRemove(toItem, toItem->getItemCount(), flags, actor) == RET_NOERROR) && ret == RET_NOERROR)
  1616.             {
  1617.                 int32_t oldToItemIndex = toCylinder->__getIndexOfThing(toItem);
  1618.                 toCylinder->__removeThing(toItem, toItem->getItemCount());
  1619.  
  1620.                 fromCylinder->__addThing(actor, toItem);
  1621.                 if(oldToItemIndex != -1)
  1622.                     toCylinder->postRemoveNotification(actor, toItem, fromCylinder, oldToItemIndex, true);
  1623.  
  1624.                 int32_t newToItemIndex = fromCylinder->__getIndexOfThing(toItem);
  1625.                 if(newToItemIndex != -1)
  1626.                     fromCylinder->postAddNotification(actor, toItem, toCylinder, newToItemIndex);
  1627.  
  1628.                 ret = toCylinder->__queryAdd(index, item, count, flags, actor);
  1629.                 toItem = NULL;
  1630.             }
  1631.         }
  1632.     }
  1633.  
  1634.     if(ret != RET_NOERROR)
  1635.         return ret;
  1636.  
  1637.     //check how much we can move
  1638.     uint32_t maxQueryCount = 0;
  1639.     ReturnValue retMaxCount = toCylinder->__queryMaxCount(index, item, count, maxQueryCount, flags);
  1640.     if(retMaxCount != RET_NOERROR && !maxQueryCount)
  1641.         return ret;
  1642.  
  1643.     uint32_t m = maxQueryCount;
  1644.     if(item->isStackable())
  1645.         m = std::min((uint32_t)count, m);
  1646.  
  1647.     Item* moveItem = item;
  1648.     //check if we can remove this item
  1649.     if((ret = fromCylinder->__queryRemove(item, m, flags, actor)) != RET_NOERROR)
  1650.         return ret;
  1651.  
  1652.     if(tradeItem)
  1653.     {
  1654.         if(toCylinder->getItem() == tradeItem)
  1655.             return RET_NOTENOUGHROOM;
  1656.  
  1657.         Cylinder* tmpCylinder = toCylinder->getParent();
  1658.         while(tmpCylinder)
  1659.         {
  1660.             if(tmpCylinder->getItem() == tradeItem)
  1661.                 return RET_NOTENOUGHROOM;
  1662.  
  1663.             tmpCylinder = tmpCylinder->getParent();
  1664.         }
  1665.     }
  1666.  
  1667.     //remove the item
  1668.     int32_t itemIndex = fromCylinder->__getIndexOfThing(item);
  1669.     fromCylinder->__removeThing(item, m);
  1670.     bool isCompleteRemoval = item->isRemoved();
  1671.  
  1672.     Item* updateItem = NULL;
  1673.     if(item->isStackable())
  1674.     {
  1675.         uint8_t n = 0;
  1676.         if(toItem && toItem->getID() == item->getID())
  1677.         {
  1678.             n = std::min((uint32_t)100 - toItem->getItemCount(), m);
  1679.             toCylinder->__updateThing(toItem, toItem->getID(), toItem->getItemCount() + n);
  1680.             updateItem = toItem;
  1681.         }
  1682.  
  1683.         if(m - n > 0)
  1684.             moveItem = Item::CreateItem(item->getID(), m - n);
  1685.         else
  1686.             moveItem = NULL;
  1687.  
  1688.         if(item->isRemoved())
  1689.             freeThing(item);
  1690.     }
  1691.  
  1692.     if(moveItem)
  1693.         toCylinder->__addThing(actor, index, moveItem);
  1694.  
  1695.     if(itemIndex != -1)
  1696.         fromCylinder->postRemoveNotification(actor, item, toCylinder, itemIndex, isCompleteRemoval);
  1697.  
  1698.     if(moveItem)
  1699.     {
  1700.         int32_t moveItemIndex = toCylinder->__getIndexOfThing(moveItem);
  1701.         if(moveItemIndex != -1)
  1702.             toCylinder->postAddNotification(actor, moveItem, fromCylinder, moveItemIndex);
  1703.     }
  1704.  
  1705.     if(updateItem)
  1706.     {
  1707.         int32_t updateItemIndex = toCylinder->__getIndexOfThing(updateItem);
  1708.         if(updateItemIndex != -1)
  1709.             toCylinder->postAddNotification(actor, updateItem, fromCylinder, updateItemIndex);
  1710.     }
  1711.  
  1712.     if(_moveItem)
  1713.     {
  1714.         if(moveItem)
  1715.             *_moveItem = moveItem;
  1716.         else
  1717.             *_moveItem = item;
  1718.     }
  1719.  
  1720.     //we could not move all, inform the player
  1721.     if(item->isStackable() && maxQueryCount < count)
  1722.         return retMaxCount;
  1723.  
  1724.     return ret;
  1725. }
  1726.  
  1727. ReturnValue Game::internalMoveTradeItem(Creature* actor, Cylinder* fromCylinder, Cylinder* toCylinder,
  1728.     int32_t index, Item* item, Item* tradeItem, uint32_t count, Item** _moveItem, uint32_t flags /*= 0*/)
  1729. {
  1730.     if(!toCylinder)
  1731.         return RET_NOTPOSSIBLE;
  1732.  
  1733.     if(!item->getParent())
  1734.     {
  1735.         assert(fromCylinder == item->getParent());
  1736.         return internalAddItem(actor, toCylinder, item, INDEX_WHEREEVER, FLAG_NOLIMIT);
  1737.     }
  1738.  
  1739.     Item* toItem = NULL;
  1740.     Cylinder* subCylinder = NULL;
  1741.  
  1742.     int32_t floor = 0;
  1743.     while((subCylinder = toCylinder->__queryDestination(index, item, &toItem, flags)) != toCylinder)
  1744.     {
  1745.         flags = 0;
  1746.         toCylinder = subCylinder;
  1747.         //to prevent infinite loop
  1748.         if(++floor >= MAP_MAX_LAYERS)
  1749.             break;
  1750.     }
  1751.  
  1752.     //destination is the same as the source?
  1753.     if(item == toItem)
  1754.         return RET_NOERROR; //silently ignore move
  1755.  
  1756.     //check if we can add this item
  1757.     ReturnValue ret = toCylinder->__queryAdd(index, item, count, flags, actor);
  1758.     if(ret == RET_NEEDEXCHANGE)
  1759.     {
  1760.         //check if we can add it to source cylinder
  1761.         int32_t fromIndex = fromCylinder->__getIndexOfThing(item);
  1762.         if((ret = fromCylinder->__queryAdd(fromIndex, toItem, toItem->getItemCount(), 0, actor)) == RET_NOERROR)
  1763.         {
  1764.             //check how much we can move
  1765.             uint32_t maxExchangeQueryCount = 0;
  1766.             ReturnValue retExchangeMaxCount = fromCylinder->__queryMaxCount(INDEX_WHEREEVER, toItem, toItem->getItemCount(), maxExchangeQueryCount, 0);
  1767.             if(retExchangeMaxCount != RET_NOERROR && maxExchangeQueryCount == 0)
  1768.                 return retExchangeMaxCount;
  1769.  
  1770.             if((toCylinder->__queryRemove(toItem, toItem->getItemCount(), flags, actor) == RET_NOERROR) && ret == RET_NOERROR)
  1771.             {
  1772.                 int32_t oldToItemIndex = toCylinder->__getIndexOfThing(toItem);
  1773.                 toCylinder->__removeThing(toItem, toItem->getItemCount());
  1774.  
  1775.                 fromCylinder->__addThing(actor, toItem);
  1776.                 if(oldToItemIndex != -1)
  1777.                     toCylinder->postRemoveNotification(actor, toItem, fromCylinder, oldToItemIndex, true);
  1778.  
  1779.                 int32_t newToItemIndex = fromCylinder->__getIndexOfThing(toItem);
  1780.                 if(newToItemIndex != -1)
  1781.                     fromCylinder->postAddNotification(actor, toItem, toCylinder, newToItemIndex);
  1782.  
  1783.                 ret = toCylinder->__queryAdd(index, item, count, flags, actor);
  1784.                 toItem = NULL;
  1785.             }
  1786.         }
  1787.     }
  1788.  
  1789.     if(ret != RET_NOERROR)
  1790.         return ret;
  1791.  
  1792.     //check how much we can move
  1793.     uint32_t maxQueryCount = 0;
  1794.     ReturnValue retMaxCount = toCylinder->__queryMaxCount(index, item, count, maxQueryCount, flags);
  1795.     if(retMaxCount != RET_NOERROR && !maxQueryCount)
  1796.         return ret;
  1797.  
  1798.     uint32_t m = maxQueryCount;
  1799.     if(item->isStackable())
  1800.         m = std::min((uint32_t)count, m);
  1801.  
  1802.     Item* moveItem = item;
  1803.     //check if we can remove this item
  1804.     if((ret = fromCylinder->__queryRemove(item, m, flags, actor)) != RET_NOERROR)
  1805.         return ret;
  1806.  
  1807.     if(toCylinder->getItem() == tradeItem)
  1808.         return RET_NOTENOUGHROOM;
  1809.  
  1810.     Cylinder* tmpCylinder = toCylinder->getParent();
  1811.     while(tmpCylinder)
  1812.     {
  1813.         if(tmpCylinder->getItem() == tradeItem)
  1814.             return RET_NOTENOUGHROOM;
  1815.  
  1816.         tmpCylinder = tmpCylinder->getParent();
  1817.     }
  1818.  
  1819.     //remove the item
  1820.     int32_t itemIndex = fromCylinder->__getIndexOfThing(item);
  1821.     fromCylinder->__removeThing(item, m);
  1822.     bool isCompleteRemoval = item->isRemoved();
  1823.  
  1824.     Item* updateItem = NULL;
  1825.     if(item->isStackable())
  1826.     {
  1827.         uint8_t n = 0;
  1828.         if(toItem && toItem->getID() == item->getID())
  1829.         {
  1830.             n = std::min((uint32_t)100 - toItem->getItemCount(), m);
  1831.             toCylinder->__updateThing(toItem, toItem->getID(), toItem->getItemCount() + n);
  1832.             updateItem = toItem;
  1833.         }
  1834.  
  1835.         if(m - n > 0)
  1836.             moveItem = Item::CreateItem(item->getID(), m - n);
  1837.         else
  1838.             moveItem = NULL;
  1839.  
  1840.         if(item->isRemoved())
  1841.             freeThing(item);
  1842.     }
  1843.  
  1844.     if(moveItem)
  1845.         toCylinder->__addThing(actor, index, moveItem);
  1846.  
  1847.     if(itemIndex != -1)
  1848.         fromCylinder->postRemoveNotification(actor, item, toCylinder, itemIndex, isCompleteRemoval);
  1849.  
  1850.     if(moveItem)
  1851.     {
  1852.         int32_t moveItemIndex = toCylinder->__getIndexOfThing(moveItem);
  1853.         if(moveItemIndex != -1)
  1854.             toCylinder->postAddNotification(actor, moveItem, fromCylinder, moveItemIndex);
  1855.     }
  1856.  
  1857.     if(updateItem)
  1858.     {
  1859.         int32_t updateItemIndex = toCylinder->__getIndexOfThing(updateItem);
  1860.         if(updateItemIndex != -1)
  1861.             toCylinder->postAddNotification(actor, updateItem, fromCylinder, updateItemIndex);
  1862.     }
  1863.  
  1864.     if(_moveItem)
  1865.     {
  1866.         if(moveItem)
  1867.             *_moveItem = moveItem;
  1868.         else
  1869.             *_moveItem = item;
  1870.     }
  1871.  
  1872.     //we could not move all, inform the player
  1873.     if(item->isStackable() && maxQueryCount < count)
  1874.         return retMaxCount;
  1875.  
  1876.     return ret;
  1877. }
  1878.  
  1879. ReturnValue Game::internalAddItem(Creature* actor, Cylinder* toCylinder, Item* item, int32_t index /*= INDEX_WHEREEVER*/,
  1880.     uint32_t flags/* = 0*/, bool test/* = false*/)
  1881. {
  1882.     uint32_t remainderCount = 0;
  1883.     return internalAddItem(actor, toCylinder, item, index, flags, test, remainderCount);
  1884. }
  1885.  
  1886. ReturnValue Game::internalAddItem(Creature* actor, Cylinder* toCylinder, Item* item, int32_t index,
  1887.     uint32_t flags, bool test, uint32_t& remainderCount)
  1888. {
  1889.     Item* stackItem = NULL;
  1890.     return internalAddItem(actor, toCylinder, item, index, flags, test, remainderCount, &stackItem);
  1891. }
  1892.  
  1893. ReturnValue Game::internalAddItem(Creature* actor, Cylinder* toCylinder, Item* item, int32_t index,
  1894.     uint32_t flags, bool test, uint32_t& remainderCount, Item** stackItem)
  1895. {
  1896.     *stackItem = NULL;
  1897.     remainderCount = 0;
  1898.     if(!toCylinder || !item)
  1899.         return RET_NOTPOSSIBLE;
  1900.  
  1901.     Cylinder* destCylinder = toCylinder;
  1902.     toCylinder = toCylinder->__queryDestination(index, item, stackItem, flags);
  1903.  
  1904.     //check if we can add this item
  1905.     ReturnValue ret = toCylinder->__queryAdd(index, item, item->getItemCount(), flags, actor);
  1906.     if(ret != RET_NOERROR)
  1907.         return ret;
  1908.  
  1909.     uint32_t maxQueryCount = 0;
  1910.     ret = destCylinder->__queryMaxCount(INDEX_WHEREEVER, item, item->getItemCount(), maxQueryCount, flags);
  1911.     if(ret != RET_NOERROR)
  1912.         return ret;
  1913.  
  1914.     if(test)
  1915.         return RET_NOERROR;
  1916.  
  1917.     Item* toItem = *stackItem;
  1918.     if(item->isStackable() && toItem)
  1919.     {
  1920.         uint32_t m = std::min((uint32_t)item->getItemCount(), maxQueryCount), n = 0;
  1921.         if(toItem->getID() == item->getID())
  1922.         {
  1923.             n = std::min((uint32_t)100 - toItem->getItemCount(), m);
  1924.             toCylinder->__updateThing(toItem, toItem->getID(), toItem->getItemCount() + n);
  1925.         }
  1926.  
  1927.         uint32_t count = m - n;
  1928.         if(count > 0)
  1929.         {
  1930.             if(item->getItemCount() != count)
  1931.             {
  1932.                 Item* remainderItem = Item::CreateItem(item->getID(), count);
  1933.                 if((ret = internalAddItem(NULL, toCylinder, remainderItem, INDEX_WHEREEVER, flags, false)) == RET_NOERROR)
  1934.                 {
  1935.                     if(item->getParent() != VirtualCylinder::virtualCylinder)
  1936.                     {
  1937.                         item->onRemoved();
  1938.                         freeThing(item);
  1939.                     }
  1940.  
  1941.                     return RET_NOERROR;
  1942.                 }
  1943.  
  1944.                 delete remainderItem;
  1945.                 remainderCount = count;
  1946.                 return ret;
  1947.             }
  1948.         }
  1949.         else
  1950.         {
  1951.             if(item->getParent() != VirtualCylinder::virtualCylinder)
  1952.             {
  1953.                 item->onRemoved();
  1954.                 freeThing(item);
  1955.             }
  1956.  
  1957.             return RET_NOERROR;
  1958.         }
  1959.     }
  1960.  
  1961.     toCylinder->__addThing(NULL, index, item);
  1962.     int32_t itemIndex = toCylinder->__getIndexOfThing(item);
  1963.     if(itemIndex != -1)
  1964.         toCylinder->postAddNotification(actor, item, NULL, itemIndex);
  1965.  
  1966.     return RET_NOERROR;
  1967. }
  1968.  
  1969. ReturnValue Game::internalRemoveItem(Creature* actor, Item* item, int32_t count/* = -1*/, bool test/* = false*/, uint32_t flags/* = 0*/)
  1970. {
  1971.     Cylinder* cylinder = item->getParent();
  1972.     if(!cylinder)
  1973.         return RET_NOTPOSSIBLE;
  1974.  
  1975.     if(count == -1)
  1976.         count = item->getItemCount();
  1977.  
  1978.     //check if we can remove this item
  1979.     ReturnValue ret = cylinder->__queryRemove(item, count, flags | FLAG_IGNORENOTMOVABLE, actor);
  1980.     if(ret != RET_NOERROR)
  1981.         return ret;
  1982.  
  1983.     if(!item->canRemove())
  1984.         return RET_NOTPOSSIBLE;
  1985.  
  1986.     if(!test)
  1987.     {
  1988.         //remove the item
  1989.         int32_t index = cylinder->__getIndexOfThing(item);
  1990.         cylinder->__removeThing(item, count);
  1991.  
  1992.         cylinder->postRemoveNotification(actor, item, NULL, index, item->isRemoved());
  1993.         if(item->isRemoved())
  1994.             freeThing(item);
  1995.     }
  1996.  
  1997.     item->onRemoved();
  1998.     return RET_NOERROR;
  1999. }
  2000.  
  2001. ReturnValue Game::internalPlayerAddItem(Creature* actor, Player* player, Item* item,
  2002.     bool dropOnMap/* = true*/, slots_t slot/* = SLOT_WHEREEVER*/)
  2003. {
  2004.     Item* toItem = NULL;
  2005.     return internalPlayerAddItem(actor, player, item, dropOnMap, slot, &toItem);
  2006. }
  2007.  
  2008. ReturnValue Game::internalPlayerAddItem(Creature* actor, Player* player, Item* item,
  2009.     bool dropOnMap, slots_t slot, Item** toItem)
  2010. {
  2011.     uint32_t remainderCount = 0, count = item->getItemCount();
  2012.     ReturnValue ret = internalAddItem(actor, player, item, (int32_t)slot, 0, false, remainderCount, toItem);
  2013.     if(ret == RET_NOERROR)
  2014.         return RET_NOERROR;
  2015.  
  2016.     if(dropOnMap)
  2017.     {
  2018.         if(!remainderCount)
  2019.             return internalAddItem(actor, player->getTile(), item, (int32_t)slot, FLAG_NOLIMIT);
  2020.  
  2021.         Item* remainderItem = Item::CreateItem(item->getID(), remainderCount);
  2022.         if(internalAddItem(actor, player->getTile(), remainderItem, INDEX_WHEREEVER, FLAG_NOLIMIT) == RET_NOERROR)
  2023.             return RET_NOERROR;
  2024.  
  2025.         delete remainderItem;
  2026.     }
  2027.  
  2028.     if(remainderCount && toItem)
  2029.         transformItem(*toItem, (*toItem)->getID(), ((*toItem)->getItemCount() - (count - remainderCount)));
  2030.  
  2031.     return ret;
  2032. }
  2033.  
  2034. Item* Game::findItemOfType(Cylinder* cylinder, uint16_t itemId,
  2035.     bool depthSearch /*= true*/, int32_t subType /*= -1*/)
  2036. {
  2037.     if(!cylinder)
  2038.         return NULL;
  2039.  
  2040.     std::list<Container*> listContainer;
  2041.     Container* tmpContainer = NULL;
  2042.     Item* item = NULL;
  2043.  
  2044.     Thing* thing = NULL;
  2045.     for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex();)
  2046.     {
  2047.         if((thing = cylinder->__getThing(i)) && (item = thing->getItem()))
  2048.         {
  2049.             if(item->getID() == itemId && (subType == -1 || subType == item->getSubType()))
  2050.                 return item;
  2051.  
  2052.             ++i;
  2053.             if(depthSearch && (tmpContainer = item->getContainer()))
  2054.                 listContainer.push_back(tmpContainer);
  2055.         }
  2056.         else
  2057.             ++i;
  2058.     }
  2059.  
  2060.     Container* container = NULL;
  2061.     while(listContainer.size() > 0)
  2062.     {
  2063.         container = listContainer.front();
  2064.         listContainer.pop_front();
  2065.         for(int32_t i = 0; i < (int32_t)container->size(); )
  2066.         {
  2067.             if((item = container->getItem(i)))
  2068.             {
  2069.                 if(item->getID() == itemId && (subType == -1 || subType == item->getSubType()))
  2070.                     return item;
  2071.  
  2072.                 ++i;
  2073.                 if((tmpContainer = item->getContainer()))
  2074.                     listContainer.push_back(tmpContainer);
  2075.             }
  2076.             else
  2077.                 ++i;
  2078.         }
  2079.     }
  2080.  
  2081.     return NULL;
  2082. }
  2083.  
  2084. bool Game::removeItemOfType(Cylinder* cylinder, uint16_t itemId, int32_t count, int32_t subType/* = -1*/, bool onlyContainers/* = false*/)
  2085. {
  2086.     if(!cylinder || ((int32_t)cylinder->__getItemTypeCount(itemId, subType) < count))
  2087.         return false;
  2088.  
  2089.     if(count <= 0)
  2090.         return true;
  2091.  
  2092.     std::list<Container*> listContainer;
  2093.     Container* tmpContainer = NULL;
  2094.     Item* item = NULL;
  2095.  
  2096.     Thing* thing = NULL;
  2097.     for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex() && count > 0; )
  2098.     {
  2099.         if((thing = cylinder->__getThing(i)) && (item = thing->getItem()))
  2100.         {
  2101.             if(!onlyContainers && item->getID() == itemId)
  2102.             {
  2103.                 if(item->isStackable())
  2104.                 {
  2105.                     if(item->getItemCount() > count)
  2106.                     {
  2107.                         internalRemoveItem(NULL, item, count);
  2108.                         count = 0;
  2109.                     }
  2110.                     else
  2111.                     {
  2112.                         count -= item->getItemCount();
  2113.                         internalRemoveItem(NULL, item);
  2114.                     }
  2115.                 }
  2116.                 else if(subType == -1 || subType == item->getSubType())
  2117.                 {
  2118.                     --count;
  2119.                     internalRemoveItem(NULL, item);
  2120.                 }
  2121.                 else
  2122.                     ++i;
  2123.             }
  2124.             else
  2125.             {
  2126.                 ++i;
  2127.                 if((tmpContainer = item->getContainer()))
  2128.                     listContainer.push_back(tmpContainer);
  2129.             }
  2130.         }
  2131.         else
  2132.             ++i;
  2133.     }
  2134.  
  2135.     Container* container = NULL;
  2136.     while(listContainer.size() > 0 && count > 0)
  2137.     {
  2138.         container = listContainer.front();
  2139.         listContainer.pop_front();
  2140.         for(int32_t i = 0; i < (int32_t)container->size() && count > 0; )
  2141.         {
  2142.             if((item = container->getItem(i)))
  2143.             {
  2144.                 if(item->getID() == itemId)
  2145.                 {
  2146.                     if(item->isStackable())
  2147.                     {
  2148.                         if(item->getItemCount() > count)
  2149.                         {
  2150.                             internalRemoveItem(NULL, item, count);
  2151.                             count = 0;
  2152.                         }
  2153.                         else
  2154.                         {
  2155.                             count-= item->getItemCount();
  2156.                             internalRemoveItem(NULL, item);
  2157.                         }
  2158.                     }
  2159.                     else if(subType == -1 || subType == item->getSubType())
  2160.                     {
  2161.                         --count;
  2162.                         internalRemoveItem(NULL, item);
  2163.                     }
  2164.                     else
  2165.                         ++i;
  2166.                 }
  2167.                 else
  2168.                 {
  2169.                     ++i;
  2170.                     if((tmpContainer = item->getContainer()))
  2171.                         listContainer.push_back(tmpContainer);
  2172.                 }
  2173.             }
  2174.             else
  2175.                 ++i;
  2176.         }
  2177.     }
  2178.  
  2179.     return !count;
  2180. }
  2181.  
  2182. uint64_t Game::getMoney(const Cylinder* cylinder)
  2183. {
  2184.     if(!cylinder)
  2185.         return 0;
  2186.  
  2187.     std::list<Container*> listContainer;
  2188.     Container* tmpContainer = NULL;
  2189.  
  2190.     Thing* thing = NULL;
  2191.     Item* item = NULL;
  2192.  
  2193.     uint64_t moneyCount = 0;
  2194.     for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex(); ++i)
  2195.     {
  2196.         if(!(thing = cylinder->__getThing(i)) || !(item = thing->getItem()))
  2197.             continue;
  2198.  
  2199.         if((tmpContainer = item->getContainer()))
  2200.             listContainer.push_back(tmpContainer);
  2201.         else if(item->getWorth())
  2202.             moneyCount += item->getWorth();
  2203.     }
  2204.  
  2205.     Container* container = NULL;
  2206.     while(listContainer.size() > 0)
  2207.     {
  2208.         container = listContainer.front();
  2209.         listContainer.pop_front();
  2210.         for(ItemList::const_iterator it = container->getItems(); it != container->getEnd(); ++it)
  2211.         {
  2212.             item = *it;
  2213.             if((tmpContainer = item->getContainer()))
  2214.                 listContainer.push_back(tmpContainer);
  2215.             else if(item->getWorth())
  2216.                 moneyCount += item->getWorth();
  2217.         }
  2218.     }
  2219.  
  2220.     return moneyCount;
  2221. }
  2222.  
  2223. bool Game::removeMoney(Cylinder* cylinder, int64_t money, uint32_t flags /*= 0*/)
  2224. {
  2225.     if(!cylinder)
  2226.         return false;
  2227.  
  2228.     if(money <= 0)
  2229.         return true;
  2230.  
  2231.     typedef std::multimap<int32_t, Item*, std::less<int32_t> > MoneyMultiMap;
  2232.     MoneyMultiMap moneyMap;
  2233.  
  2234.     std::list<Container*> listContainer;
  2235.     Container* tmpContainer = NULL;
  2236.  
  2237.     Thing* thing = NULL;
  2238.     Item* item = NULL;
  2239.  
  2240.     int64_t moneyCount = 0;
  2241.     for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex(); ++i)
  2242.     {
  2243.         if(!(thing = cylinder->__getThing(i)) || !(item = thing->getItem()))
  2244.             continue;
  2245.  
  2246.         if((tmpContainer = item->getContainer()))
  2247.             listContainer.push_back(tmpContainer);
  2248.         else if(item->getWorth())
  2249.         {
  2250.             moneyCount += item->getWorth();
  2251.             moneyMap.insert(std::make_pair(item->getWorth(), item));
  2252.         }
  2253.     }
  2254.  
  2255.     while(listContainer.size() > 0)
  2256.     {
  2257.         Container* container = listContainer.front();
  2258.         listContainer.pop_front();
  2259.         for(int32_t i = 0; i < (int32_t)container->size(); ++i)
  2260.         {
  2261.             Item* item = container->getItem(i);
  2262.             if((tmpContainer = item->getContainer()))
  2263.                 listContainer.push_back(tmpContainer);
  2264.             else if(item->getWorth())
  2265.             {
  2266.                 moneyCount += item->getWorth();
  2267.                 moneyMap.insert(std::make_pair(item->getWorth(), item));
  2268.             }
  2269.         }
  2270.     }
  2271.  
  2272.     // Not enough money
  2273.     if(moneyCount < money)
  2274.         return false;
  2275.  
  2276.     for(MoneyMultiMap::iterator mit = moneyMap.begin(); mit != moneyMap.end() && money > 0; ++mit)
  2277.     {
  2278.         if(!(item = mit->second))
  2279.             continue;
  2280.  
  2281.         internalRemoveItem(NULL, item);
  2282.         if(mit->first > money)
  2283.         {
  2284.             // Remove a monetary value from an item
  2285.             addMoney(cylinder, (int64_t)(item->getWorth() - money), flags);
  2286.             money = 0;
  2287.         }
  2288.         else
  2289.             money -= mit->first;
  2290.  
  2291.         mit->second = NULL;
  2292.     }
  2293.  
  2294.     moneyMap.clear();
  2295.     return !money;
  2296. }
  2297.  
  2298. void Game::addMoney(Cylinder* cylinder, int64_t money, uint32_t flags /*= 0*/)
  2299. {
  2300.     IntegerMap moneyMap = Item::items.getMoneyMap();
  2301.     for(IntegerMap::reverse_iterator it = moneyMap.rbegin(); it != moneyMap.rend(); ++it)
  2302.     {
  2303.         int64_t tmp = money / it->first;
  2304.         money -= tmp * it->first;
  2305.         if(!tmp)
  2306.             continue;
  2307.  
  2308.         do
  2309.         {
  2310.             uint32_t remainderCount = 0;
  2311.             Item* item = Item::CreateItem(it->second, std::min<uint16_t>(100, tmp));
  2312.             if(internalAddItem(NULL, cylinder, item, INDEX_WHEREEVER, flags, false, remainderCount) != RET_NOERROR)
  2313.             {
  2314.                 if(remainderCount)
  2315.                 {
  2316.                     delete item;
  2317.                     item = Item::CreateItem(it->second, remainderCount);
  2318.                 }
  2319.  
  2320.                 if(internalAddItem(NULL, cylinder->getTile(), item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RET_NOERROR)
  2321.                     delete item;
  2322.             }
  2323.  
  2324.             tmp -= std::min((int64_t)100, tmp);
  2325.         }
  2326.         while(tmp > 0);
  2327.     }
  2328. }
  2329.  
  2330. Item* Game::transformItem(Item* item, uint16_t newId, int32_t newCount/* = -1*/)
  2331. {
  2332.     if(item->getID() == newId && (newCount == -1 || (newCount == item->getSubType() && newCount)))
  2333.         return item;
  2334.  
  2335.     Cylinder* cylinder = item->getParent();
  2336.     if(!cylinder)
  2337.         return NULL;
  2338.  
  2339.     int32_t itemIndex = cylinder->__getIndexOfThing(item);
  2340.     if(itemIndex == -1)
  2341.     {
  2342. #ifdef __DEBUG__
  2343.         std::clog << "Error: transformItem, itemIndex == -1" << std::endl;
  2344. #endif
  2345.         return item;
  2346.     }
  2347.  
  2348.     if(!item->canTransform())
  2349.         return item;
  2350.  
  2351.     const ItemType &curType = Item::items[item->getID()], &newType = Item::items[newId];
  2352.     if(curType.alwaysOnTop != newType.alwaysOnTop)
  2353.     {
  2354.         // This only occurs when you transform items on tiles from a downItem to a topItem (or vice versa)
  2355.         // Remove the old, and add the new
  2356.         ReturnValue ret = internalRemoveItem(NULL, item);
  2357.         if(ret != RET_NOERROR)
  2358.             return item;
  2359.  
  2360.         Item* newItem = NULL;
  2361.         if(newCount == -1)
  2362.             newItem = Item::CreateItem(newId);
  2363.         else
  2364.             newItem = Item::CreateItem(newId, newCount);
  2365.  
  2366.         if(!newItem)
  2367.             return NULL;
  2368.  
  2369.         newItem->copyAttributes(item);
  2370.         if(internalAddItem(NULL, cylinder, newItem, INDEX_WHEREEVER, FLAG_NOLIMIT) != RET_NOERROR)
  2371.         {
  2372.             delete newItem;
  2373.             return NULL;
  2374.         }
  2375.  
  2376.         newItem->makeUnique(item);
  2377.         return newItem;
  2378.     }
  2379.  
  2380.     if(curType.type == newType.type)
  2381.     {
  2382.         //Both items has the same type so we can safely change id/subtype
  2383.         if(!newCount && (item->isStackable() || item->hasCharges()))
  2384.         {
  2385.             if(!item->isStackable() && (!item->getDefaultDuration() || item->getDuration() <= 0))
  2386.             {
  2387.                 int16_t tmp = newId;
  2388.                 if(curType.id == newId)
  2389.                     tmp = curType.decayTo;
  2390.  
  2391.                 if(tmp != -1)
  2392.                     return transformItem(item, tmp);
  2393.             }
  2394.  
  2395.             internalRemoveItem(NULL, item);
  2396.             return NULL;
  2397.         }
  2398.  
  2399.         cylinder->postRemoveNotification(NULL, item, cylinder, itemIndex, false);
  2400.         uint16_t tmp = item->getID();
  2401.         if(curType.id != newId)
  2402.         {
  2403.             tmp = newId;
  2404.             if(newType.group != curType.group)
  2405.                 item->setDefaultSubtype();
  2406.  
  2407.             if(curType.hasSubType() && !newType.hasSubType())
  2408.             {
  2409.                 item->resetFluidType();
  2410.                 item->resetCharges();
  2411.             }
  2412.         }
  2413.  
  2414.         int32_t count = item->getSubType();
  2415.         if(newCount != -1 && newType.hasSubType())
  2416.             count = newCount;
  2417.  
  2418.         cylinder->__updateThing(item, tmp, count);
  2419.         cylinder->postAddNotification(NULL, item, cylinder, itemIndex);
  2420.         return item;
  2421.     }
  2422.  
  2423.     //Replacing the the old item with the new while maintaining the old position
  2424.     Item* newItem = NULL;
  2425.     if(newCount == -1)
  2426.         newItem = Item::CreateItem(newId);
  2427.     else
  2428.         newItem = Item::CreateItem(newId, newCount);
  2429.  
  2430.     if(!newItem)
  2431.         return NULL;
  2432.  
  2433.     newItem->copyAttributes(item);
  2434.     newItem->makeUnique(item);
  2435.     cylinder->__replaceThing(itemIndex, newItem);
  2436.  
  2437.     cylinder->postAddNotification(NULL, newItem, cylinder, itemIndex);
  2438.     item->setParent(NULL);
  2439.     cylinder->postRemoveNotification(NULL, item, cylinder, itemIndex, true);
  2440.  
  2441.     freeThing(item);
  2442.     return newItem;
  2443. }
  2444.  
  2445. ReturnValue Game::internalTeleport(Thing* thing, const Position& newPos, bool forceTeleport, uint32_t flags/* = 0*/, bool fullTeleport/* = true*/)
  2446. {
  2447.     if(newPos == thing->getPosition())
  2448.         return RET_NOERROR;
  2449.  
  2450.     if(thing->isRemoved())
  2451.         return RET_NOTPOSSIBLE;
  2452.  
  2453.     if(Tile* toTile = map->getTile(newPos))
  2454.     {
  2455.         if(Creature* creature = thing->getCreature())
  2456.         {
  2457.             if(fullTeleport)
  2458.                 return internalMoveCreature(NULL, creature, creature->getParent(), toTile, flags, forceTeleport);
  2459.  
  2460.             creature->getTile()->moveCreature(NULL, creature, toTile, forceTeleport);
  2461.             return RET_NOERROR;
  2462.         }
  2463.  
  2464.         if(Item* item = thing->getItem())
  2465.             return internalMoveItem(NULL, item->getParent(), toTile, INDEX_WHEREEVER, item, item->getItemCount(), NULL, flags);
  2466.     }
  2467.  
  2468.     return RET_NOTPOSSIBLE;
  2469. }
  2470.  
  2471. bool Game::playerMove(uint32_t playerId, Direction dir)
  2472. {
  2473.     Player* player = getPlayerByID(playerId);
  2474.     if(!player || player->isRemoved())
  2475.         return false;
  2476.  
  2477.     player->setIdleTime(0);
  2478.     if(player->getNoMove())
  2479.     {
  2480.         player->sendCancelWalk();
  2481.         return false;
  2482.     }
  2483.  
  2484.     std::list<Direction> dirs;
  2485.     dirs.push_back(dir);
  2486.  
  2487.     player->setNextWalkActionTask(NULL);
  2488.     return player->startAutoWalk(dirs);
  2489. }
  2490.  
  2491. bool Game::playerBroadcastMessage(Player* player, MessageClasses type, const std::string& text, uint32_t statementId)
  2492. {
  2493.     if(!player->hasFlag(PlayerFlag_CanBroadcast) || !((type >= MSG_SPEAK_FIRST && type <= MSG_SPEAK_LAST) ||
  2494.             (type >= MSG_SPEAK_MONSTER_FIRST && type <= MSG_SPEAK_MONSTER_LAST)))
  2495.         return false;
  2496.  
  2497.     Logger::getInstance()->eFile("talkactions/" + player->getName() + ".log", "#b " + text, true);
  2498.     for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
  2499.         it->second->sendCreatureSay(player, type, text, NULL, statementId);
  2500.  
  2501.     std::clog << "> " << player->getName() << " broadcasted: \"" << text << "\"." << std::endl;
  2502.     return true;
  2503. }
  2504.  
  2505. bool Game::playerCreatePrivateChannel(uint32_t playerId)
  2506. {
  2507.     Player* player = getPlayerByID(playerId);
  2508.     if(!player || player->isRemoved() || !player->isPremium())
  2509.         return false;
  2510.  
  2511.     ChatChannel* channel = g_chat.createChannel(player, 0xFFFF);
  2512.     if(!channel || !channel->addUser(player))
  2513.         return false;
  2514.  
  2515.     player->sendCreatePrivateChannel(channel->getId(), channel->getName());
  2516.     return true;
  2517. }
  2518.  
  2519. bool Game::playerChannelInvite(uint32_t playerId, const std::string& name)
  2520. {
  2521.     Player* player = getPlayerByID(playerId);
  2522.     if(!player || player->isRemoved())
  2523.         return false;
  2524.  
  2525.     PrivateChatChannel* channel = g_chat.getPrivateChannel(player);
  2526.     if(!channel)
  2527.         return false;
  2528.  
  2529.     Player* invitePlayer = getPlayerByName(name);
  2530.     if(!invitePlayer)
  2531.         return false;
  2532.  
  2533.     channel->invitePlayer(player, invitePlayer);
  2534.     return true;
  2535. }
  2536.  
  2537. bool Game::playerChannelExclude(uint32_t playerId, const std::string& name)
  2538. {
  2539.     Player* player = getPlayerByID(playerId);
  2540.     if(!player || player->isRemoved())
  2541.         return false;
  2542.  
  2543.     PrivateChatChannel* channel = g_chat.getPrivateChannel(player);
  2544.     if(!channel)
  2545.         return false;
  2546.  
  2547.     Player* excludePlayer = getPlayerByName(name);
  2548.     if(!excludePlayer)
  2549.         return false;
  2550.  
  2551.     channel->excludePlayer(player, excludePlayer);
  2552.     return true;
  2553. }
  2554.  
  2555. bool Game::playerRequestChannels(uint32_t playerId)
  2556. {
  2557.     Player* player = getPlayerByID(playerId);
  2558.     if(!player || player->isRemoved())
  2559.         return false;
  2560.  
  2561.     player->sendChannelsDialog(g_chat.getChannelList(player));
  2562.     player->setSentChat(true);
  2563.     return true;
  2564. }
  2565.  
  2566. bool Game::playerOpenChannel(uint32_t playerId, uint16_t channelId)
  2567. {
  2568.     Player* player = getPlayerByID(playerId);
  2569.     if(!player || player->isRemoved())
  2570.         return false;
  2571.  
  2572.     bool deny = false;
  2573.     CreatureEventList openEvents = player->getCreatureEvents(CREATURE_EVENT_CHANNEL_REQUEST);
  2574.     for(CreatureEventList::iterator it = openEvents.begin(); it != openEvents.end(); ++it)
  2575.     {
  2576.         if(!(*it)->executeChannelRequest(player, asString(channelId), false, !player->hasSentChat()) && !deny)
  2577.             deny = true;
  2578.     }
  2579.  
  2580.     player->setSentChat(false);
  2581.     if(deny)
  2582.         return false;
  2583.  
  2584.     ChatChannel* channel = g_chat.addUserToChannel(player, channelId);
  2585.     if(!channel)
  2586.     {
  2587.         #ifdef __DEBUG_CHAT__
  2588.         std::clog << "Game::playerOpenChannel - failed adding user to channel." << std::endl;
  2589.         #endif
  2590.         return false;
  2591.     }
  2592.  
  2593.     if(channel->getId() != CHANNEL_RVR)
  2594.         player->sendChannel(channel->getId(), channel->getName());
  2595.     else
  2596.         player->sendRuleViolationsChannel(channel->getId());
  2597.  
  2598.     return true;
  2599. }
  2600.  
  2601. bool Game::playerCloseChannel(uint32_t playerId, uint16_t channelId)
  2602. {
  2603.     Player* player = getPlayerByID(playerId);
  2604.     if(!player || player->isRemoved())
  2605.         return false;
  2606.  
  2607.     g_chat.removeUserFromChannel(player, channelId);
  2608.     player->client->chat(channelId);
  2609.     return true;
  2610. }
  2611.  
  2612. bool Game::playerProcessRuleViolation(uint32_t playerId, const std::string& name)
  2613. {
  2614.     Player* player = getPlayerByID(playerId);
  2615.     if(!player || player->isRemoved())
  2616.         return false;
  2617.  
  2618.     if(!player->hasFlag(PlayerFlag_CanAnswerRuleViolations))
  2619.         return false;
  2620.  
  2621.     Player* reporter = getPlayerByName(name);
  2622.     if(!reporter)
  2623.         return false;
  2624.  
  2625.     RuleViolationsMap::iterator it = ruleViolations.find(reporter->getID());
  2626.     if(it == ruleViolations.end())
  2627.         return false;
  2628.  
  2629.     RuleViolation& rvr = *it->second;
  2630.     if(!rvr.isOpen)
  2631.         return false;
  2632.  
  2633.     rvr.isOpen = false;
  2634.     rvr.gamemaster = player;
  2635.     if(ChatChannel* channel = g_chat.getChannelById(CHANNEL_RVR))
  2636.     {
  2637.         UsersMap tmpMap = channel->getUsers();
  2638.         for(UsersMap::iterator tit = tmpMap.begin(); tit != tmpMap.end(); ++tit)
  2639.             tit->second->sendRemoveReport(reporter->getName());
  2640.     }
  2641.  
  2642.     return true;
  2643. }
  2644.  
  2645. bool Game::playerCloseRuleViolation(uint32_t playerId, const std::string& name)
  2646. {
  2647.     Player* player = getPlayerByID(playerId);
  2648.     if(!player || player->isRemoved())
  2649.         return false;
  2650.  
  2651.     Player* reporter = getPlayerByName(name);
  2652.     if(!reporter)
  2653.         return false;
  2654.  
  2655.     return closeRuleViolation(reporter);
  2656. }
  2657.  
  2658. bool Game::playerCancelRuleViolation(uint32_t playerId)
  2659. {
  2660.     Player* player = getPlayerByID(playerId);
  2661.     if(!player || player->isRemoved())
  2662.         return false;
  2663.  
  2664.     return cancelRuleViolation(player);
  2665. }
  2666.  
  2667. bool Game::playerOpenPrivateChannel(uint32_t playerId, std::string& receiver)
  2668. {
  2669.     Player* player = getPlayerByID(playerId);
  2670.     if(!player || player->isRemoved())
  2671.         return false;
  2672.  
  2673.     if(player->hasCondition(CONDITION_EXHAUST, EXHAUST_PLAYEROPENCHANNEL))
  2674.     {
  2675.         player->sendTextMessage(MSG_STATUS_SMALL, "Please wait few seconds.");
  2676.         return false;
  2677.     }
  2678.  
  2679.     if(Condition* privCondition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 1000, 0, false, EXHAUST_PLAYEROPENCHANNEL))
  2680.         player->addCondition(privCondition);
  2681.  
  2682.     bool deny = false;
  2683.     CreatureEventList openEvents = player->getCreatureEvents(CREATURE_EVENT_CHANNEL_REQUEST);
  2684.     for(CreatureEventList::iterator it = openEvents.begin(); it != openEvents.end(); ++it)
  2685.     {
  2686.         if(!(*it)->executeChannelRequest(player, receiver, true, !player->hasSentChat()) && !deny)
  2687.             deny = true;
  2688.     }
  2689.  
  2690.     player->setSentChat(false);
  2691.     if(deny)
  2692.         return false;
  2693.  
  2694.     if(IOLoginData::getInstance()->playerExists(receiver))
  2695.         player->sendOpenPrivateChannel(receiver);
  2696.     else
  2697.         player->sendCancel("A player with this name does not exist.");
  2698.  
  2699.     return true;
  2700. }
  2701.  
  2702. bool Game::playerCloseNpcChannel(uint32_t playerId)
  2703. {
  2704.     Player* player = getPlayerByID(playerId);
  2705.     if(!player || player->isRemoved())
  2706.         return false;
  2707.  
  2708.     SpectatorVec list;
  2709.     SpectatorVec::iterator it;
  2710.  
  2711.     getSpectators(list, player->getPosition());
  2712.     Npc* npc = NULL;
  2713.     for(it = list.begin(); it != list.end(); ++it)
  2714.     {
  2715.         if((npc = (*it)->getNpc()))
  2716.             npc->onPlayerCloseChannel(player);
  2717.     }
  2718.  
  2719.     return true;
  2720. }
  2721.  
  2722. bool Game::playerReceivePing(uint32_t playerId)
  2723. {
  2724.     Player* player = getPlayerByID(playerId);
  2725.     if(!player || player->isRemoved())
  2726.         return false;
  2727.  
  2728.     player->receivePing();
  2729.     return true;
  2730. }
  2731.  
  2732. bool Game::playerAutoWalk(uint32_t playerId, std::list<Direction>& listDir)
  2733. {
  2734.     Player* player = getPlayerByID(playerId);
  2735.     if(!player || player->isRemoved())
  2736.         return false;
  2737.  
  2738.     player->setIdleTime(0);
  2739.     if(player->getNoMove())
  2740.     {
  2741.         player->sendCancelWalk();
  2742.         return false;
  2743.     }
  2744.  
  2745.     if(player->hasCondition(CONDITION_GAMEMASTER, GAMEMASTER_TELEPORT))
  2746.     {
  2747.         Position pos = player->getPosition();
  2748.         for(std::list<Direction>::iterator it = listDir.begin(); it != listDir.end(); ++it)
  2749.             pos = getNextPosition((*it), pos);
  2750.  
  2751.         pos = getClosestFreeTile(player, pos, true, false);
  2752.         if(!pos.x || !pos.y)
  2753.         {
  2754.             player->sendCancelWalk();
  2755.             return false;
  2756.         }
  2757.  
  2758.         internalCreatureTurn(player, getDirectionTo(player->getPosition(), pos, false));
  2759.         internalTeleport(player, pos, true);
  2760.         return true;
  2761.     }
  2762.  
  2763.     player->setNextWalkTask(NULL);
  2764.     return player->startAutoWalk(listDir);
  2765. }
  2766.  
  2767. bool Game::playerStopAutoWalk(uint32_t playerId)
  2768. {
  2769.     Player* player = getPlayerByID(playerId);
  2770.     if(!player || player->isRemoved())
  2771.         return false;
  2772.  
  2773.     player->stopWalk();
  2774.     return true;
  2775. }
  2776.  
  2777. bool Game::playerUseItemEx(uint32_t playerId, const Position& fromPos, int16_t fromStackpos, uint16_t fromSpriteId,
  2778.     const Position& toPos, int16_t toStackpos, uint16_t toSpriteId, bool isHotkey)
  2779. {
  2780.     Player* player = getPlayerByID(playerId);
  2781.     if(!player || player->isRemoved())
  2782.         return false;
  2783.  
  2784.     if(isHotkey && !g_config.getBool(ConfigManager::AIMBOT_HOTKEY_ENABLED))
  2785.         return false;
  2786.  
  2787.     Thing* thing = internalGetThing(player, fromPos, fromStackpos, fromSpriteId, STACKPOS_USEITEM);
  2788.     if(!thing)
  2789.     {
  2790.         player->sendCancelMessage(RET_NOTPOSSIBLE);
  2791.         return false;
  2792.     }
  2793.  
  2794.     Item* item = thing->getItem();
  2795.     if(!item || !item->isUsable())
  2796.     {
  2797.         player->sendCancelMessage(RET_CANNOTUSETHISOBJECT);
  2798.         return false;
  2799.     }
  2800.  
  2801.     Position walkToPos = fromPos;
  2802.     ReturnValue ret = g_actions->canUse(player, fromPos);
  2803.     if(ret == RET_NOERROR)
  2804.     {
  2805.         ret = g_actions->canUseEx(player, toPos, item);
  2806.         if(ret == RET_TOOFARAWAY)
  2807.         {
  2808.             if(!player->hasCustomFlag(PlayerCustomFlag_CanUseFar))
  2809.                 walkToPos = toPos;
  2810.             else
  2811.                 ret = RET_NOERROR;
  2812.         }
  2813.     }
  2814.  
  2815.     if(ret != RET_NOERROR)
  2816.     {
  2817.         if(ret == RET_TOOFARAWAY)
  2818.         {
  2819.             Position itemPos = fromPos;
  2820.             if(fromPos.x != 0xFFFF && toPos.x != 0xFFFF && Position::areInRange<1,1,0>(fromPos,
  2821.                 player->getPosition()) && !Position::areInRange<1,1,0>(fromPos, toPos))
  2822.             {
  2823.                 Item* moveItem = NULL;
  2824.                 ReturnValue retTmp = internalMoveItem(player, item->getParent(), player,
  2825.                     INDEX_WHEREEVER, item, item->getItemCount(), &moveItem);
  2826.                 if(retTmp != RET_NOERROR)
  2827.                 {
  2828.                     player->sendCancelMessage(retTmp);
  2829.                     return false;
  2830.                 }
  2831.  
  2832.                 //changing the position since its now in the inventory of the player
  2833.                 internalGetPosition(moveItem, itemPos, fromStackpos);
  2834.             }
  2835.  
  2836.             if(player->getNoMove())
  2837.             {
  2838.                 player->sendCancelMessage(RET_NOTPOSSIBLE);
  2839.                 return false;
  2840.             }
  2841.  
  2842.             std::list<Direction> listDir;
  2843.             if(getPathToEx(player, walkToPos, listDir, 0, 1, true, true, 10))
  2844.             {
  2845.                 Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
  2846.                     this, player->getID(), listDir)));
  2847.  
  2848.                 SchedulerTask* task = createSchedulerTask(std::max((int64_t)SCHEDULER_MINTICKS, player->getStepDuration()),
  2849.                     boost::bind(&Game::playerUseItemEx, this, playerId, itemPos, fromStackpos, fromSpriteId, toPos, toStackpos, toSpriteId, isHotkey));
  2850.  
  2851.                 player->setNextWalkActionTask(task);
  2852.                 return true;
  2853.             }
  2854.  
  2855.             ret = RET_THEREISNOWAY;
  2856.         }
  2857.  
  2858.         player->sendCancelMessage(ret);
  2859.         return false;
  2860.     }
  2861.  
  2862.     if(isHotkey)
  2863.         showHotkeyUseMessage(player, item);
  2864.  
  2865.     if(!player->canDoAction())
  2866.     {
  2867.         SchedulerTask* task = createSchedulerTask(player->getNextActionTime(),
  2868.             boost::bind(&Game::playerUseItemEx, this, playerId, fromPos, fromStackpos, fromSpriteId, toPos, toStackpos, toSpriteId, isHotkey));
  2869.         player->setNextActionTask(task);
  2870.         return false;
  2871.     }
  2872.  
  2873.     player->setIdleTime(0);
  2874.     player->setNextActionTask(NULL);
  2875.     return g_actions->useItemEx(player, fromPos, toPos, toStackpos, item, isHotkey);
  2876. }
  2877.  
  2878. bool Game::playerUseItem(uint32_t playerId, const Position& pos, int16_t stackpos,
  2879.     uint8_t index, uint16_t spriteId, bool isHotkey)
  2880. {
  2881.     Player* player = getPlayerByID(playerId);
  2882.     if(!player || player->isRemoved())
  2883.         return false;
  2884.  
  2885.     if(isHotkey && !g_config.getBool(ConfigManager::AIMBOT_HOTKEY_ENABLED))
  2886.         return false;
  2887.  
  2888.     Thing* thing = internalGetThing(player, pos, stackpos, spriteId, STACKPOS_USEITEM);
  2889.     if(!thing)
  2890.     {
  2891.         player->sendCancelMessage(RET_NOTPOSSIBLE);
  2892.         return false;
  2893.     }
  2894.  
  2895.     Item* item = thing->getItem();
  2896.     if(!item || item->isUsable())
  2897.     {
  2898.         player->sendCancelMessage(RET_CANNOTUSETHISOBJECT);
  2899.         return false;
  2900.     }
  2901.  
  2902.     ReturnValue ret = g_actions->canUse(player, pos);
  2903.     if(ret == RET_TOOFARAWAY && player->hasCustomFlag(PlayerCustomFlag_CanUseFar))
  2904.         ret = RET_NOERROR;
  2905.  
  2906.     if(ret != RET_NOERROR)
  2907.     {
  2908.         if(ret == RET_TOOFARAWAY)
  2909.         {
  2910.             if(player->getNoMove())
  2911.             {
  2912.                 player->sendCancelMessage(RET_NOTPOSSIBLE);
  2913.                 return false;
  2914.             }
  2915.  
  2916.             std::list<Direction> listDir;
  2917.             if(getPathToEx(player, pos, listDir, 0, 1, true, true))
  2918.             {
  2919.                 Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
  2920.                     this, player->getID(), listDir)));
  2921.  
  2922.                 SchedulerTask* task = createSchedulerTask(std::max((int64_t)SCHEDULER_MINTICKS, player->getStepDuration()),
  2923.                     boost::bind(&Game::playerUseItem, this, playerId, pos, stackpos, index, spriteId, isHotkey));
  2924.  
  2925.                 player->setNextWalkActionTask(task);
  2926.                 return true;
  2927.             }
  2928.  
  2929.             ret = RET_THEREISNOWAY;
  2930.         }
  2931.  
  2932.         player->sendCancelMessage(ret);
  2933.         return false;
  2934.     }
  2935.  
  2936.     if(isHotkey)
  2937.         showHotkeyUseMessage(player, item);
  2938.  
  2939.     if(!player->canDoAction())
  2940.     {
  2941.         SchedulerTask* task = createSchedulerTask(player->getNextActionTime(),
  2942.             boost::bind(&Game::playerUseItem, this, playerId, pos, stackpos, index, spriteId, isHotkey));
  2943.         player->setNextActionTask(task);
  2944.         return false;
  2945.     }
  2946.  
  2947.     player->setIdleTime(0);
  2948.     player->setNextActionTask(NULL);
  2949.     return g_actions->useItem(player, pos, index, item);
  2950. }
  2951.  
  2952. bool Game::playerUseBattleWindow(uint32_t playerId, const Position& pos, int16_t stackpos,
  2953.     uint32_t creatureId, uint16_t spriteId, bool isHotkey)
  2954. {
  2955.     Player* player = getPlayerByID(playerId);
  2956.     if(!player || player->isRemoved())
  2957.         return false;
  2958.  
  2959.     Creature* creature = getCreatureByID(creatureId);
  2960.     if(!creature)
  2961.         return false;
  2962.  
  2963.     if(!Position::areInRange<7,5,0>(creature->getPosition(), player->getPosition()))
  2964.         return false;
  2965.  
  2966.     if(!g_config.getBool(ConfigManager::AIMBOT_HOTKEY_ENABLED) && (creature->getPlayer() || isHotkey))
  2967.     {
  2968.         player->sendCancelMessage(RET_DIRECTPLAYERSHOOT);
  2969.         return false;
  2970.     }
  2971.  
  2972.     Thing* thing = internalGetThing(player, pos, stackpos, spriteId, STACKPOS_USE);
  2973.     if(!thing)
  2974.     {
  2975.         player->sendCancelMessage(RET_NOTPOSSIBLE);
  2976.         return false;
  2977.     }
  2978.  
  2979.     Item* item = thing->getItem();
  2980.     if(!item || item->getClientID() != spriteId)
  2981.     {
  2982.         player->sendCancelMessage(RET_CANNOTUSETHISOBJECT);
  2983.         return false;
  2984.     }
  2985.  
  2986.     ReturnValue ret = g_actions->canUse(player, pos);
  2987.     if(ret != RET_NOERROR)
  2988.     {
  2989.         if(ret == RET_TOOFARAWAY)
  2990.         {
  2991.             if(player->getNoMove())
  2992.             {
  2993.                 player->sendCancelMessage(RET_NOTPOSSIBLE);
  2994.                 return false;
  2995.             }
  2996.  
  2997.             std::list<Direction> listDir;
  2998.             if(getPathToEx(player, item->getPosition(), listDir, 0, 1, true, true))
  2999.             {
  3000.                 Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
  3001.                     this, player->getID(), listDir)));
  3002.  
  3003.                 SchedulerTask* task = createSchedulerTask(std::max((int64_t)SCHEDULER_MINTICKS, player->getStepDuration()),
  3004.                     boost::bind(&Game::playerUseBattleWindow, this, playerId, pos, stackpos, creatureId, spriteId, isHotkey));
  3005.  
  3006.                 player->setNextWalkActionTask(task);
  3007.                 return true;
  3008.             }
  3009.  
  3010.             ret = RET_THEREISNOWAY;
  3011.         }
  3012.  
  3013.         player->sendCancelMessage(ret);
  3014.         return false;
  3015.     }
  3016.  
  3017.     if(isHotkey)
  3018.         showHotkeyUseMessage(player, item);
  3019.  
  3020.     if(!player->canDoAction())
  3021.     {
  3022.         SchedulerTask* task = createSchedulerTask(player->getNextActionTime(),
  3023.             boost::bind(&Game::playerUseBattleWindow, this, playerId, pos, stackpos, creatureId, spriteId, isHotkey));
  3024.         player->setNextActionTask(task);
  3025.         return false;
  3026.     }
  3027.  
  3028.     player->setIdleTime(0);
  3029.     player->setNextActionTask(NULL);
  3030.     return g_actions->useItemEx(player, pos, creature->getPosition(),
  3031.         creature->getParent()->__getIndexOfThing(creature), item, isHotkey, creatureId);
  3032. }
  3033.  
  3034. bool Game::playerCloseContainer(uint32_t playerId, uint8_t cid)
  3035. {
  3036.     Player* player = getPlayerByID(playerId);
  3037.     if(!player || player->isRemoved())
  3038.         return false;
  3039.  
  3040.     player->closeContainer(cid);
  3041.     player->sendCloseContainer(cid);
  3042.     return true;
  3043. }
  3044.  
  3045. bool Game::playerMoveUpContainer(uint32_t playerId, uint8_t cid)
  3046. {
  3047.     Player* player = getPlayerByID(playerId);
  3048.     if(!player || player->isRemoved())
  3049.         return false;
  3050.  
  3051.     Container* container = player->getContainer(cid);
  3052.     if(!container)
  3053.         return false;
  3054.  
  3055.     Container* parentContainer = dynamic_cast<Container*>(container->getParent());
  3056.     if(!parentContainer)
  3057.         return false;
  3058.  
  3059.     player->addContainer(cid, parentContainer);
  3060.     player->sendContainer(cid, parentContainer, (dynamic_cast<const Container*>(parentContainer->getParent()) != NULL));
  3061.     return true;
  3062. }
  3063.  
  3064. bool Game::playerUpdateTile(uint32_t playerId, const Position& pos)
  3065. {
  3066.     Player* player = getPlayerByID(playerId);
  3067.     if(!player || player->isRemoved())
  3068.         return false;
  3069.  
  3070.     if(!player->canSee(pos))
  3071.         return false;
  3072.  
  3073.     if(Tile* tile = getTile(pos))
  3074.         player->sendUpdateTile(tile, pos);
  3075.  
  3076.     return true;
  3077. }
  3078.  
  3079. bool Game::playerUpdateContainer(uint32_t playerId, uint8_t cid)
  3080. {
  3081.     Player* player = getPlayerByID(playerId);
  3082.     if(!player || player->isRemoved())
  3083.         return false;
  3084.  
  3085.     Container* container = player->getContainer(cid);
  3086.     if(!container)
  3087.         return false;
  3088.  
  3089.     player->sendContainer(cid, container, (dynamic_cast<const Container*>(container->getParent()) != NULL));
  3090.     return true;
  3091. }
  3092.  
  3093. bool Game::playerRotateItem(uint32_t playerId, const Position& pos, int16_t stackpos, const uint16_t spriteId)
  3094. {
  3095.     Player* player = getPlayerByID(playerId);
  3096.     if(!player || player->isRemoved())
  3097.         return false;
  3098.  
  3099.     Thing* thing = internalGetThing(player, pos, stackpos);
  3100.     if(!thing)
  3101.         return false;
  3102.  
  3103.     Item* item = thing->getItem();
  3104.     if(!item || item->getClientID() != spriteId || !item->isRoteable() || (item->isLoadedFromMap() &&
  3105.         (item->getUniqueId() || (item->getActionId() && item->getContainer()))))
  3106.     {
  3107.         player->sendCancelMessage(RET_NOTPOSSIBLE);
  3108.         return false;
  3109.     }
  3110.  
  3111.     if(pos.x != 0xFFFF && !Position::areInRange<1,1,0>(pos, player->getPosition()))
  3112.     {
  3113.         if(player->getNoMove())
  3114.         {
  3115.             player->sendCancelMessage(RET_NOTPOSSIBLE);
  3116.             return false;
  3117.         }
  3118.  
  3119.         std::list<Direction> listDir;
  3120.         if(getPathToEx(player, pos, listDir, 0, 1, true, true))
  3121.         {
  3122.             Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
  3123.                 this, player->getID(), listDir)));
  3124.  
  3125.             SchedulerTask* task = createSchedulerTask(std::max((int64_t)SCHEDULER_MINTICKS, player->getStepDuration()),
  3126.                 boost::bind(&Game::playerRotateItem, this, playerId, pos, stackpos, spriteId));
  3127.  
  3128.             player->setNextWalkActionTask(task);
  3129.             return true;
  3130.         }
  3131.  
  3132.         player->sendCancelMessage(RET_THEREISNOWAY);
  3133.         return false;
  3134.     }
  3135.  
  3136.     uint16_t newId = Item::items[item->getID()].rotateTo;
  3137.     if(newId)
  3138.         transformItem(item, newId);
  3139.  
  3140.     return true;
  3141. }
  3142.  
  3143. bool Game::playerWriteItem(uint32_t playerId, uint32_t windowTextId, const std::string& text)
  3144. {
  3145.     Player* player = getPlayerByID(playerId);
  3146.     if(!player || player->isRemoved())
  3147.         return false;
  3148.  
  3149.     uint16_t maxTextLength = 0;
  3150.     uint32_t internalWindowTextId = 0;
  3151.  
  3152.     Item* writeItem = player->getWriteItem(internalWindowTextId, maxTextLength);
  3153.     if(text.length() > maxTextLength || windowTextId != internalWindowTextId)
  3154.         return false;
  3155.  
  3156.     if(!writeItem || writeItem->isRemoved())
  3157.     {
  3158.         player->sendCancelMessage(RET_NOTPOSSIBLE);
  3159.         return false;
  3160.     }
  3161.  
  3162.     Cylinder* topParent = writeItem->getTopParent();
  3163.     Player* owner = dynamic_cast<Player*>(topParent);
  3164.     if(owner && owner != player)
  3165.     {
  3166.         player->sendCancelMessage(RET_NOTPOSSIBLE);
  3167.         return false;
  3168.     }
  3169.  
  3170.     if(!Position::areInRange<1,1,0>(writeItem->getPosition(), player->getPosition()))
  3171.     {
  3172.         player->sendCancelMessage(RET_NOTPOSSIBLE);
  3173.         return false;
  3174.     }
  3175.  
  3176.     bool deny = false;
  3177.     CreatureEventList textEditEvents = player->getCreatureEvents(CREATURE_EVENT_TEXTEDIT);
  3178.     for(CreatureEventList::iterator it = textEditEvents.begin(); it != textEditEvents.end(); ++it)
  3179.     {
  3180.         if(!(*it)->executeTextEdit(player, writeItem, text))
  3181.             deny = true;
  3182.     }
  3183.  
  3184.     player->setWriteItem(NULL);
  3185.     if((Container*)writeItem->getParent() == &player->transferContainer)
  3186.     {
  3187.         player->transferContainer.setParent(NULL);
  3188.         player->transferContainer.__removeThing(writeItem, writeItem->getItemCount());
  3189.  
  3190.         freeThing(writeItem);
  3191.         return true;
  3192.     }
  3193.  
  3194.     if(deny)
  3195.         return false;
  3196.  
  3197.     if(!text.empty())
  3198.     {
  3199.         if(writeItem->getText() != text)
  3200.         {
  3201.             writeItem->setText(text);
  3202.             writeItem->setWriter(player->getName());
  3203.             writeItem->setDate(std::time(NULL));
  3204.         }
  3205.     }
  3206.     else
  3207.     {
  3208.         writeItem->resetText();
  3209.         writeItem->resetWriter();
  3210.         writeItem->resetDate();
  3211.     }
  3212.  
  3213.     uint16_t newId = Item::items[writeItem->getID()].writeOnceItemId;
  3214.     if(newId)
  3215.         transformItem(writeItem, newId);
  3216.  
  3217.     return true;
  3218. }
  3219.  
  3220. bool Game::playerUpdateHouseWindow(uint32_t playerId, uint8_t listId, uint32_t windowTextId, const std::string& text)
  3221. {
  3222.     Player* player = getPlayerByID(playerId);
  3223.     if(!player || player->isRemoved())
  3224.         return false;
  3225.  
  3226.     uint32_t internalWindowTextId = 0, internalListId = 0;
  3227.     House* house = player->getEditHouse(internalWindowTextId, internalListId);
  3228.     if(!house || internalWindowTextId != windowTextId || listId)
  3229.         return true;
  3230.  
  3231.     bool deny = false;
  3232.     CreatureEventList houseEditEvents = player->getCreatureEvents(CREATURE_EVENT_HOUSEEDIT);
  3233.     for(CreatureEventList::iterator it = houseEditEvents.begin(); it != houseEditEvents.end(); ++it)
  3234.     {
  3235.         if(!(*it)->executeHouseEdit(player, house->getId(), internalListId, text))
  3236.             deny = true;
  3237.     }
  3238.  
  3239.     player->setEditHouse(NULL);
  3240.     if(deny)
  3241.         return false;
  3242.  
  3243.     house->setAccessList(internalListId, text);
  3244.     return true;
  3245. }
  3246.  
  3247. bool Game::playerRequestTrade(uint32_t playerId, const Position& pos, int16_t stackpos,
  3248.     uint32_t tradePlayerId, uint16_t spriteId)
  3249. {
  3250.     Player* player = getPlayerByID(playerId);
  3251.     if(!player || player->isRemoved())
  3252.         return false;
  3253.  
  3254.     if(player->hasCondition(CONDITION_EXHAUST, EXHAUST_PLAYERTRADE))
  3255.     {
  3256.         player->sendTextMessage(MSG_STATUS_SMALL, "You have to wait a bit before you can trade again.");
  3257.         return false;
  3258.     }
  3259.  
  3260.     if(Condition* conditiontrade = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 1000, 0, false, EXHAUST_PLAYERTRADE))
  3261.         player->addCondition(conditiontrade);
  3262.  
  3263.     Player* tradePartner = getPlayerByID(tradePlayerId);
  3264.     if(!tradePartner || tradePartner == player)
  3265.     {
  3266.         player->sendCancelMessage(RET_NOTPOSSIBLE);
  3267.         return false;
  3268.     }
  3269.  
  3270.     if(!Position::areInRange<2,2,0>(tradePartner->getPosition(), player->getPosition()))
  3271.     {
  3272.         player->sendCancelMessage(RET_DESTINATIONOUTOFREACH);
  3273.         return false;
  3274.     }
  3275.  
  3276.     if(!canThrowObjectTo(tradePartner->getPosition(), player->getPosition())
  3277.         && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
  3278.     {
  3279.         player->sendCancelMessage(RET_CANNOTTHROW);
  3280.         return false;
  3281.     }
  3282.  
  3283.     Item* tradeItem = dynamic_cast<Item*>(internalGetThing(player, pos, stackpos, spriteId, STACKPOS_USE));
  3284.     if(!tradeItem || tradeItem->getClientID() != spriteId || !tradeItem->isPickupable() || (tradeItem->isLoadedFromMap()
  3285.         && (tradeItem->getUniqueId() || (tradeItem->getActionId() && tradeItem->getContainer()))))
  3286.     {
  3287.         player->sendCancelMessage(RET_NOTPOSSIBLE);
  3288.         return false;
  3289.     }
  3290.  
  3291.     if(player->getPosition().z > tradeItem->getPosition().z)
  3292.     {
  3293.         player->sendCancelMessage(RET_FIRSTGOUPSTAIRS);
  3294.         return false;
  3295.     }
  3296.  
  3297.     if(player->getPosition().z < tradeItem->getPosition().z)
  3298.     {
  3299.         player->sendCancelMessage(RET_FIRSTGODOWNSTAIRS);
  3300.         return false;
  3301.     }
  3302.  
  3303.     HouseTile* houseTile = dynamic_cast<HouseTile*>(tradeItem->getParent());
  3304.     if(houseTile && houseTile->getHouse() && !houseTile->getHouse()->isInvited(player))
  3305.     {
  3306.         player->sendCancelMessage(RET_PLAYERISNOTINVITED);
  3307.         return false;
  3308.     }
  3309.  
  3310.     if(!Position::areInRange<1,1,0>(tradeItem->getPosition(), player->getPosition()))
  3311.     {
  3312.         if(player->getNoMove())
  3313.         {
  3314.             player->sendCancelMessage(RET_NOTPOSSIBLE);
  3315.             return false;
  3316.         }
  3317.  
  3318.         std::list<Direction> listDir;
  3319.         if(getPathToEx(player, pos, listDir, 0, 1, true, true))
  3320.         {
  3321.             Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
  3322.                 this, player->getID(), listDir)));
  3323.  
  3324.             SchedulerTask* task = createSchedulerTask(std::max((int64_t)SCHEDULER_MINTICKS, player->getStepDuration()),
  3325.                 boost::bind(&Game::playerRequestTrade, this, playerId, pos, stackpos, tradePlayerId, spriteId));
  3326.  
  3327.             player->setNextWalkActionTask(task);
  3328.             return true;
  3329.         }
  3330.  
  3331.         player->sendCancelMessage(RET_THEREISNOWAY);
  3332.         return false;
  3333.     }
  3334.  
  3335.     const Container* container = NULL;
  3336.     for(std::map<Item*, uint32_t>::const_iterator it = tradeItems.begin(); it != tradeItems.end(); ++it)
  3337.     {
  3338.         if(tradeItem == it->first ||
  3339.             ((container = dynamic_cast<const Container*>(tradeItem)) && container->isHoldingItem(it->first)) ||
  3340.             ((container = dynamic_cast<const Container*>(it->first)) && container->isHoldingItem(tradeItem)))
  3341.         {
  3342.             player->sendCancelMessage(RET_YOUAREALREADYTRADING);
  3343.             return false;
  3344.         }
  3345.     }
  3346.  
  3347.     Container* tradeContainer = tradeItem->getContainer();
  3348.     if(tradeContainer && tradeContainer->getItemHoldingCount() + 1 > (uint32_t)g_config.getNumber(ConfigManager::TRADE_LIMIT))
  3349.     {
  3350.         player->sendCancelMessage(RET_YOUCANONLYTRADEUPTOX);
  3351.         return false;
  3352.     }
  3353.  
  3354.     bool deny = false;
  3355.     CreatureEventList tradeEvents = player->getCreatureEvents(CREATURE_EVENT_TRADE_REQUEST);
  3356.     for(CreatureEventList::iterator it = tradeEvents.begin(); it != tradeEvents.end(); ++it)
  3357.     {
  3358.         if(!(*it)->executeTradeRequest(player, tradePartner, tradeItem))
  3359.             deny = true;
  3360.     }
  3361.  
  3362.     if(deny)
  3363.         return false;
  3364.  
  3365.     return internalStartTrade(player, tradePartner, tradeItem);
  3366. }
  3367.  
  3368. bool Game::internalStartTrade(Player* player, Player* tradePartner, Item* tradeItem)
  3369. {
  3370.     if(player->tradeState != TRADE_NONE && !(player->tradeState == TRADE_ACKNOWLEDGE && player->tradePartner == tradePartner))
  3371.     {
  3372.         player->sendCancelMessage(RET_YOUAREALREADYTRADING);
  3373.         return false;
  3374.     }
  3375.     else if(tradePartner->tradeState != TRADE_NONE && tradePartner->tradePartner != player)
  3376.     {
  3377.         player->sendCancelMessage(RET_THISPLAYERISALREADYTRADING);
  3378.         return false;
  3379.     }
  3380.  
  3381.     player->tradePartner = tradePartner;
  3382.     player->tradeItem = tradeItem;
  3383.     player->tradeState = TRADE_INITIATED;
  3384.  
  3385.     tradeItem->addRef();
  3386.     tradeItems[tradeItem] = player->getID();
  3387.  
  3388.     player->sendTradeItemRequest(player, tradeItem, true);
  3389.     if(tradePartner->tradeState == TRADE_NONE)
  3390.     {
  3391.         char buffer[100];
  3392.         sprintf(buffer, "%s wants to trade with you", player->getName().c_str());
  3393.         tradePartner->sendTextMessage(MSG_EVENT_ADVANCE, buffer);
  3394.  
  3395.         tradePartner->tradeState = TRADE_ACKNOWLEDGE;
  3396.         tradePartner->tradePartner = player;
  3397.     }
  3398.     else
  3399.     {
  3400.         Item* counterItem = tradePartner->tradeItem;
  3401.         player->sendTradeItemRequest(tradePartner, counterItem, false);
  3402.         tradePartner->sendTradeItemRequest(player, tradeItem, false);
  3403.     }
  3404.  
  3405.     return true;
  3406. }
  3407.  
  3408. void Game::playerAcceptTrade(uint32_t playerId)
  3409. {
  3410.     Player* player = getPlayerByID(playerId);
  3411.     if(!player)
  3412.     {
  3413.         return;
  3414.     }
  3415.  
  3416.     if(!(player->getTradeState() == TRADE_ACKNOWLEDGE || player->getTradeState() == TRADE_INITIATED))
  3417.     {
  3418.         return;
  3419.     }
  3420.  
  3421.     Player* tradePartner = player->tradePartner;
  3422.     if(!tradePartner)
  3423.     {
  3424.         return;
  3425.     }
  3426.  
  3427.     if(!canThrowObjectTo(tradePartner->getPosition(), player->getPosition()))
  3428.     {
  3429.         player->sendCancelMessage(RET_CREATUREISNOTREACHABLE);
  3430.         return;
  3431.     }
  3432.  
  3433.     player->setTradeState(TRADE_ACCEPT);
  3434.  
  3435.     if(tradePartner->getTradeState() == TRADE_ACCEPT)
  3436.     {
  3437.         Item* tradeItem1 = player->tradeItem;
  3438.         Item* tradeItem2 = tradePartner->tradeItem;
  3439.  
  3440.         bool deny = false;
  3441.         CreatureEventList tradeEvents = player->getCreatureEvents(CREATURE_EVENT_TRADE_ACCEPT);
  3442.         for(CreatureEventList::iterator it = tradeEvents.begin(); it != tradeEvents.end(); ++it)
  3443.         {
  3444.             if(!(*it)->executeTradeAccept(player, tradePartner, tradeItem1, tradeItem2))
  3445.                 deny = true;
  3446.         }
  3447.  
  3448.         if(deny)
  3449.             return;
  3450.  
  3451.         player->setTradeState(TRADE_TRANSFER);
  3452.         tradePartner->setTradeState(TRADE_TRANSFER);
  3453.  
  3454.         std::map<Item*, uint32_t>::iterator it = tradeItems.find(tradeItem1);
  3455.         if(it != tradeItems.end())
  3456.         {
  3457.             freeThing(it->first);
  3458.             tradeItems.erase(it);
  3459.         }
  3460.  
  3461.         it = tradeItems.find(tradeItem2);
  3462.         if(it != tradeItems.end())
  3463.         {
  3464.             freeThing(it->first);
  3465.             tradeItems.erase(it);
  3466.         }
  3467.  
  3468.         bool isSuccess = false;
  3469.  
  3470.         ReturnValue ret1 = internalAddItem(player, tradePartner, tradeItem1, INDEX_WHEREEVER, 0, true);
  3471.         ReturnValue ret2 = internalAddItem(tradePartner, player, tradeItem2, INDEX_WHEREEVER, 0, true);
  3472.         if(ret1 == RET_NOERROR && ret2 == RET_NOERROR)
  3473.         {
  3474.             ret1 = internalRemoveItem(tradePartner, tradeItem1, tradeItem1->getItemCount(), true);
  3475.             ret2 = internalRemoveItem(player, tradeItem2, tradeItem2->getItemCount(), true);
  3476.             if(ret1 == RET_NOERROR && ret2 == RET_NOERROR)
  3477.             {
  3478.                 Cylinder* cylinder1 = tradeItem1->getParent();
  3479.                 Cylinder* cylinder2 = tradeItem2->getParent();
  3480.  
  3481.                 uint32_t count1 = tradeItem1->getItemCount();
  3482.                 uint32_t count2 = tradeItem2->getItemCount();
  3483.  
  3484.                 ret1 = internalMoveItem(NULL, cylinder1, tradePartner, INDEX_WHEREEVER, tradeItem1, count1, NULL, FLAG_IGNOREAUTOSTACK);
  3485.                 if(ret1 == RET_NOERROR)
  3486.                 {
  3487.                     internalMoveItem(NULL, cylinder2, player, INDEX_WHEREEVER, tradeItem2, count2, NULL, FLAG_IGNOREAUTOSTACK);
  3488.  
  3489.                     tradeItem1->onTradeEvent(ON_TRADE_TRANSFER, tradePartner, player);
  3490.                     tradeItem2->onTradeEvent(ON_TRADE_TRANSFER, player, tradePartner);
  3491.  
  3492.                     isSuccess = true;
  3493.                 }
  3494.             }
  3495.         }
  3496.  
  3497.         if(!isSuccess)
  3498.         {
  3499.             std::string errorDescription;
  3500.  
  3501.             if(tradePartner->tradeItem)
  3502.             {
  3503.                 errorDescription = getTradeErrorDescription(ret1, tradeItem1);
  3504.                 tradePartner->sendTextMessage(MSG_EVENT_ADVANCE, errorDescription);
  3505.                 tradeItem2->onTradeEvent(ON_TRADE_CANCEL, tradePartner, player);
  3506.             }
  3507.  
  3508.             if(player->tradeItem)
  3509.             {
  3510.                 errorDescription = getTradeErrorDescription(ret2, tradeItem2);
  3511.                 player->sendTextMessage(MSG_EVENT_ADVANCE, errorDescription);
  3512.                 tradeItem1->onTradeEvent(ON_TRADE_CANCEL, player, tradePartner);
  3513.             }
  3514.         }
  3515.  
  3516.         player->setTradeState(TRADE_NONE);
  3517.         player->tradeItem = NULL;
  3518.         player->tradePartner = NULL;
  3519.         player->sendTradeClose();
  3520.  
  3521.         tradePartner->setTradeState(TRADE_NONE);
  3522.         tradePartner->tradeItem = NULL;
  3523.         tradePartner->tradePartner = NULL;
  3524.         tradePartner->sendTradeClose();
  3525.     }
  3526. }
  3527.  
  3528. std::string Game::getTradeErrorDescription(ReturnValue ret, Item* item)
  3529. {
  3530.     if(!item)
  3531.         return std::string();
  3532.  
  3533.     std::ostringstream ss;
  3534.     if(ret == RET_NOTENOUGHCAPACITY)
  3535.     {
  3536.         ss << "You do not have enough capacity to carry";
  3537.         if(item->isStackable() && item->getItemCount() > 1)
  3538.             ss << " these objects.";
  3539.         else
  3540.             ss << " this object." ;
  3541.  
  3542.         ss << std::endl << " " << item->getWeightDescription();
  3543.     }
  3544.     else if(ret == RET_NOTENOUGHROOM || ret == RET_CONTAINERNOTENOUGHROOM)
  3545.     {
  3546.         ss << "You do not have enough room to carry";
  3547.         if(item->isStackable() && item->getItemCount() > 1)
  3548.             ss << " these objects.";
  3549.         else
  3550.             ss << " this object.";
  3551.     }
  3552.     else
  3553.         ss << "Trade could not be completed.";
  3554.  
  3555.     return ss.str();
  3556. }
  3557.  
  3558. bool Game::playerLookInTrade(uint32_t playerId, bool lookAtCounterOffer, int32_t index)
  3559. {
  3560.     Player* player = getPlayerByID(playerId);
  3561.     if(!player || player->isRemoved())
  3562.         return false;
  3563.  
  3564.     Player* tradePartner = player->tradePartner;
  3565.     if(!tradePartner)
  3566.         return false;
  3567.    
  3568.     if (player->hasCondition(CONDITION_EXHAUST, EXHAUST_PLAYERLOOKTRADE))
  3569.     {
  3570.         player->sendTextMessage(MSG_STATUS_SMALL, "You have to wait a bit before doing this again.");
  3571.         return false;
  3572.     }
  3573.  
  3574.     if (Condition* conditionlook = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 200, 0, false, EXHAUST_PLAYERLOOKTRADE))
  3575.         player->addCondition(conditionlook);
  3576.  
  3577.     Item* tradeItem = NULL;
  3578.     if(lookAtCounterOffer)
  3579.         tradeItem = tradePartner->getTradeItem();
  3580.     else
  3581.         tradeItem = player->getTradeItem();
  3582.  
  3583.     if(!tradeItem)
  3584.         return false;
  3585.  
  3586.     std::ostringstream ss;
  3587.     ss << "You see ";
  3588.  
  3589.     int32_t lookDistance = std::max(std::abs(player->getPosition().x - tradeItem->getPosition().x),
  3590.         std::abs(player->getPosition().y - tradeItem->getPosition().y));
  3591.     if(!index)
  3592.     {
  3593.         ss << tradeItem->getDescription(lookDistance);
  3594.         if(player->hasCustomFlag(PlayerCustomFlag_CanSeeItemDetails))
  3595.         {
  3596.             ss << std::endl << "ItemID: [" << tradeItem->getID() << "]";
  3597.             if(tradeItem->getActionId() > 0)
  3598.                 ss << ", ActionID: [" << tradeItem->getActionId() << "]";
  3599.  
  3600.             if(tradeItem->getUniqueId() > 0)
  3601.                 ss << ", UniqueID: [" << tradeItem->getUniqueId() << "]";
  3602.  
  3603.             ss << ".";
  3604.             const ItemType& it = Item::items[tradeItem->getID()];
  3605.             if(it.transformEquipTo)
  3606.                 ss << std::endl << "TransformTo (onEquip): [" << it.transformEquipTo << "]";
  3607.             else if(it.transformDeEquipTo)
  3608.                 ss << std::endl << "TransformTo (onDeEquip): [" << it.transformDeEquipTo << "]";
  3609.             else if(it.decayTo != -1)
  3610.                 ss << std::endl << "DecayTo: [" << it.decayTo << "]";
  3611.         }
  3612.  
  3613.         player->sendTextMessage(MSG_INFO_DESCR, ss.str());
  3614.         return false;
  3615.     }
  3616.  
  3617.     Container* tradeContainer = tradeItem->getContainer();
  3618.     if(!tradeContainer || index > (int32_t)tradeContainer->getItemHoldingCount())
  3619.         return false;
  3620.  
  3621.     std::list<const Container*> listContainer;
  3622.     listContainer.push_back(tradeContainer);
  3623.     ItemList::const_iterator it;
  3624.  
  3625.     Container* tmpContainer = NULL;
  3626.     while(listContainer.size() > 0)
  3627.     {
  3628.         const Container* container = listContainer.front();
  3629.         listContainer.pop_front();
  3630.         for(it = container->getItems(); it != container->getEnd(); ++it)
  3631.         {
  3632.             if((tmpContainer = (*it)->getContainer()))
  3633.                 listContainer.push_back(tmpContainer);
  3634.  
  3635.             --index;
  3636.             if(index)
  3637.                 continue;
  3638.  
  3639.             ss << (*it)->getDescription(lookDistance);
  3640.             if(player->hasCustomFlag(PlayerCustomFlag_CanSeeItemDetails))
  3641.             {
  3642.                 ss << std::endl << "ItemID: [" << (*it)->getID() << "]";
  3643.                 if((*it)->getActionId() > 0)
  3644.                     ss << ", ActionID: [" << (*it)->getActionId() << "]";
  3645.  
  3646.                 if((*it)->getUniqueId() > 0)
  3647.                     ss << ", UniqueID: [" << (*it)->getUniqueId() << "]";
  3648.  
  3649.                 ss << ".";
  3650.                 const ItemType& iit = Item::items[(*it)->getID()];
  3651.                 if(iit.transformEquipTo)
  3652.                     ss << std::endl << "TransformTo: [" << iit.transformEquipTo << "] (onEquip).";
  3653.                 else if(iit.transformDeEquipTo)
  3654.                     ss << std::endl << "TransformTo: [" << iit.transformDeEquipTo << "] (onDeEquip).";
  3655.                 else if(iit.decayTo != -1)
  3656.                     ss << std::endl << "DecayTo: [" << iit.decayTo << "].";
  3657.             }
  3658.  
  3659.             player->sendTextMessage(MSG_INFO_DESCR, ss.str());
  3660.             return true;
  3661.         }
  3662.     }
  3663.  
  3664.     return false;
  3665. }
  3666.  
  3667. bool Game::playerCloseTrade(uint32_t playerId)
  3668. {
  3669.     Player* player = getPlayerByID(playerId);
  3670.     if(!player || player->isRemoved())
  3671.         return false;
  3672.  
  3673.     return internalCloseTrade(player);
  3674. }
  3675.  
  3676. bool Game::internalCloseTrade(Player* player)
  3677. {
  3678.     Player* tradePartner = player->tradePartner;
  3679.     if((tradePartner && tradePartner->getTradeState() == TRADE_TRANSFER) || player->getTradeState() == TRADE_TRANSFER)
  3680.     {
  3681.         std::clog << "[Warning - Game::internalCloseTrade] TradeState == TRADE_TRANSFER, " <<
  3682.             player->getName() << " " << player->getTradeState() << ", " <<
  3683.             tradePartner->getName() << " " << tradePartner->getTradeState() << std::endl;
  3684.         return true;
  3685.     }
  3686.  
  3687.     std::vector<Item*>::iterator it;
  3688.     if(player->getTradeItem())
  3689.     {
  3690.         std::map<Item*, uint32_t>::iterator it = tradeItems.find(player->getTradeItem());
  3691.         if(it != tradeItems.end())
  3692.         {
  3693.             freeThing(it->first);
  3694.             tradeItems.erase(it);
  3695.         }
  3696.  
  3697.         player->tradeItem->onTradeEvent(ON_TRADE_CANCEL, player, tradePartner);
  3698.         player->tradeItem = NULL;
  3699.     }
  3700.  
  3701.     player->setTradeState(TRADE_NONE);
  3702.     player->tradePartner = NULL;
  3703.  
  3704.     player->sendTextMessage(MSG_STATUS_SMALL, "Trade cancelled.");
  3705.     player->sendTradeClose();
  3706.     if(tradePartner)
  3707.     {
  3708.         if(tradePartner->getTradeItem())
  3709.         {
  3710.             std::map<Item*, uint32_t>::iterator it = tradeItems.find(tradePartner->getTradeItem());
  3711.             if(it != tradeItems.end())
  3712.             {
  3713.                 freeThing(it->first);
  3714.                 tradeItems.erase(it);
  3715.             }
  3716.  
  3717.             tradePartner->tradeItem->onTradeEvent(ON_TRADE_CANCEL, tradePartner, player);
  3718.             tradePartner->tradeItem = NULL;
  3719.         }
  3720.  
  3721.         tradePartner->setTradeState(TRADE_NONE);
  3722.         tradePartner->tradePartner = NULL;
  3723.  
  3724.         tradePartner->sendTextMessage(MSG_STATUS_SMALL, "Trade cancelled.");
  3725.         tradePartner->sendTradeClose();
  3726.     }
  3727.  
  3728.     return true;
  3729. }
  3730.  
  3731. bool Game::playerPurchaseItem(uint32_t playerId, uint16_t spriteId, uint8_t count, uint8_t amount,
  3732.     bool ignoreCap/* = false*/, bool inBackpacks/* = false*/)
  3733. {
  3734.     Player* player = getPlayerByID(playerId);
  3735.     if(!player || player->isRemoved())
  3736.         return false;
  3737.    
  3738.     if (player->hasCondition(CONDITION_EXHAUST, EXHAUST_PLAYERPURCHASEITEM))
  3739.     {
  3740.         player->sendTextMessage(MSG_STATUS_SMALL, "You have to wait a bit before buying again.");
  3741.         return false;
  3742.     }
  3743.  
  3744.     int32_t onBuy, onSell;
  3745.     Npc* merchant = player->getShopOwner(onBuy, onSell);
  3746.     if(!merchant)
  3747.         return false;
  3748.    
  3749.     if (Condition* conditionlook = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 200, 0, false, EXHAUST_PLAYERPURCHASEITEM))
  3750.         player->addCondition(conditionlook);
  3751.    
  3752.     const ItemType& it = Item::items.getItemIdByClientId(spriteId);
  3753.     if(!it.id)
  3754.         return false;
  3755.  
  3756.     uint8_t subType;
  3757.     if(it.isSplash() || it.isFluidContainer())
  3758.         subType = clientFluidToServer(count);
  3759.     else
  3760.         subType = count;
  3761.  
  3762.     if(!player->canShopItem(it.id, subType, SHOPEVENT_BUY))
  3763.         return false;
  3764.  
  3765.     merchant->onPlayerTrade(player, SHOPEVENT_BUY, onBuy, it.id, subType, amount, ignoreCap, inBackpacks);
  3766.     return true;
  3767. }
  3768.  
  3769. bool Game::playerSellItem(uint32_t playerId, uint16_t spriteId, uint8_t count, uint8_t amount, bool ignoreEquipped)
  3770. {
  3771.     Player* player = getPlayerByID(playerId);
  3772.     if(!player || player->isRemoved())
  3773.         return false;
  3774.    
  3775.     if (player->hasCondition(CONDITION_EXHAUST, EXHAUST_PLAYERSELLITEM))
  3776.     {
  3777.         player->sendTextMessage(MSG_STATUS_SMALL, "You have to wait a bit before selling again.");
  3778.         return false;
  3779.     }
  3780.    
  3781.     int32_t onBuy, onSell;
  3782.     Npc* merchant = player->getShopOwner(onBuy, onSell);
  3783.     if(!merchant)
  3784.         return false;
  3785.    
  3786.     if (Condition* conditionlook = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 200, 0, false, EXHAUST_PLAYERSELLITEM))
  3787.         player->addCondition(conditionlook);
  3788.    
  3789.     const ItemType& it = Item::items.getItemIdByClientId(spriteId);
  3790.     if(!it.id)
  3791.         return false;
  3792.  
  3793.     uint8_t subType;
  3794.     if(it.isSplash() || it.isFluidContainer())
  3795.         subType = clientFluidToServer(count);
  3796.     else
  3797.         subType = count;
  3798.  
  3799.     if(!player->canShopItem(it.id, subType, SHOPEVENT_SELL))
  3800.         return false;
  3801.  
  3802.     merchant->onPlayerTrade(player, SHOPEVENT_SELL, onSell, it.id, subType, amount, ignoreEquipped);
  3803.     return true;
  3804. }
  3805.  
  3806. bool Game::playerCloseShop(uint32_t playerId)
  3807. {
  3808.     Player* player = getPlayerByID(playerId);
  3809.     if(player == NULL || player->isRemoved())
  3810.         return false;
  3811.  
  3812.     player->closeShopWindow();
  3813.     return true;
  3814. }
  3815.  
  3816. bool Game::playerLookInShop(uint32_t playerId, uint16_t spriteId, uint8_t count)
  3817. {
  3818.     Player* player = getPlayerByID(playerId);
  3819.     if(player == NULL || player->isRemoved())
  3820.         return false;
  3821.    
  3822.     if (player->hasCondition(CONDITION_EXHAUST, EXHAUST_PLAYERLOOKSHOP))
  3823.     {
  3824.         player->sendTextMessage(MSG_STATUS_SMALL, "You have to wait a bit before doing this again.");
  3825.         return false;
  3826.     }
  3827.  
  3828.     if (Condition* conditionlook = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 200, 0, false, EXHAUST_PLAYERLOOKSHOP))
  3829.         player->addCondition(conditionlook);
  3830.  
  3831.     const ItemType& it = Item::items.getItemIdByClientId(spriteId);
  3832.     if(!it.id)
  3833.         return false;
  3834.  
  3835.     int32_t subType;
  3836.     if(it.isFluidContainer() || it.isSplash())
  3837.         subType = clientFluidToServer(count);
  3838.     else
  3839.         subType = count;
  3840.  
  3841.     std::ostringstream ss;
  3842.     ss << "You see " << Item::getDescription(it, 1, NULL, subType);
  3843.     if(player->hasCustomFlag(PlayerCustomFlag_CanSeeItemDetails))
  3844.         ss << std::endl << "ItemID: [" << it.id << "].";
  3845.  
  3846.     player->sendTextMessage(MSG_INFO_DESCR, ss.str());
  3847.     return true;
  3848. }
  3849.  
  3850. bool Game::playerLookAt(uint32_t playerId, const Position& pos, uint16_t spriteId, int16_t stackpos)
  3851. {
  3852.     Player* player = getPlayerByID(playerId);
  3853.     if(!player || player->isRemoved())
  3854.         return false;
  3855.  
  3856.     if(player->hasCondition(CONDITION_EXHAUST, EXHAUST_PLAYERLOOK))
  3857.     {
  3858.         player->sendTextMessage(MSG_STATUS_SMALL, "You have to wait a few seconds before doing this again.");
  3859.         return false;
  3860.     }
  3861.  
  3862.     if(Condition* conditionlook = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 1000, 0, false, EXHAUST_PLAYERLOOK))
  3863.         player->addCondition(conditionlook);
  3864.  
  3865.     Thing* thing = internalGetThing(player, pos, stackpos, spriteId, STACKPOS_LOOK);
  3866.     if(!thing)
  3867.     {
  3868.         player->sendCancelMessage(RET_NOTPOSSIBLE);
  3869.         return false;
  3870.     }
  3871.  
  3872.     Position thingPos = pos;
  3873.     if(pos.x == 0xFFFF)
  3874.         thingPos = thing->getPosition();
  3875.  
  3876.     if(!player->canSee(thingPos))
  3877.     {
  3878.         player->sendCancelMessage(RET_NOTPOSSIBLE);
  3879.         return false;
  3880.     }
  3881.  
  3882.     Position playerPos = player->getPosition();
  3883.     int32_t lookDistance = -1;
  3884.     if(thing != player)
  3885.     {
  3886.         lookDistance = std::max(std::abs(playerPos.x - thingPos.x), std::abs(playerPos.y - thingPos.y));
  3887.         if(playerPos.z != thingPos.z)
  3888.             lookDistance += 15;
  3889.     }
  3890.  
  3891.     bool deny = false;
  3892.     CreatureEventList lookEvents = player->getCreatureEvents(CREATURE_EVENT_LOOK);
  3893.     for(CreatureEventList::iterator it = lookEvents.begin(); it != lookEvents.end(); ++it)
  3894.     {
  3895.         if(!(*it)->executeLook(player, thing, thingPos, stackpos, lookDistance))
  3896.             deny = true;
  3897.     }
  3898.  
  3899.     if(deny)
  3900.         return false;
  3901.  
  3902.     std::ostringstream ss;
  3903.     ss << "You see " << thing->getDescription(lookDistance);
  3904.     if(player->hasCustomFlag(PlayerCustomFlag_CanSeeItemDetails))
  3905.     {
  3906.         if(Item* item = thing->getItem())
  3907.         {
  3908.             ss << std::endl << "ItemID: [" << item->getID() << "]";
  3909.             if(item->getActionId() > 0)
  3910.                 ss << ", ActionID: [" << item->getActionId() << "]";
  3911.  
  3912.             if(item->getUniqueId() > 0)
  3913.                 ss << ", UniqueID: [" << item->getUniqueId() << "]";
  3914.  
  3915.             ss << ".";
  3916.             const ItemType& it = Item::items[item->getID()];
  3917.             if(it.transformEquipTo)
  3918.                 ss << std::endl << "TransformTo: [" << it.transformEquipTo << "] (onEquip).";
  3919.             else if(it.transformDeEquipTo)
  3920.                 ss << std::endl << "TransformTo: [" << it.transformDeEquipTo << "] (onDeEquip).";
  3921.  
  3922.             if(it.transformUseTo)
  3923.                 ss << std::endl << "TransformTo: [" << it.transformUseTo << "] (onUse).";
  3924.  
  3925.             if(it.decayTo != -1)
  3926.                 ss << std::endl << "DecayTo: [" << it.decayTo << "].";
  3927.         }
  3928.     }
  3929.  
  3930.     if(player->hasCustomFlag(PlayerCustomFlag_CanSeeCreatureDetails))
  3931.     {
  3932.         if(const Creature* creature = thing->getCreature())
  3933.         {
  3934.             if(!player->hasFlag(PlayerFlag_HideHealth))
  3935.             {
  3936.                 ss << std::endl << "Health: [" << creature->getHealth() << " / " << creature->getMaxHealth() << "]";
  3937.                 if(creature->getMaxMana() > 0)
  3938.                     ss << ", Mana: [" << creature->getMana() << " / " << creature->getMaxMana() << "]";
  3939.  
  3940.                 ss << ".";
  3941.             }
  3942.  
  3943.             if(const Player* target = creature->getPlayer())
  3944.             {
  3945.                 ss << std::endl << "IP: " << convertIPAddress(target->getIP());
  3946. #if CLIENT_VERSION_MIN != CLIENT_VERSION_MAX
  3947.                 ss << ", Client: " << target->getClientVersion();
  3948. #endif
  3949.                 ss << ".";
  3950.             }
  3951.  
  3952.             if(creature->isGhost())
  3953.                 ss << std::endl << "* Ghost mode *";
  3954.         }
  3955.     }
  3956.  
  3957.     if(player->hasCustomFlag(PlayerCustomFlag_CanSeePosition))
  3958.     {
  3959.         ss << std::endl << "Position: [X: " << thingPos.x << "] [Y: " << thingPos.y << "] [Z: " << thingPos.z << "]";
  3960.         if(Tile* tile = getTile(thingPos))
  3961.         {
  3962.             if(House* house = tile->getHouse())
  3963.                 ss << " [House: " << house->getId() << "]";
  3964.         }
  3965.  
  3966.         ss << ".";
  3967.     }
  3968.  
  3969.     player->sendTextMessage(MSG_INFO_DESCR, ss.str());
  3970.     return true;
  3971. }
  3972.  
  3973. bool Game::playerLookInBattleList(uint32_t playerId, uint32_t creatureId)
  3974. {
  3975.     Player* player = getPlayerByID(playerId);
  3976.     if(!player || player->isRemoved())
  3977.         return false;
  3978.  
  3979.     Creature* creature = getCreatureByID(creatureId);
  3980.     if(!creature || creature->isRemoved())
  3981.         return false;
  3982.  
  3983.     if(!player->canSeeCreature(creature))
  3984.         return false;
  3985.  
  3986.     const Position& creaturePos = creature->getPosition();
  3987.     if(!player->canSee(creaturePos))
  3988.         return false;
  3989.  
  3990.     int32_t lookDistance;
  3991.     if(creature != player)
  3992.     {
  3993.         const Position& playerPos = player->getPosition();
  3994.         lookDistance = std::max(std::abs(playerPos.x - creaturePos.x), std::abs(playerPos.y - creaturePos.y));
  3995.         if(playerPos.z != creaturePos.z)
  3996.             lookDistance += 15;
  3997.     }
  3998.     else
  3999.         lookDistance = -1;
  4000.  
  4001.     std::ostringstream ss;
  4002.     ss << "You see " << creature->getDescription(lookDistance);
  4003.     if(player->hasCustomFlag(PlayerCustomFlag_CanSeeCreatureDetails))
  4004.     {
  4005.         if(!player->hasFlag(PlayerFlag_HideHealth))
  4006.         {
  4007.             ss << std::endl << "Health: [" << creature->getHealth() << " / " << creature->getMaxHealth() << "]";
  4008.             if(creature->getMaxMana() > 0)
  4009.                 ss << ", Mana: [" << creature->getMana() << " / " << creature->getMaxMana() << "]";
  4010.  
  4011.             ss << ".";
  4012.         }
  4013.  
  4014.         if(const Player* target = creature->getPlayer())
  4015.         {
  4016.             ss << std::endl << "IP: " << convertIPAddress(target->getIP());
  4017. #if CLIENT_VERSION_MIN != CLIENT_VERSION_MAX
  4018.             ss << ", Client: " << target->getClientVersion();
  4019. #endif
  4020.             ss << ".";
  4021.         }
  4022.  
  4023.         if(creature->isGhost())
  4024.             ss << std::endl << "* Ghost mode *";
  4025.     }
  4026.  
  4027.     if(player->hasCustomFlag(PlayerCustomFlag_CanSeePosition))
  4028.     {
  4029.         ss << std::endl << "Position: [X: " << creaturePos.x << "] [Y: " << creaturePos.y << "] [Z: " << creaturePos.z << "]";
  4030.         ss << ".";
  4031.     }
  4032.  
  4033.     player->sendTextMessage(MSG_INFO_DESCR, ss.str());
  4034.     return true;
  4035. }
  4036.  
  4037. bool Game::playerQuests(uint32_t playerId)
  4038. {
  4039.     Player* player = getPlayerByID(playerId);
  4040.     if(!player || player->isRemoved())
  4041.         return false;
  4042.  
  4043.     player->sendQuests();
  4044.     return true;
  4045. }
  4046.  
  4047. bool Game::playerQuestInfo(uint32_t playerId, uint16_t questId)
  4048. {
  4049.     Player* player = getPlayerByID(playerId);
  4050.     if(!player || player->isRemoved())
  4051.         return false;
  4052.  
  4053.     Quest* quest = Quests::getInstance()->getQuestById(questId);
  4054.     if(!quest)
  4055.         return false;
  4056.  
  4057.     player->sendQuestInfo(quest);
  4058.     return true;
  4059. }
  4060.  
  4061. bool Game::playerCancelAttackAndFollow(uint32_t playerId)
  4062. {
  4063.     Player* player = getPlayerByID(playerId);
  4064.     if(!player || player->isRemoved())
  4065.         return false;
  4066.  
  4067.     playerSetAttackedCreature(playerId, 0);
  4068.     playerFollowCreature(playerId, 0);
  4069.  
  4070.     player->stopWalk();
  4071.     return true;
  4072. }
  4073.  
  4074. bool Game::playerSetAttackedCreature(uint32_t playerId, uint32_t creatureId)
  4075. {
  4076.     Player* player = getPlayerByID(playerId);
  4077.     if(!player || player->isRemoved())
  4078.         return false;
  4079.  
  4080.     if(player->getAttackedCreature() && !creatureId)
  4081.     {
  4082.         player->setAttackedCreature(NULL);
  4083.         player->sendCancelTarget();
  4084.         return true;
  4085.     }
  4086.  
  4087.     Creature* attackCreature = getCreatureByID(creatureId);
  4088.     if(!attackCreature)
  4089.     {
  4090.         player->setAttackedCreature(NULL);
  4091.         player->sendCancelTarget();
  4092.         return false;
  4093.     }
  4094.  
  4095.     ReturnValue ret = Combat::canTargetCreature(player, attackCreature);
  4096.     if(ret != RET_NOERROR)
  4097.     {
  4098.         if(ret != RET_NEEDEXCHANGE)
  4099.             player->sendCancelMessage(ret);
  4100.  
  4101.         player->sendCancelTarget();
  4102.         player->setAttackedCreature(NULL);
  4103.         return false;
  4104.     }
  4105.  
  4106.     player->setAttackedCreature(attackCreature);
  4107.     Dispatcher::getInstance().addTask(createTask(boost::bind(
  4108.         &Game::updateCreatureWalk, this, player->getID())));
  4109.     return true;
  4110. }
  4111.  
  4112. bool Game::playerFollowCreature(uint32_t playerId, uint32_t creatureId)
  4113. {
  4114.     Player* player = getPlayerByID(playerId);
  4115.     if(!player || player->isRemoved())
  4116.         return false;
  4117.  
  4118.     Creature* followCreature = NULL;
  4119.     if(creatureId)
  4120.     {
  4121.         if(player->getNoMove())
  4122.         {
  4123.             playerCancelAttackAndFollow(playerId);
  4124.             player->sendCancelMessage(RET_NOTPOSSIBLE);
  4125.             return false;
  4126.         }
  4127.  
  4128.         followCreature = getCreatureByID(creatureId);
  4129.     }
  4130.  
  4131.     player->setAttackedCreature(NULL);
  4132.     Dispatcher::getInstance().addTask(createTask(boost::bind(
  4133.         &Game::updateCreatureWalk, this, player->getID())));
  4134.     return player->setFollowCreature(followCreature);
  4135. }
  4136.  
  4137. bool Game::playerSetFightModes(uint32_t playerId, fightMode_t fightMode, chaseMode_t chaseMode, secureMode_t secureMode)
  4138. {
  4139.     Player* player = getPlayerByID(playerId);
  4140.     if(!player || player->isRemoved())
  4141.         return false;
  4142.  
  4143.     player->setFightMode(fightMode);
  4144.     player->setChaseMode(chaseMode);
  4145.     player->setSecureMode(secureMode);
  4146.  
  4147.     player->setLastAttack(OTSYS_TIME());
  4148.     return true;
  4149. }
  4150.  
  4151. bool Game::playerRequestAddVip(uint32_t playerId, const std::string& vipName)
  4152. {
  4153.     Player* player = getPlayerByID(playerId);
  4154.     if(!player || player->isRemoved() || !player->canDoExAction())
  4155.         return false;
  4156.  
  4157.     uint32_t guid;
  4158.     bool specialVip;
  4159.     std::string name = vipName;
  4160.  
  4161.     player->setNextExAction(OTSYS_TIME() + g_config.getNumber(ConfigManager::CUSTOM_ACTIONS_DELAY_INTERVAL) - 10);
  4162.     if(!IOLoginData::getInstance()->getGuidByNameEx(guid, specialVip, name))
  4163.     {
  4164.         player->sendTextMessage(MSG_STATUS_SMALL, "A player with that name does not exist.");
  4165.         return false;
  4166.     }
  4167.  
  4168.     if(specialVip && !player->hasFlag(PlayerFlag_SpecialVIP))
  4169.     {
  4170.         player->sendTextMessage(MSG_STATUS_SMALL, "You cannot add this player.");
  4171.         return false;
  4172.     }
  4173.  
  4174.     if(player->hasCondition(CONDITION_EXHAUST, EXHAUST_PLAYERVIP))
  4175.     {
  4176.         player->sendTextMessage(MSG_STATUS_SMALL, "Please wait few seconds before adding a new player to your vip list.");
  4177.         return false;
  4178.     }
  4179.  
  4180.     bool online = false;
  4181.     if(Player* target = getPlayerByName(name))
  4182.         online = player->canSeeCreature(target);
  4183.  
  4184.     if(Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 1000, 0, false, EXHAUST_PLAYERVIP))
  4185.         player->addCondition(condition);
  4186.  
  4187.     return player->addVIP(guid, name, online);
  4188. }
  4189.  
  4190. bool Game::playerRequestRemoveVip(uint32_t playerId, uint32_t guid)
  4191. {
  4192.     Player* player = getPlayerByID(playerId);
  4193.     if(!player || player->isRemoved())
  4194.         return false;
  4195.  
  4196.     if(player->hasCondition(CONDITION_EXHAUST, EXHAUST_PLAYERVIP))
  4197.     {
  4198.         player->sendTextMessage(MSG_STATUS_SMALL, "Please wait few seconds before deleting a player from your vip list.");
  4199.         return false;
  4200.     }
  4201.  
  4202.     if(Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 1000, 0, false, EXHAUST_PLAYERVIP))
  4203.         player->addCondition(condition);
  4204.  
  4205.     player->removeVIP(guid);
  4206.     return true;
  4207. }
  4208.  
  4209. bool Game::playerTurn(uint32_t playerId, Direction dir)
  4210. {
  4211.     Player* player = getPlayerByID(playerId);
  4212.     if(!player || player->isRemoved())
  4213.         return false;
  4214.  
  4215.     if(internalCreatureTurn(player, dir))
  4216.     {
  4217.         player->setIdleTime(0);
  4218.         return true;
  4219.     }
  4220.  
  4221.     if(player->getDirection() != dir || !player->hasCustomFlag(PlayerCustomFlag_CanTurnhop))
  4222.         return false;
  4223.  
  4224.     Position pos = getNextPosition(dir, player->getPosition());
  4225.     Tile* tile = map->getTile(pos);
  4226.     if(!tile || !tile->ground)
  4227.         return false;
  4228.  
  4229.     player->setIdleTime(0);
  4230.     ReturnValue ret = tile->__queryAdd(0, player, 1, FLAG_IGNOREBLOCKITEM);
  4231.     if(ret != RET_NOTENOUGHROOM && (ret != RET_NOTPOSSIBLE || player->hasCustomFlag(PlayerCustomFlag_CanMoveAnywhere)))
  4232.         return (internalTeleport(player, pos, false, FLAG_NOLIMIT, false) != RET_NOERROR);
  4233.  
  4234.     player->sendCancelMessage(ret);
  4235.     return false;
  4236. }
  4237.  
  4238. bool Game::playerRequestOutfit(uint32_t playerId)
  4239. {
  4240.     Player* player = getPlayerByID(playerId);
  4241.     if(!player || player->isRemoved())
  4242.         return false;
  4243.  
  4244.     if(player->hasCondition(CONDITION_EXHAUST, EXHAUST_OUTFIT))
  4245.     {
  4246.         player->sendTextMessage(MSG_STATUS_SMALL, "You have to wait a few seconds to change your outfit again.");
  4247.         return false;
  4248.     }
  4249.  
  4250.     if(Condition* conditionoutfit = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 1000, 0, false, EXHAUST_OUTFIT))
  4251.         player->addCondition(conditionoutfit);
  4252.  
  4253.     player->sendOutfitWindow();
  4254.     return true;
  4255. }
  4256.  
  4257. bool Game::playerChangeOutfit(uint32_t playerId, Outfit_t outfit)
  4258. {
  4259.     Player* player = getPlayerByID(playerId);
  4260.     if(!player || player->isRemoved())
  4261.         return false;
  4262.  
  4263.     if(player->hasCondition(CONDITION_EXHAUST, EXHAUST_OUTFIT))
  4264.     {
  4265.         player->sendTextMessage(MSG_STATUS_SMALL, "You have to wait a few seconds to change your outfit again.");
  4266.         return false;
  4267.     }
  4268.  
  4269.     if(Condition* conditionoutfit = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 1000, 0, false, EXHAUST_OUTFIT))
  4270.         player->addCondition(conditionoutfit);
  4271.  
  4272.     if(!player->changeOutfit(outfit, true))
  4273.         return false;
  4274.  
  4275.     player->setIdleTime(0);
  4276.     if(!player->hasCondition(CONDITION_OUTFIT, -1))
  4277.         internalCreatureChangeOutfit(player, outfit);
  4278.  
  4279.     return true;
  4280. }
  4281.  
  4282. bool Game::playerSay(uint32_t playerId, uint16_t channelId, MessageClasses type, const std::string& receiver, const std::string& text)
  4283. {
  4284.     Player* player = getPlayerByID(playerId);
  4285.     if (!player || player->isRemoved())
  4286.         return false;
  4287.  
  4288.     player->setIdleTime(0);
  4289.  
  4290.     int32_t muted = 0;
  4291.     bool mute = player->isMuted(channelId, type, muted);
  4292.     if (muted && mute)
  4293.     {
  4294.         if (muted > 0)
  4295.         {
  4296.             char buffer[75];
  4297.             sprintf(buffer, "You are still muted for %d seconds.", muted);
  4298.             player->sendTextMessage(MSG_STATUS_SMALL, buffer);
  4299.         }
  4300.         else
  4301.             player->sendTextMessage(MSG_STATUS_SMALL, "You are muted permanently.");
  4302.  
  4303.         return false;
  4304.     }
  4305.  
  4306.     if (player->isAccountManager())
  4307.     {
  4308.         if (mute)
  4309.             player->removeMessageBuffer();
  4310.  
  4311.         return internalCreatureSay(player, MSG_SPEAK_SAY, text, false);
  4312.     }
  4313.  
  4314.     if (g_talkActions->onPlayerSay(player, type == MSG_SPEAK_SAY ? (unsigned)CHANNEL_DEFAULT : channelId, text, false))
  4315.         return true;
  4316.  
  4317.     ReturnValue ret = RET_NOERROR;
  4318.     if (!muted)
  4319.     {
  4320.         ret = g_spells->onPlayerSay(player, text);
  4321.         if (ret == RET_NOERROR || (ret == RET_NEEDEXCHANGE &&
  4322.             !g_config.getBool(ConfigManager::BUFFER_SPELL_FAILURE)))
  4323.             return true;
  4324.     }
  4325.  
  4326.     if (mute && type != MSG_NPC_TO)
  4327.         player->removeMessageBuffer();
  4328.  
  4329.     if (ret == RET_NEEDEXCHANGE)
  4330.         return true;
  4331.  
  4332.     uint32_t statementId = 0;
  4333.     if (g_config.getBool(ConfigManager::SAVE_STATEMENT))
  4334.         IOLoginData::getInstance()->playerStatement(player, channelId, text, statementId);
  4335.  
  4336.     switch (type)
  4337.     {
  4338.     case MSG_SPEAK_SAY:
  4339.         return internalCreatureSay(player, MSG_SPEAK_SAY, text, false, NULL, NULL, statementId);
  4340.     case MSG_SPEAK_WHISPER:
  4341.         return playerWhisper(player, text, statementId);
  4342.     case MSG_SPEAK_YELL:
  4343.         return playerYell(player, text, statementId);
  4344.     case MSG_PRIVATE:
  4345.     case MSG_GAMEMASTER_PRIVATE:
  4346.     case MSG_RVR_ANSWER:
  4347.         return playerSpeakTo(player, type, receiver, text, statementId);
  4348.     case MSG_CHANNEL:
  4349.     case MSG_CHANNEL_HIGHLIGHT:
  4350.     case MSG_GAMEMASTER_CHANNEL:
  4351.     case MSG_GAMEMASTER_ANONYMOUS:
  4352.     {
  4353.         if (playerSpeakToChannel(player, type, text, channelId, statementId))
  4354.             return true;
  4355.  
  4356.         return internalCreatureSay(player, MSG_SPEAK_SAY, text, false, NULL, NULL, statementId);
  4357.     }
  4358.     case MSG_NPC_TO:
  4359.         return playerSpeakToNpc(player, text);
  4360.     case MSG_GAMEMASTER_BROADCAST:
  4361.         return playerBroadcastMessage(player, MSG_GAMEMASTER_BROADCAST, text, statementId);
  4362.     case MSG_RVR_CHANNEL:
  4363.         return playerReportRuleViolation(player, text);
  4364.         break;
  4365.     case MSG_RVR_CONTINUE:
  4366.         return playerContinueReport(player, text);
  4367.         break;
  4368.  
  4369.     default:
  4370.         break;
  4371.     }
  4372.  
  4373.     return false;
  4374. }
  4375.  
  4376. bool Game::playerWhisper(Player* player, const std::string& text, uint32_t statementId)
  4377. {
  4378.     SpectatorVec list;
  4379.     getSpectators(list, player->getPosition(), false, false, 1, 1);
  4380.     internalCreatureSay(player, MSG_SPEAK_WHISPER, text, false, &list, NULL, statementId);
  4381.     return true;
  4382. }
  4383.  
  4384. bool Game::playerYell(Player* player, const std::string& text, uint32_t statementId)
  4385. {
  4386.     if(player->getLevel() < 20 && !player->hasFlag(PlayerFlag_CannotBeMuted) && player->getPremiumDays() < 1)
  4387.     {
  4388.         player->sendTextMessage(MSG_STATUS_SMALL, "You may not yell unless you heave reached level 20 or your account has premium status.");
  4389.         return true;
  4390.     }
  4391.  
  4392.     if(player->hasCondition(CONDITION_MUTED, 1))
  4393.     {
  4394.         player->sendCancelMessage(RET_YOUAREEXHAUSTED);
  4395.         return true;
  4396.     }
  4397.  
  4398.     if(!player->hasFlag(PlayerFlag_CannotBeMuted))
  4399.     {
  4400.         if(Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_MUTED, 30000, 0, false, 1))
  4401.             player->addCondition(condition);
  4402.     }
  4403.  
  4404.     internalCreatureSay(player, MSG_SPEAK_YELL, asUpperCaseString(text), false, NULL, NULL, statementId);
  4405.     return true;
  4406. }
  4407.  
  4408. bool Game::playerSpeakTo(Player* player, MessageClasses type, const std::string& receiver,
  4409.     const std::string& text, uint32_t statementId)
  4410. {
  4411.     Player* toPlayer = getPlayerByName(receiver);
  4412.     if(!toPlayer || toPlayer->isRemoved())
  4413.     {
  4414.         player->sendTextMessage(MSG_STATUS_SMALL, "A player with this name is not online.");
  4415.         return false;
  4416.     }
  4417.     if (type == MSG_GAMEMASTER_PRIVATE && (player->hasFlag(PlayerFlag_CanTalkRedPrivate) || player->hasFlag(PlayerFlag_CannotBeMuted)))
  4418.         type = MSG_PRIVATE;
  4419.  
  4420.     bool canSee = player->canSeeCreature(toPlayer);
  4421.     if(toPlayer->hasCondition(CONDITION_GAMEMASTER, GAMEMASTER_IGNORE)
  4422.         && !player->hasFlag(PlayerFlag_CannotBeMuted))
  4423.     {
  4424.         char buffer[70];
  4425.         if(!canSee)
  4426.             sprintf(buffer, "A player with this name is not online.");
  4427.         else
  4428.             sprintf(buffer, "Sorry, %s is currently ignoring private messages.", toPlayer->getName().c_str());
  4429.  
  4430.         player->sendTextMessage(MSG_STATUS_SMALL, buffer);
  4431.         return false;
  4432.     }
  4433.  
  4434.  
  4435.     char buffer[80];
  4436.     toPlayer->sendCreatureSay(player, type, text, NULL, statementId);
  4437.     toPlayer->onCreatureSay(player, type, text);
  4438.  
  4439.     if (!canSee)
  4440.     {
  4441.         player->sendTextMessage(MSG_STATUS_SMALL, "A player with this name is not online.");
  4442.     }else
  4443.     {
  4444.         sprintf(buffer, "Message sent to %s.", toPlayer->getName().c_str());
  4445.         player->sendTextMessage(MSG_STATUS_SMALL, buffer);
  4446.     }
  4447.    
  4448.     return true;
  4449. }
  4450.  
  4451. bool Game::playerSpeakToChannel(Player* player, MessageClasses type, const std::string& text, uint16_t channelId, uint32_t statementId)
  4452. {
  4453.     if(player->hasCondition(CONDITION_EXHAUST, EXHAUST_PLAYERSPEAK))
  4454.     {
  4455.         player->sendTextMessage(MSG_STATUS_SMALL, "You have to wait a while to keep talking here.");
  4456.         return true;
  4457.     }
  4458.  
  4459.     if(Condition* conditionchannel = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 1000, 0, false, EXHAUST_PLAYERSPEAK))
  4460.         player->addCondition(conditionchannel);
  4461.  
  4462.     switch(type)
  4463.     {
  4464.         case MSG_CHANNEL:
  4465.         {
  4466.             if(channelId == CHANNEL_HELP && player->hasFlag(PlayerFlag_TalkOrangeHelpChannel))
  4467.                 type = MSG_CHANNEL_HIGHLIGHT;
  4468.  
  4469.             break;
  4470.         }
  4471.  
  4472.         case MSG_GAMEMASTER_CHANNEL:
  4473.         {
  4474.             if(!player->hasFlag(PlayerFlag_CanTalkRedChannel))
  4475.                 type = MSG_CHANNEL;
  4476.             break;
  4477.         }
  4478.  
  4479.         case MSG_GAMEMASTER_ANONYMOUS:
  4480.         {
  4481.             if(!player->hasFlag(PlayerFlag_CanTalkRedChannelAnonymous))
  4482.                 type = MSG_CHANNEL;
  4483.             break;
  4484.         }
  4485.  
  4486.         case MSG_GAMEMASTER_BROADCAST:
  4487.         {
  4488.             if(!player->hasFlag(PlayerFlag_CanBroadcast))
  4489.                 type = MSG_CHANNEL;
  4490.             break;
  4491.         }
  4492.  
  4493.         default:
  4494.             break;
  4495.     }
  4496.  
  4497.     if(text.length() < 251)
  4498.         return g_chat.talk(player, type, text, channelId, statementId, false);
  4499.  
  4500.     player->sendCancelMessage(RET_NOTPOSSIBLE);
  4501.     return false;
  4502. }
  4503.  
  4504. bool Game::playerSpeakToNpc(Player* player, const std::string& text)
  4505. {
  4506.     if(player->hasCondition(CONDITION_EXHAUST, EXHAUST_TALKNPC))
  4507.     {
  4508.         player->sendTextMessage(MSG_STATUS_SMALL, "You have to wait a while to keep talking here.");
  4509.         return false;
  4510.     }
  4511.  
  4512.     if(Condition* conditionnpc = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 250, 0, false, EXHAUST_TALKNPC))
  4513.         player->addCondition(conditionnpc);
  4514.  
  4515.     SpectatorVec list;
  4516.     SpectatorVec::iterator it;
  4517.     getSpectators(list, player->getPosition());
  4518.  
  4519.     //send to npcs only
  4520.     Npc* tmpNpc;
  4521.     for(it = list.begin(); it != list.end(); ++it)
  4522.     {
  4523.         if((tmpNpc = (*it)->getNpc()))
  4524.             (*it)->onCreatureSay(player, MSG_NPC_TO, text);
  4525.     }
  4526.     return true;
  4527. }
  4528.  
  4529. bool Game::canThrowObjectTo(const Position& fromPos, const Position& toPos, bool checkLineOfSight /*= true*/,
  4530.     int32_t rangex/* = Map::maxClientViewportX*/, int32_t rangey/* = Map::maxClientViewportY*/)
  4531. {
  4532.     return map->canThrowObjectTo(fromPos, toPos, checkLineOfSight, rangex, rangey);
  4533. }
  4534.  
  4535. bool Game::playerReportRuleViolation(Player* player, const std::string& text)
  4536. {
  4537.     //Do not allow reports on multiclones worlds since reports are name-based
  4538.     if(g_config.getNumber(ConfigManager::ALLOW_CLONES))
  4539.     {
  4540.         player->sendTextMessage(MSG_INFO_DESCR, "Rule violation reports are disabled.");
  4541.         return false;
  4542.     }
  4543.  
  4544.     cancelRuleViolation(player);
  4545.     boost::shared_ptr<RuleViolation> rvr(new RuleViolation(player, text, time(NULL)));
  4546.     ruleViolations[player->getID()] = rvr;
  4547.  
  4548.     ChatChannel* channel = g_chat.getChannelById(CHANNEL_RVR);
  4549.     if(!channel)
  4550.         return false;
  4551.  
  4552.     for(UsersMap::const_iterator it = channel->getUsers().begin(); it != channel->getUsers().end(); ++it)
  4553.         it->second->sendCreatureChannelSay(player, MSG_RVR_CHANNEL, text, CHANNEL_RVR, rvr->time);
  4554.  
  4555.     return true;
  4556. }
  4557.  
  4558. bool Game::playerContinueReport(Player* player, const std::string& text)
  4559. {
  4560.     RuleViolationsMap::iterator it = ruleViolations.find(player->getID());
  4561.     if(it == ruleViolations.end())
  4562.         return false;
  4563.  
  4564.     RuleViolation& rvr = *it->second;
  4565.     Player* toPlayer = rvr.gamemaster;
  4566.     if(!toPlayer)
  4567.         return false;
  4568.  
  4569.     toPlayer->sendCreatureSay(player, MSG_RVR_CONTINUE, text);
  4570.     player->sendTextMessage(MSG_STATUS_SMALL, "Message sent to Gamemaster.");
  4571.     return true;
  4572. }
  4573.  
  4574. bool Game::isSightClear(const Position& fromPos, const Position& toPos, bool floorCheck)
  4575. {
  4576.     return map->isSightClear(fromPos, toPos, floorCheck);
  4577. }
  4578.  
  4579. bool Game::internalCreatureTurn(Creature* creature, Direction dir)
  4580. {
  4581.     if (creature->getDirection() == dir)
  4582.         return false;
  4583.  
  4584.     bool deny = false;
  4585.     CreatureEventList directionEvents = creature->getCreatureEvents(CREATURE_EVENT_DIRECTION);
  4586.     for(CreatureEventList::iterator it = directionEvents.begin(); it != directionEvents.end(); ++it)
  4587.     {
  4588.         if(!(*it)->executeDirection(creature, creature->getDirection(), dir) && !deny)
  4589.             deny = true;
  4590.     }
  4591.  
  4592.     if (deny)
  4593.         return false;
  4594.  
  4595.     creature->setDirection(dir);
  4596.  
  4597.     SpectatorVec list;
  4598.     getSpectators(list, creature->getPosition(), true, true);
  4599.     for (Creature* spectator : list) {
  4600.         spectator->getPlayer()->sendCreatureTurn(creature);
  4601.     }
  4602.     return true;
  4603. }
  4604.  
  4605. bool Game::internalCreatureSay(Creature* creature, MessageClasses type, const std::string& text,
  4606.     bool ghostMode, SpectatorVec* spectators/* = NULL*/, Position* pos/* = NULL*/, uint32_t statementId/* = 0*/)
  4607. {
  4608.     Player* player = creature->getPlayer();
  4609.     if(player && player->isAccountManager() && !ghostMode)
  4610.     {
  4611.         player->manageAccount(text);
  4612.         return true;
  4613.     }
  4614.  
  4615.     Position destPos = creature->getPosition();
  4616.     if(pos)
  4617.         destPos = (*pos);
  4618.  
  4619.     SpectatorVec list;
  4620.     SpectatorVec::const_iterator it;
  4621.     if(!spectators || !spectators->size())
  4622.     {
  4623.         // This somewhat complex construct ensures that the cached SpectatorVec
  4624.         // is used if available and if it can be used, else a local vector is
  4625.         // used (hopefully the compiler will optimize away the construction of
  4626.         // the temporary when it's not used).
  4627.         if(type != MSG_SPEAK_YELL && type != MSG_SPEAK_MONSTER_YELL)
  4628.             getSpectators(list, destPos, false, false,
  4629.                 Map::maxClientViewportX, Map::maxClientViewportX,
  4630.                 Map::maxClientViewportY, Map::maxClientViewportY);
  4631.         else
  4632.             getSpectators(list, destPos, true, false, 18, 18, 14, 14);
  4633.     }
  4634.     else
  4635.         list = (*spectators);
  4636.  
  4637.     //send to client
  4638.     Player* tmpPlayer = NULL;
  4639.     for(it = list.begin(); it != list.end(); ++it)
  4640.     {
  4641.         if(!(tmpPlayer = (*it)->getPlayer()))
  4642.             continue;
  4643.  
  4644.         if(!ghostMode || tmpPlayer->canSeeCreature(creature))
  4645.             tmpPlayer->sendCreatureSay(creature, type, text, &destPos, statementId);
  4646.     }
  4647.  
  4648.     //event method
  4649.     for(it = list.begin(); it != list.end(); ++it)
  4650.         (*it)->onCreatureSay(creature, type, text, &destPos);
  4651.  
  4652.     return true;
  4653. }
  4654.  
  4655. bool Game::getPathTo(const Creature* creature, const Position& destPos,
  4656.     std::list<Direction>& listDir, int32_t maxSearchDist /*= -1*/)
  4657. {
  4658.     return map->getPathTo(creature, destPos, listDir, maxSearchDist);
  4659. }
  4660.  
  4661. bool Game::getPathToEx(const Creature* creature, const Position& targetPos,
  4662.     std::list<Direction>& dirList, const FindPathParams& fpp)
  4663. {
  4664.     return map->getPathMatching(creature, dirList, FrozenPathingConditionCall(targetPos), fpp);
  4665. }
  4666.  
  4667. bool Game::getPathToEx(const Creature* creature, const Position& targetPos, std::list<Direction>& dirList,
  4668.     uint32_t minTargetDist, uint32_t maxTargetDist, bool fullPathSearch/* = true*/,
  4669.     bool clearSight/* = true*/, int32_t maxSearchDist/* = -1*/)
  4670. {
  4671.     FindPathParams fpp;
  4672.     fpp.fullPathSearch = fullPathSearch;
  4673.     fpp.maxSearchDist = maxSearchDist;
  4674.     fpp.clearSight = clearSight;
  4675.     fpp.minTargetDist = minTargetDist;
  4676.     fpp.maxTargetDist = maxTargetDist;
  4677.     return getPathToEx(creature, targetPos, dirList, fpp);
  4678. }
  4679.  
  4680. bool Game::steerCreature(Creature* creature, const Position& position, uint16_t maxNodes/* = 100*/)
  4681. {
  4682.     FindPathParams fpp;
  4683.     fpp.maxClosedNodes = maxNodes;
  4684.  
  4685.     fpp.fullPathSearch = true;
  4686.     fpp.maxSearchDist = -1;
  4687.     fpp.minTargetDist = 0;
  4688.     fpp.maxTargetDist = 1;
  4689.  
  4690.     std::list<Direction> dirList;
  4691.     if(!getPathToEx(creature, position, dirList, fpp))
  4692.         return false;
  4693.  
  4694.     if(Player* player = creature->getPlayer())
  4695.         player->setNextWalkTask(NULL);
  4696.  
  4697.     creature->startAutoWalk(dirList);
  4698.     return true;
  4699. }
  4700.  
  4701. void Game::checkCreatureWalk(uint32_t creatureId)
  4702. {
  4703.     Creature* creature = getCreatureByID(creatureId);
  4704.     if(!creature || creature->getHealth() < 1)
  4705.         return;
  4706.  
  4707.     creature->onWalk();
  4708.     cleanup();
  4709. }
  4710.  
  4711. void Game::updateCreatureWalk(uint32_t creatureId)
  4712. {
  4713.     Creature* creature = getCreatureByID(creatureId);
  4714.     if(creature && creature->getHealth() > 0)
  4715.         creature->goToFollowCreature();
  4716. }
  4717.  
  4718. void Game::checkCreatureAttack(uint32_t creatureId)
  4719. {
  4720.     Creature* creature = getCreatureByID(creatureId);
  4721.     if(creature && creature->getHealth() > 0)
  4722.         creature->onAttacking(0);
  4723. }
  4724.  
  4725. void Game::addCreatureCheck(Creature* creature)
  4726. {
  4727.     if(creature->isRemoved())
  4728.         return;
  4729.  
  4730.     creature->checked = true;
  4731.     if(creature->checkVector >= 0) //already in a vector, or about to be added
  4732.         return;
  4733.  
  4734.     toAddCheckCreatureVector.push_back(creature);
  4735.     creature->checkVector = random_range(0, EVENT_CREATURECOUNT - 1);
  4736.     creature->addRef();
  4737. }
  4738.  
  4739. void Game::removeCreatureCheck(Creature* creature)
  4740. {
  4741.     if(creature->checkVector == -1) //not in any vector
  4742.         return;
  4743.  
  4744.     creature->checked = false;
  4745. }
  4746.  
  4747. void Game::checkCreatures()
  4748. {
  4749.     checkCreatureEvent = Scheduler::getInstance().addEvent(createSchedulerTask(
  4750.         EVENT_CHECK_CREATURE_INTERVAL, boost::bind(&Game::checkCreatures, this)));
  4751.     if(++checkCreatureLastIndex == EVENT_CREATURECOUNT)
  4752.         checkCreatureLastIndex = 0;
  4753.  
  4754.     std::vector<Creature*>::iterator it;
  4755. #ifndef __GROUPED_ATTACKS__
  4756.     std::vector<Creature*> creatureVector;
  4757.     for(uint16_t i = 0; i < EVENT_CREATURECOUNT; ++i)
  4758.     {
  4759.         if(i == checkCreatureLastIndex)
  4760.             continue;
  4761.  
  4762.         creatureVector = checkCreatureVectors[i];
  4763.         for(it = creatureVector.begin(); it != creatureVector.end(); ++it)
  4764.         {
  4765.             if((*it)->checked && (*it)->getHealth() > 0)
  4766.                 (*it)->onAttacking(EVENT_CHECK_CREATURE_INTERVAL);
  4767.         }
  4768.     }
  4769. #endif
  4770.  
  4771.     for(it = toAddCheckCreatureVector.begin(); it != toAddCheckCreatureVector.end(); ++it)
  4772.         checkCreatureVectors[(*it)->checkVector].push_back(*it);
  4773.  
  4774.     toAddCheckCreatureVector.clear();
  4775.     std::vector<Creature*>& checkCreatureVector = checkCreatureVectors[checkCreatureLastIndex];
  4776.     for(it = checkCreatureVector.begin(); it != checkCreatureVector.end(); )
  4777.     {
  4778.         if((*it)->checked)
  4779.         {
  4780.             if((*it)->getHealth() > 0 || !(*it)->onDeath())
  4781.                 (*it)->onThink(EVENT_CREATURE_THINK_INTERVAL);
  4782.  
  4783.             ++it;
  4784.         }
  4785.         else
  4786.         {
  4787.             (*it)->checkVector = -1;
  4788.             freeThing(*it);
  4789.             it = checkCreatureVector.erase(it);
  4790.         }
  4791.     }
  4792.  
  4793.     cleanup();
  4794. }
  4795.  
  4796. void Game::changeSpeed(Creature* creature, int32_t varSpeed)
  4797. {
  4798.     if(!creature)
  4799.         return;
  4800.  
  4801.     creature->setSpeed(creature->getSpeed() - creature->getBaseSpeed() + varSpeed);
  4802.  
  4803.     //send to client
  4804.     SpectatorVec list;
  4805.     getSpectators(list, creature->getPosition(), false, true);
  4806.     for (Creature* spectator : list) {
  4807.         spectator->getPlayer()->sendChangeSpeed(creature, creature->getStepSpeed());
  4808.     }
  4809. }
  4810.  
  4811. void Game::internalCreatureChangeOutfit(Creature* creature, const Outfit_t& outfit, bool forced/* = false*/)
  4812. {
  4813.     if(!forced)
  4814.     {
  4815.         bool deny = false;
  4816.         CreatureEventList outfitEvents = creature->getCreatureEvents(CREATURE_EVENT_OUTFIT);
  4817.         for(CreatureEventList::iterator it = outfitEvents.begin(); it != outfitEvents.end(); ++it)
  4818.         {
  4819.             if(!(*it)->executeOutfit(creature, creature->getCurrentOutfit(), outfit) && !deny)
  4820.                 deny = true;
  4821.         }
  4822.  
  4823.         if(deny || creature->getCurrentOutfit() == outfit)
  4824.             return;
  4825.     }
  4826.  
  4827.     creature->setCurrentOutfit(outfit);
  4828.  
  4829.     SpectatorVec list;
  4830.     getSpectators(list, creature->getPosition(), true, true);
  4831.  
  4832.     //send to client
  4833.     for (Creature* spectator : list) {
  4834.         spectator->getPlayer()->sendCreatureChangeOutfit(creature, outfit);
  4835.     }
  4836. }
  4837.  
  4838. void Game::internalCreatureChangeVisible(Creature* creature, Visible_t visible)
  4839. {
  4840.     SpectatorVec list;
  4841.     getSpectators(list, creature->getPosition(), true, true);
  4842.     //send to client
  4843.     for (Creature* spectator : list) {
  4844.         spectator->getPlayer()->sendCreatureChangeVisible(creature, visible);
  4845.     }
  4846. }
  4847.  
  4848.  
  4849. void Game::changeLight(const Creature* creature)
  4850. {
  4851.     SpectatorVec list;
  4852.     getSpectators(list, creature->getPosition(), true, true);
  4853.     //send to client
  4854.     for (Creature* spectator : list) {
  4855.         Player* tmpPlayer = spectator->getPlayer();
  4856.         if (!tmpPlayer->hasCustomFlag(PlayerCustomFlag_HasFullLight))
  4857.             tmpPlayer->sendCreatureLight(creature);
  4858.     }
  4859. }
  4860.  
  4861. bool Game::combatBlockHit(CombatType_t combatType, Creature* attacker, Creature* target,
  4862.     int32_t& healthChange, bool checkDefense, bool checkArmor, bool field/* = false*/, bool element/* = false*/)
  4863. {
  4864.     if(healthChange > 0)
  4865.         return false;
  4866.  
  4867.     const Position& targetPos = target->getPosition();
  4868.     SpectatorVec list;
  4869.     getSpectators(list, targetPos, true, true);
  4870.     if(Combat::canDoCombat(attacker, target, true) != RET_NOERROR)
  4871.     {
  4872.         if(!element)
  4873.             addMagicEffect(list, targetPos, MAGIC_EFFECT_POFF, target->isGhost());
  4874.  
  4875.         return true;
  4876.     }
  4877.  
  4878.     int32_t damage = -healthChange;
  4879.     BlockType_t blockType = target->blockHit(attacker, combatType,
  4880.         damage, checkDefense, checkArmor, !field, field, element);
  4881.  
  4882.     healthChange = -damage;
  4883.     if(blockType == BLOCK_DEFENSE)
  4884.     {
  4885.         if(!element)
  4886.             addMagicEffect(list, targetPos, MAGIC_EFFECT_POFF);
  4887.  
  4888.         return true;
  4889.     }
  4890.  
  4891.     if(blockType == BLOCK_ARMOR)
  4892.     {
  4893.         if(!element)
  4894.             addMagicEffect(list, targetPos, MAGIC_EFFECT_BLOCKHIT);
  4895.  
  4896.         return true;
  4897.     }
  4898.  
  4899.     if(blockType != BLOCK_IMMUNITY)
  4900.         return false;
  4901.  
  4902.     if(element)
  4903.         return true;
  4904.  
  4905.     MagicEffect_t effect = MAGIC_EFFECT_NONE;
  4906.     switch(combatType)
  4907.     {
  4908.         case COMBAT_UNDEFINEDDAMAGE:
  4909.             break;
  4910.  
  4911.         case COMBAT_ENERGYDAMAGE:
  4912.         case COMBAT_FIREDAMAGE:
  4913.         case COMBAT_PHYSICALDAMAGE:
  4914.         case COMBAT_ICEDAMAGE:
  4915.         case COMBAT_DEATHDAMAGE:
  4916.         case COMBAT_EARTHDAMAGE:
  4917.         case COMBAT_HOLYDAMAGE:
  4918.         {
  4919.             effect = MAGIC_EFFECT_BLOCKHIT;
  4920.             break;
  4921.         }
  4922.  
  4923.         default:
  4924.         {
  4925.             effect = MAGIC_EFFECT_POFF;
  4926.             break;
  4927.         }
  4928.     }
  4929.  
  4930.     addMagicEffect(list, targetPos, effect);
  4931.     return true;
  4932. }
  4933.  
  4934. bool Game::combatChangeHealth(CombatType_t combatType, Creature* attacker, Creature* target, int32_t healthChange,
  4935.     MagicEffect_t hitEffect/* = MAGIC_EFFECT_UNKNOWN*/, Color_t hitColor/* = COLOR_UNKNOWN*/, bool force/* = false*/)
  4936. {
  4937.     CombatParams params;
  4938.     params.effects.hit =  hitEffect;
  4939.     params.effects.color = hitColor;
  4940.  
  4941.     params.combatType = combatType;
  4942.     return combatChangeHealth(params, attacker, target, healthChange, force);
  4943. }
  4944.  
  4945. bool Game::combatChangeHealth(const CombatParams& params, Creature* attacker, Creature* target, int32_t healthChange, bool force)
  4946. {
  4947.     const Position& targetPos = target->getPosition();
  4948.     if(healthChange > 0)
  4949.     {
  4950.         if(!force && target->getHealth() <= 0)
  4951.             return false;
  4952.  
  4953.         bool deny = false;
  4954.         CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE);
  4955.         for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it)
  4956.         {
  4957.             if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_HEALTHGAIN, params.combatType, healthChange))
  4958.                 deny = true;
  4959.         }
  4960.  
  4961.         if(deny)
  4962.             return false;
  4963.  
  4964.         int32_t oldHealth = target->getHealth();
  4965.         target->gainHealth(attacker, healthChange);
  4966.         if(oldHealth != target->getHealth() && g_config.getBool(ConfigManager::SHOW_HEALTH_CHANGE) && !target->isGhost() &&
  4967.             (g_config.getBool(ConfigManager::SHOW_HEALTH_CHANGE_MONSTER) || !target->getMonster()))
  4968.         {
  4969.             SpectatorVec list;
  4970.             getSpectators(list, targetPos, true, true);
  4971.             if(params.combatType != COMBAT_HEALING)
  4972.                 addMagicEffect(list, targetPos, MAGIC_EFFECT_WRAPS_BLUE);
  4973.  
  4974.             SpectatorVec textList;
  4975.             for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
  4976.             {
  4977.                 if(!(*it)->getPlayer())
  4978.                     continue;
  4979.  
  4980.                 if((*it) != attacker && (*it) != target && (*it)->getPosition().z == target->getPosition().z)
  4981.                     textList.insert(*it);
  4982.             }
  4983.  
  4984.             healthChange = (target->getHealth() - oldHealth);
  4985.             std::string plural = (healthChange != 1 ? "s." : ".");
  4986.  
  4987.             std::ostringstream ss;
  4988.             char buffer[20];
  4989.             sprintf(buffer, "+%d", healthChange);
  4990.             addAnimatedText(list, targetPos, COLOR_MAYABLUE, buffer);
  4991.             if(!textList.empty())
  4992.             {
  4993.                 if(!attacker)
  4994.                     ss << ucfirst(target->getNameDescription()) << " is healed for " << healthChange << " hitpoint" << plural;
  4995.                 else if(attacker != target)
  4996.                     ss << ucfirst(attacker->getNameDescription()) << " heals " << target->getNameDescription() << " for " << healthChange << " hitpoint" << plural;
  4997.                 else
  4998.                 {
  4999.                     ss << ucfirst(attacker->getNameDescription()) << " heals ";
  5000.                     if(Player* attackerPlayer = attacker->getPlayer())
  5001.                         ss << (attackerPlayer->getSex(false) == PLAYERSEX_FEMALE ? "herself" : "himself") << " for " << healthChange << " hitpoint" << plural;
  5002.                     else
  5003.                         ss << "itself for " << healthChange << " hitpoint" << plural;
  5004.                 }
  5005.  
  5006.                 addStatsMessage(textList, MSG_HEALED_OTHERS, ss.str(), targetPos);
  5007.                 ss.str("");
  5008.             }
  5009.  
  5010.             Player* player = NULL;
  5011.             if(attacker && (player = attacker->getPlayer()))
  5012.             {
  5013.                 if(attacker != target)
  5014.                     ss << "You healed " << target->getNameDescription() << " for " << healthChange << " hitpoint" << plural;
  5015.                 else
  5016.                     ss << "You healed yourself for " << healthChange << " hitpoint" << plural;
  5017.  
  5018.                 player->sendStatsMessage(MSG_HEALED, ss.str(), targetPos);
  5019.                 ss.str("");
  5020.             }
  5021.  
  5022.             if((player = target->getPlayer()) && attacker != target)
  5023.             {
  5024.                 if(attacker)
  5025.                     ss << ucfirst(attacker->getNameDescription()) << " heals you for " << healthChange << " hitpoint" << plural;
  5026.                 else
  5027.                     ss << "You are healed for " << healthChange << " hitpoint" << plural;
  5028.  
  5029.                 player->sendStatsMessage(MSG_HEALED, ss.str(), targetPos);
  5030.             }
  5031.         }
  5032.     }
  5033.     else
  5034.     {
  5035.         SpectatorVec list;
  5036.         getSpectators(list, targetPos, true, true);
  5037.         if(target->getHealth() < 1 || Combat::canDoCombat(attacker, target, true) != RET_NOERROR)
  5038.         {
  5039.             addMagicEffect(list, targetPos, MAGIC_EFFECT_POFF);
  5040.             return true;
  5041.         }
  5042.  
  5043.         int32_t elementDamage = 0;
  5044.         if(params.element.damage && params.element.type != COMBAT_NONE)
  5045.             elementDamage = -params.element.damage;
  5046.  
  5047.         int32_t damage = -healthChange;
  5048.         if(damage > 0)
  5049.         {
  5050.             if(target->hasCondition(CONDITION_MANASHIELD) && params.combatType != COMBAT_UNDEFINEDDAMAGE)
  5051.             {
  5052.                 int32_t manaDamage = std::min(target->getMana(), damage + elementDamage);
  5053.                 damage = std::max((int32_t)0, damage + elementDamage - manaDamage);
  5054.  
  5055.                 elementDamage = 0; // TODO: I don't know how it works ;(
  5056.                 if(manaDamage && combatChangeMana(attacker, target, -manaDamage, params.combatType, true))
  5057.                     addMagicEffect(list, targetPos, MAGIC_EFFECT_LOSE_ENERGY);
  5058.             }
  5059.  
  5060.             damage = std::min(target->getHealth(), damage);
  5061.             if(damage > 0)
  5062.             {
  5063.                 bool deny = false;
  5064.                 Position creaturePos = target->getPosition();
  5065.                 CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE);
  5066.                 for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it)
  5067.                 {
  5068.                     if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_HEALTHLOSS, params.combatType, damage))
  5069.                         deny = true;
  5070.                 }
  5071.  
  5072.                 if(deny)
  5073.                     return false;
  5074.  
  5075.                 target->drainHealth(attacker, params.combatType, damage);
  5076.                 if(elementDamage)
  5077.                     target->drainHealth(attacker, params.element.type, elementDamage);
  5078.  
  5079.                 Color_t textColor = COLOR_NONE;
  5080.                 MagicEffect_t magicEffect = MAGIC_EFFECT_NONE;
  5081.                
  5082.                 if (target->getPosition() != creaturePos)// The target was teleported/moved on statschange, a new spectator list must be created
  5083.                 {
  5084.                     SpectatorVec newList;
  5085.                     getSpectators(newList, targetPos, true, true);
  5086.                     addCreatureHealth(newList, target);
  5087.                 }
  5088.                 else
  5089.                     addCreatureHealth(list, target);
  5090.  
  5091.                 if(params.combatType == COMBAT_PHYSICALDAMAGE)
  5092.                 {
  5093.                     Item* splash = NULL;
  5094.                     switch(target->getRace())
  5095.                     {
  5096.                         case RACE_VENOM:
  5097.                             textColor = COLOR_LIGHTGREEN;
  5098.                             magicEffect = MAGIC_EFFECT_POISON;
  5099.                             splash = Item::CreateItem(ITEM_SMALLSPLASH, FLUID_GREEN);
  5100.                             break;
  5101.  
  5102.                         case RACE_BLOOD:
  5103.                             textColor = COLOR_RED;
  5104.                             magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
  5105.                             splash = Item::CreateItem(ITEM_SMALLSPLASH, FLUID_BLOOD);
  5106.                             break;
  5107.  
  5108.                         case RACE_UNDEAD:
  5109.                             textColor = COLOR_GREY;
  5110.                             magicEffect = MAGIC_EFFECT_HIT_AREA;
  5111.                             break;
  5112.  
  5113.                         case RACE_FIRE:
  5114.                             textColor = COLOR_ORANGE;
  5115.                             magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
  5116.                             break;
  5117.  
  5118.                         case RACE_ENERGY:
  5119.                             textColor = COLOR_PURPLE;
  5120.                             magicEffect = MAGIC_EFFECT_PURPLEENERGY;
  5121.                             break;
  5122.  
  5123.                         default:
  5124.                             break;
  5125.                     }
  5126.  
  5127.                     if(splash)
  5128.                     {
  5129.                         internalAddItem(NULL, target->getTile(), splash, INDEX_WHEREEVER, FLAG_NOLIMIT);
  5130.                         startDecay(splash);
  5131.                     }
  5132.                 }
  5133.                 else
  5134.                     getCombatDetails(params.combatType, magicEffect, textColor);
  5135.  
  5136.                 if(params.effects.hit != MAGIC_EFFECT_UNKNOWN)
  5137.                     magicEffect = params.effects.hit;
  5138.  
  5139.                 if(params.effects.color != COLOR_UNKNOWN)
  5140.                     textColor = params.effects.color;
  5141.  
  5142.                 if(textColor < COLOR_NONE && magicEffect < MAGIC_EFFECT_NONE)
  5143.                 {
  5144.                     SpectatorVec textList;
  5145.  
  5146.                     if (target->getPosition() != creaturePos) // The target was teleported/moved on statschange, a new spectator list must be created
  5147.                     {
  5148.                         SpectatorVec newList;
  5149.                         getSpectators(newList, targetPos, true, true);
  5150.                         addMagicEffect(newList, targetPos, magicEffect);
  5151.                         for (SpectatorVec::const_iterator it = newList.begin(); it != newList.end(); ++it)
  5152.                         {
  5153.                             if (!(*it)->getPlayer())
  5154.                                 continue;
  5155.  
  5156.                             if ((*it) != attacker && (*it) != target && (*it)->getPosition().z == target->getPosition().z)
  5157.                                 textList.insert(*it);
  5158.                         }
  5159.                     }
  5160.                     else
  5161.                     {
  5162.                         addMagicEffect(list, targetPos, magicEffect);
  5163.                         for (SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
  5164.                         {
  5165.                             if (!(*it)->getPlayer())
  5166.                                 continue;
  5167.  
  5168.                             if ((*it) != attacker && (*it) != target && (*it)->getPosition().z == target->getPosition().z)
  5169.                                 textList.insert(*it);
  5170.                         }
  5171.                     }
  5172.  
  5173.                     MessageDetails* details = new MessageDetails(damage, textColor);
  5174.                     if(elementDamage)
  5175.                     {
  5176.                         getCombatDetails(params.element.type, magicEffect, textColor);
  5177.                         details->sub = new MessageDetails(elementDamage, textColor);
  5178.  
  5179.                         if (target->getPosition() != creaturePos) { // The target was teleported/moved on statschange, a new spectator list must be created
  5180.                             SpectatorVec newList;
  5181.                             getSpectators(newList, targetPos, true, true);
  5182.                             addMagicEffect(newList, targetPos, magicEffect);
  5183.                         }
  5184.                         else
  5185.                             addMagicEffect(list, targetPos, magicEffect);
  5186.                     }
  5187.  
  5188.                     std::ostringstream ss;
  5189.                     int32_t totalDamage = damage + elementDamage;
  5190.  
  5191.                     std::string plural = (totalDamage != 1 ? "s" : "");
  5192.                     if(!textList.empty())
  5193.                     {
  5194.                         if(!attacker)
  5195.                             ss << ucfirst(target->getNameDescription()) << " loses " << totalDamage << " hitpoint" << plural << ".";
  5196.                         else if(attacker != target)
  5197.                             ss << ucfirst(target->getNameDescription()) << " loses " << totalDamage << " hitpoint" << plural << " due to an attack by " << attacker->getNameDescription() << ".";
  5198.                         else
  5199.                             ss << ucfirst(target->getNameDescription()) << " loses " << totalDamage << " hitpoint" << plural << " due to a self attack.";
  5200.  
  5201.                         addStatsMessage(textList, MSG_DAMAGE_OTHERS, ss.str(), targetPos, details);
  5202.                         ss.str("");
  5203.                     }
  5204.  
  5205.                     Player* player = NULL;
  5206.                     if(attacker && (player = attacker->getPlayer()))
  5207.                     {
  5208.                         if(attacker != target)
  5209.                             ss << ucfirst(target->getNameDescription()) << " loses " << totalDamage << " hitpoint" << plural << " due to your attack.";
  5210.                         else
  5211.                             ss << "You lose " << totalDamage << " hitpoint" << plural << " due to your attack.";
  5212.  
  5213.                         player->sendStatsMessage(MSG_DAMAGE_DEALT, ss.str(), targetPos, details);
  5214.                         ss.str("");
  5215.                     }
  5216.  
  5217.                     if((player = target->getPlayer()) && attacker != target)
  5218.                     {
  5219.                         if(attacker)
  5220.                             ss << "You lose " << totalDamage << " hitpoint" << plural << " due to an attack by " << attacker->getNameDescription() << ".";
  5221.                         else
  5222.                             ss << "You lose " << totalDamage << " hitpoint" << plural << ".";
  5223.  
  5224.                         player->sendStatsMessage(MSG_DAMAGE_RECEIVED, ss.str(), targetPos, details);
  5225.                     }
  5226.  
  5227.                     if(details->sub)
  5228.                         delete details->sub;
  5229.  
  5230.                     delete details;
  5231.                 }
  5232.             }
  5233.         }
  5234.     }
  5235.  
  5236.     return true;
  5237. }
  5238.  
  5239. bool Game::combatChangeMana(Creature* attacker, Creature* target, int32_t manaChange,
  5240.     CombatType_t combatType/* = COMBAT_MANADRAIN*/, bool inherited/* = false*/)
  5241. {
  5242.     const Position& targetPos = target->getPosition();
  5243.     if(manaChange > 0)
  5244.     {
  5245.         bool deny = false;
  5246.         CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE);
  5247.         for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it)
  5248.         {
  5249.             if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_MANAGAIN, COMBAT_HEALING, manaChange))
  5250.                 deny = true;
  5251.         }
  5252.  
  5253.         if(deny)
  5254.             return false;
  5255.  
  5256.         int32_t oldMana = target->getMana();
  5257.         target->changeMana(manaChange);
  5258.         if(oldMana != target->getMana() && g_config.getBool(ConfigManager::SHOW_MANA_CHANGE) && !target->isGhost() &&
  5259.             (g_config.getBool(ConfigManager::SHOW_MANA_CHANGE_MONSTER) || !target->getMonster()))
  5260.         {
  5261.             SpectatorVec list;
  5262.             getSpectators(list, targetPos, true, true);
  5263.  
  5264.             SpectatorVec textList;
  5265.             for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
  5266.             {
  5267.                 if(!(*it)->getPlayer())
  5268.                     continue;
  5269.  
  5270.                 if((*it) != attacker && (*it) != target && (*it)->getPosition().z == target->getPosition().z)
  5271.                     textList.insert(*it);
  5272.             }
  5273.  
  5274.             manaChange = (target->getMana() - oldMana);
  5275.             std::string plural = (manaChange != 1 ? "s." : ".");
  5276.  
  5277.             std::ostringstream ss;
  5278.             char buffer[20];
  5279.             sprintf(buffer, "+%d", manaChange);
  5280.             addAnimatedText(list, targetPos, COLOR_DARKPURPLE, buffer);
  5281.             if(!textList.empty())
  5282.             {
  5283.                 if(!attacker)
  5284.                     ss << ucfirst(target->getNameDescription()) << " is regenerated with " << manaChange << " mana" << plural;
  5285.                 else if(attacker != target)
  5286.                     ss << ucfirst(attacker->getNameDescription()) << " regenerates " << target->getNameDescription() << " with " << manaChange << " mana" << plural;
  5287.                 else
  5288.                 {
  5289.                     ss << ucfirst(attacker->getNameDescription()) << " regenerates ";
  5290.                     if(Player* attackerPlayer = attacker->getPlayer())
  5291.                         ss << (attackerPlayer->getSex(false) == PLAYERSEX_FEMALE ? "herself" : "himself") << " with " << manaChange << " mana" << plural;
  5292.                     else
  5293.                         ss << "itself with " << manaChange << " mana" << plural;
  5294.                 }
  5295.  
  5296.                 addStatsMessage(textList, MSG_HEALED_OTHERS, ss.str(), targetPos);
  5297.                 ss.str("");
  5298.             }
  5299.  
  5300.             Player* player = NULL;
  5301.             if(attacker && (player = attacker->getPlayer()))
  5302.             {
  5303.                 if(attacker != target)
  5304.                     ss << "You regenerate " << target->getNameDescription() << " with " << manaChange << " mana" << plural;
  5305.                 else
  5306.                     ss << "You regenerate yourself with " << manaChange << " mana" << plural;
  5307.  
  5308.                 player->sendStatsMessage(MSG_HEALED, ss.str(), targetPos);
  5309.                 ss.str("");
  5310.             }
  5311.  
  5312.             if((player = target->getPlayer()) && attacker != target)
  5313.             {
  5314.                 if(attacker)
  5315.                     ss << ucfirst(attacker->getNameDescription()) << " regenerates you with " << manaChange << " mana" << plural;
  5316.                 else
  5317.                     ss << "You are regenerated with " << manaChange << " mana" << plural;
  5318.  
  5319.                 player->sendStatsMessage(MSG_HEALED, ss.str(), targetPos);
  5320.             }
  5321.         }
  5322.     }
  5323.     else if(!inherited && Combat::canDoCombat(attacker, target, true) != RET_NOERROR)
  5324.     {
  5325.         SpectatorVec list;
  5326.         getSpectators(list, targetPos, true, true);
  5327.         addMagicEffect(list, targetPos, MAGIC_EFFECT_POFF);
  5328.         return false;
  5329.     }
  5330.     else
  5331.     {
  5332.         int32_t manaLoss = std::min(target->getMana(), -manaChange);
  5333.         if(manaLoss > 0)
  5334.         {
  5335.             bool deny = false;
  5336.             CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE);
  5337.             for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it)
  5338.             {
  5339.                 if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_MANALOSS, combatType, manaLoss))
  5340.                     deny = true;
  5341.             }
  5342.  
  5343.             if(deny)
  5344.                 return false;
  5345.  
  5346.             target->drainMana(attacker, combatType, manaLoss);
  5347.             SpectatorVec list;
  5348.             getSpectators(list, targetPos, true, true);
  5349.  
  5350.             SpectatorVec textList;
  5351.             for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
  5352.             {
  5353.                 if(!(*it)->getPlayer())
  5354.                     continue;
  5355.  
  5356.                 if((*it) != attacker && (*it) != target && (*it)->getPosition().z == target->getPosition().z)
  5357.                     textList.insert(*it);
  5358.             }
  5359.  
  5360.             std::ostringstream ss;
  5361.             MessageDetails* details = new MessageDetails(manaLoss, COLOR_BLUE);
  5362.             if(!textList.empty())
  5363.             {
  5364.                 if(!attacker)
  5365.                     ss << ucfirst(target->getNameDescription()) << " loses " << manaLoss << " mana.";
  5366.                 else if(attacker != target)
  5367.                     ss << ucfirst(target->getNameDescription()) << " loses " << manaLoss << " mana due to an attack by " << attacker->getNameDescription();
  5368.                 else
  5369.                     ss << ucfirst(target->getNameDescription()) << " loses " << manaLoss << " mana due to a self attack.";
  5370.  
  5371.                 addStatsMessage(textList, MSG_DAMAGE_OTHERS, ss.str(), targetPos, details);
  5372.                 ss.str("");
  5373.             }
  5374.  
  5375.             Player* player;
  5376.             if(attacker && (player = attacker->getPlayer()))
  5377.             {
  5378.                 if(attacker != target)
  5379.                     ss << ucfirst(target->getNameDescription()) << " loses " << manaLoss << " mana due to your attack.";
  5380.                 else
  5381.                     ss << "You lose " << manaLoss << " mana due to your attack.";
  5382.  
  5383.                 player->sendStatsMessage(MSG_DAMAGE_DEALT, ss.str(), targetPos, details);
  5384.                 ss.str("");
  5385.             }
  5386.  
  5387.             if((player = target->getPlayer()) && attacker != target)
  5388.             {
  5389.                 if(attacker)
  5390.                     ss << "You lose " << manaLoss << " mana due to an attack by " << attacker->getNameDescription();
  5391.                 else
  5392.                     ss << "You lose " << manaLoss << " mana.";
  5393.  
  5394.                 player->sendStatsMessage(MSG_DAMAGE_RECEIVED, ss.str(), targetPos, details);
  5395.             }
  5396.  
  5397.             delete details;
  5398.         }
  5399.     }
  5400.  
  5401.     return true;
  5402. }
  5403.  
  5404. void Game::addCreatureHealth(const Creature* target)
  5405. {
  5406.     SpectatorVec list;
  5407.     getSpectators(list, target->getPosition(), true, true);
  5408.     for (Creature* spectator : list) {
  5409.         spectator->getPlayer()->sendCreatureHealth(target);
  5410.     }
  5411. }
  5412.  
  5413. void Game::addCreatureHealth(const SpectatorVec& list, const Creature* target)
  5414. {
  5415.     Player* player = NULL;
  5416.     for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
  5417.     {
  5418.         if((player = (*it)->getPlayer()))
  5419.             player->sendCreatureHealth(target);
  5420.     }
  5421. }
  5422.  
  5423. void Game::addCreatureSquare(const Creature* target, uint8_t squareColor)
  5424. {
  5425.     SpectatorVec list;
  5426.     getSpectators(list, target->getPosition(), true, true);
  5427.     addCreatureSquare(list, target, squareColor);
  5428. }
  5429.  
  5430. void Game::addCreatureSquare(const SpectatorVec& list, const Creature* target, uint8_t squareColor)
  5431. {
  5432.     Player* player = NULL;
  5433.     for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
  5434.     {
  5435.         if((player = (*it)->getPlayer()))
  5436.             player->sendCreatureSquare(target, squareColor);
  5437.     }
  5438. }
  5439.  
  5440. void Game::addAnimatedText(const Position& pos, uint8_t textColor, const std::string& text)
  5441. {
  5442.     SpectatorVec list;
  5443.     getSpectators(list, pos, true, true);
  5444.     addAnimatedText(list, pos, textColor, text);
  5445. }
  5446.  
  5447. void Game::addAnimatedText(const SpectatorVec& list, const Position& pos, uint8_t textColor,
  5448.     const std::string& text)
  5449. {
  5450.     Player* player = NULL;
  5451.     for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
  5452.     {
  5453.         if((player = (*it)->getPlayer()))
  5454.             player->sendAnimatedText(pos, textColor, text);
  5455.     }
  5456. }
  5457.  
  5458. void Game::addMagicEffect(const Position& pos, uint8_t effect, bool ghostMode/* = false*/)
  5459. {
  5460.     if(ghostMode)
  5461.         return;
  5462.  
  5463.     SpectatorVec list;
  5464.     map->getSpectators(list, pos, true, true);
  5465.     addMagicEffect(list, pos, effect);
  5466. }
  5467.  
  5468. void Game::addMagicEffect(const SpectatorVec& list, const Position& pos, uint8_t effect,
  5469.     bool ghostMode/* = false*/)
  5470. {
  5471.     if(ghostMode)
  5472.         return;
  5473.  
  5474.     Player* player = NULL;
  5475.     for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
  5476.     {
  5477.         if((player = (*it)->getPlayer()))
  5478.             player->sendMagicEffect(pos, effect);
  5479.     }
  5480. }
  5481.  
  5482. void Game::addDistanceEffect(const Position& fromPos, const Position& toPos, uint8_t effect)
  5483. {
  5484.     SpectatorVec list;
  5485.     getSpectators(list, fromPos, false, true);
  5486.     getSpectators(list, toPos, false, true);
  5487.     addDistanceEffect(list, fromPos, toPos, effect);
  5488. }
  5489.  
  5490. void Game::addDistanceEffect(const SpectatorVec& list, const Position& fromPos,
  5491.     const Position& toPos, uint8_t effect)
  5492. {
  5493.     Player* player = NULL;
  5494.     for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
  5495.     {
  5496.         if((player = (*it)->getPlayer()))
  5497.             player->sendDistanceShoot(fromPos, toPos, effect);
  5498.     }
  5499. }
  5500.  
  5501. void Game::addStatsMessage(const SpectatorVec& list, MessageClasses mClass, const std::string& message,
  5502.     const Position& pos, MessageDetails* details/* = NULL*/)
  5503. {
  5504.     Player* player = NULL;
  5505.     for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
  5506.     {
  5507.         if((player = (*it)->getPlayer()))
  5508.             player->sendStatsMessage(mClass, message, pos, details);
  5509.     }
  5510. }
  5511.  
  5512. void Game::startDecay(Item* item)
  5513. {
  5514.     if(!item || !item->canDecay() || item->getDecaying() == DECAYING_TRUE)
  5515.         return;
  5516.  
  5517.     if(item->getDuration() > 0)
  5518.     {
  5519.         item->addRef();
  5520.         item->setDecaying(DECAYING_TRUE);
  5521.         toDecayItems.push_back(item);
  5522.     }
  5523.     else
  5524.         internalDecayItem(item);
  5525. }
  5526.  
  5527. void Game::internalDecayItem(Item* item)
  5528. {
  5529.     const ItemType& it = Item::items.getItemType(item->getID());
  5530.     if(it.decayTo)
  5531.     {
  5532.         Item* newItem = transformItem(item, it.decayTo);
  5533.         startDecay(newItem);
  5534.     }
  5535.     else
  5536.     {
  5537.         ReturnValue ret = internalRemoveItem(NULL, item);
  5538.         if(ret != RET_NOERROR)
  5539.             std::clog << "> DEBUG: internalDecayItem failed, error code: " << (int32_t)ret << ", item id: " << item->getID() << std::endl;
  5540.     }
  5541. }
  5542.  
  5543. void Game::checkDecay()
  5544. {
  5545.     checkDecayEvent = Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_DECAYINTERVAL,
  5546.         boost::bind(&Game::checkDecay, this)));
  5547.  
  5548.     size_t bucket = (lastBucket + 1) % EVENT_DECAYBUCKETS;
  5549.     for (DecayList::iterator it = decayItems[bucket].begin(); it != decayItems[bucket].end();)
  5550.     {
  5551.         Item* item = *it;
  5552.        
  5553.         if (!item) {
  5554.             freeThing(item);
  5555.             it = decayItems[bucket].erase(it);
  5556.             continue;
  5557.         }
  5558.        
  5559.         if (!item->canDecay())
  5560.         {
  5561.             item->setDecaying(DECAYING_FALSE);
  5562.             freeThing(item);
  5563.             it = decayItems[bucket].erase(it);
  5564.             continue;
  5565.         }
  5566.  
  5567.         int32_t duration = item->getDuration();
  5568.         int32_t decreaseTime = std::min<int32_t>(EVENT_DECAYINTERVAL * EVENT_DECAYBUCKETS, duration);
  5569.         if (decreaseTime > duration) {
  5570.             decreaseTime = duration;
  5571.         }
  5572.  
  5573.         duration -= decreaseTime;
  5574.         item->decreaseDuration(decreaseTime);
  5575.  
  5576.         if (duration <= 0)
  5577.         {
  5578.             it = decayItems[bucket].erase(it);
  5579.             internalDecayItem(item);
  5580.             freeThing(item);
  5581.         }
  5582.         else if (duration < EVENT_DECAYINTERVAL * EVENT_DECAYBUCKETS)
  5583.         {
  5584.             it = decayItems[bucket].erase(it);
  5585.             size_t newBucket = (bucket + ((duration + EVENT_DECAYINTERVAL / 2) / 1000)) % EVENT_DECAYBUCKETS;
  5586.             if (newBucket == bucket)
  5587.             {
  5588.                 internalDecayItem(item);
  5589.                 freeThing(item);
  5590.             }
  5591.             else
  5592.                 decayItems[newBucket].push_back(item);
  5593.         }
  5594.         else
  5595.             ++it;
  5596.     }
  5597.  
  5598.     lastBucket = bucket;
  5599.     cleanup();
  5600. }
  5601.  
  5602. void Game::checkLight()
  5603. {
  5604.     checkLightEvent = Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_LIGHTINTERVAL,
  5605.         boost::bind(&Game::checkLight, this)));
  5606.  
  5607.     lightHour = lightHour + lightHourDelta;
  5608.     if(lightHour > 1440)
  5609.         lightHour -= 1440;
  5610.  
  5611.     if(std::abs(lightHour - SUNRISE) < 2 * lightHourDelta)
  5612.         lightState = LIGHT_STATE_SUNRISE;
  5613.     else if(std::abs(lightHour - SUNSET) < 2 * lightHourDelta)
  5614.         lightState = LIGHT_STATE_SUNSET;
  5615.  
  5616.     int32_t newLightLevel = lightLevel;
  5617.     bool lightChange = false;
  5618.     switch(lightState)
  5619.     {
  5620.         case LIGHT_STATE_SUNRISE:
  5621.         {
  5622.             newLightLevel += (LIGHT_LEVEL_DAY - LIGHT_LEVEL_NIGHT) / 30;
  5623.             lightChange = true;
  5624.             break;
  5625.         }
  5626.         case LIGHT_STATE_SUNSET:
  5627.         {
  5628.             newLightLevel -= (LIGHT_LEVEL_DAY - LIGHT_LEVEL_NIGHT) / 30;
  5629.             lightChange = true;
  5630.             break;
  5631.         }
  5632.         default:
  5633.             break;
  5634.     }
  5635.  
  5636.     if(newLightLevel <= LIGHT_LEVEL_NIGHT)
  5637.     {
  5638.         lightLevel = LIGHT_LEVEL_NIGHT;
  5639.         lightState = LIGHT_STATE_NIGHT;
  5640.     }
  5641.     else if(newLightLevel >= LIGHT_LEVEL_DAY)
  5642.     {
  5643.         lightLevel = LIGHT_LEVEL_DAY;
  5644.         lightState = LIGHT_STATE_DAY;
  5645.     }
  5646.     else
  5647.         lightLevel = newLightLevel;
  5648.  
  5649.     if(lightChange)
  5650.     {
  5651.         LightInfo lightInfo;
  5652.         getWorldLightInfo(lightInfo);
  5653.         for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
  5654.         {
  5655.             if(!it->second->hasCustomFlag(PlayerCustomFlag_HasFullLight))
  5656.                 it->second->sendWorldLight(lightInfo);
  5657.         }
  5658.     }
  5659. }
  5660.  
  5661. void Game::checkWars()
  5662. {
  5663.     //executes every EVENT_WARSINTERVAL
  5664.     IOGuild::getInstance()->checkWars();
  5665.     if(checkEndingWars)
  5666.     {
  5667.         //executes every EVENT_WARSINTERVAL*2
  5668.         checkEndingWars = false;
  5669.         IOGuild::getInstance()->checkEndingWars();
  5670.     }
  5671.     else
  5672.         checkEndingWars = true;
  5673.  
  5674.     checkWarsEvent = Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_WARSINTERVAL,
  5675.         boost::bind(&Game::checkWars, this)));
  5676. }
  5677.  
  5678. void Game::getWorldLightInfo(LightInfo& lightInfo)
  5679. {
  5680.     lightInfo.level = lightLevel;
  5681.     lightInfo.color = 0xD7;
  5682. }
  5683.  
  5684. bool Game::cancelRuleViolation(Player* player)
  5685. {
  5686.     RuleViolationsMap::iterator it = ruleViolations.find(player->getID());
  5687.     if(it == ruleViolations.end())
  5688.         return false;
  5689.  
  5690.     Player* gamemaster = it->second->gamemaster;
  5691.     if(!it->second->isOpen && gamemaster) //Send to the responser
  5692.         gamemaster->sendRuleViolationCancel(player->getName());
  5693.     else if(ChatChannel* channel = g_chat.getChannelById(CHANNEL_RVR))
  5694.     {
  5695.         UsersMap tmpMap = channel->getUsers();
  5696.         for(UsersMap::iterator tit = tmpMap.begin(); tit != tmpMap.end(); ++tit)
  5697.             tit->second->sendRemoveReport(player->getName());
  5698.     }
  5699.  
  5700.     //Now erase it
  5701.     ruleViolations.erase(it);
  5702.     return true;
  5703. }
  5704.  
  5705. bool Game::closeRuleViolation(Player* player)
  5706. {
  5707.     RuleViolationsMap::iterator it = ruleViolations.find(player->getID());
  5708.     if(it == ruleViolations.end())
  5709.         return false;
  5710.  
  5711.     ruleViolations.erase(it);
  5712.     player->sendLockRuleViolation();
  5713.     if(ChatChannel* channel = g_chat.getChannelById(CHANNEL_RVR))
  5714.     {
  5715.         UsersMap tmpMap = channel->getUsers();
  5716.         for(UsersMap::iterator tit = tmpMap.begin(); tit != tmpMap.end(); ++tit)
  5717.             tit->second->sendRemoveReport(player->getName());
  5718.     }
  5719.  
  5720.     return true;
  5721. }
  5722.  
  5723. void Game::updateCreatureSkull(Creature* creature)
  5724. {
  5725.     SpectatorVec list;
  5726.     getSpectators(list, creature->getPosition(), true, true);
  5727.  
  5728.     //send to client
  5729.     for (Creature* spectator : list) {
  5730.         spectator->getPlayer()->sendCreatureSkull(creature);
  5731.     }
  5732. }
  5733.  
  5734. void Game::updateCreatureShield(Creature* creature)
  5735. {
  5736.     SpectatorVec list;
  5737.     getSpectators(list, creature->getPosition(), true, true);
  5738.  
  5739.     //send to client
  5740.     for (Creature* spectator : list) {
  5741.         spectator->getPlayer()->sendCreatureShield(creature);
  5742.     }
  5743. }
  5744.  
  5745. void Game::updateCreatureEmblem(Creature* creature)
  5746. {
  5747.     SpectatorVec list;
  5748.     getSpectators(list, creature->getPosition(), true, true);
  5749.  
  5750.     //send to client
  5751.     for (Creature* spectator : list) {
  5752.         spectator->getPlayer()->sendCreatureEmblem(creature);
  5753.     }
  5754. }
  5755.  
  5756. void Game::updateCreatureWalkthrough(Creature* creature)
  5757. {
  5758.     SpectatorVec list;
  5759.     getSpectators(list, creature->getPosition(), true, true);
  5760.  
  5761.     //send to client
  5762.     for (Creature* spectator : list) {
  5763.         spectator->getPlayer()->sendCreatureWalkthrough(creature, spectator->canWalkthrough(creature));
  5764.     }
  5765. }
  5766.  
  5767. bool Game::playerInviteToParty(uint32_t playerId, uint32_t invitedId)
  5768. {
  5769.     Player* player = getPlayerByID(playerId);
  5770.     if(!player || player->isRemoved())
  5771.         return false;
  5772.  
  5773.     if(playerId == invitedId)
  5774.         return false;
  5775.  
  5776.     if(player->hasCondition(CONDITION_EXHAUST, EXHAUST_PARTY))
  5777.     {
  5778.         player->sendTextMessage(MSG_STATUS_SMALL, "You have a few seconds to invite a player to the party.");
  5779.         return false;
  5780.     }
  5781.  
  5782.     if(Condition* conditionparty = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 1000, 0, false, EXHAUST_PARTY))
  5783.         player->addCondition(conditionparty);
  5784.  
  5785.     Player* invitedPlayer = getPlayerByID(invitedId);
  5786.     if(!invitedPlayer || invitedPlayer->isRemoved() || invitedPlayer->isInviting(player))
  5787.         return false;
  5788.  
  5789.     if(invitedPlayer->getParty())
  5790.     {
  5791.         char buffer[90];
  5792.         sprintf(buffer, "%s is already in a party.", invitedPlayer->getName().c_str());
  5793.         player->sendTextMessage(MSG_PARTY, buffer);
  5794.         return false;
  5795.     }
  5796.  
  5797.     Party* party = player->getParty();
  5798.     if(!party)
  5799.         party = new Party(player);
  5800.  
  5801.     return party->getLeader() == player && party->invitePlayer(invitedPlayer);
  5802. }
  5803.  
  5804. bool Game::playerJoinParty(uint32_t playerId, uint32_t leaderId)
  5805. {
  5806.     Player* player = getPlayerByID(playerId);
  5807.     if(!player || player->isRemoved())
  5808.         return false;
  5809.  
  5810.     if(player->hasCondition(CONDITION_EXHAUST, EXHAUST_PARTY))
  5811.     {
  5812.         player->sendTextMessage(MSG_STATUS_SMALL, "You have a few seconds before joining a party again.");
  5813.         return false;
  5814.     }
  5815.  
  5816.     if(Condition* conditionparty = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 1000, 0, false, EXHAUST_PARTY))
  5817.         player->addCondition(conditionparty);
  5818.  
  5819.     Player* leader = getPlayerByID(leaderId);
  5820.     if(!leader || leader->isRemoved() || !leader->isInviting(player))
  5821.         return false;
  5822.  
  5823.     if(!player->getParty())
  5824.         return leader->getParty()->join(player);
  5825.  
  5826.     player->sendTextMessage(MSG_PARTY, "You are already in a party.");
  5827.     return false;
  5828. }
  5829.  
  5830. bool Game::playerRevokePartyInvitation(uint32_t playerId, uint32_t invitedId)
  5831. {
  5832.     Player* player = getPlayerByID(playerId);
  5833.     if(!player || player->isRemoved() || !player->getParty() || player->getParty()->getLeader() != player)
  5834.         return false;
  5835.  
  5836.     Player* invitedPlayer = getPlayerByID(invitedId);
  5837.     if(!invitedPlayer || invitedPlayer->isRemoved() || !player->isInviting(invitedPlayer))
  5838.         return false;
  5839.  
  5840.     player->getParty()->revokeInvitation(invitedPlayer);
  5841.     return true;
  5842. }
  5843.  
  5844. bool Game::playerPassPartyLeadership(uint32_t playerId, uint32_t newLeaderId)
  5845. {
  5846.     Player* player = getPlayerByID(playerId);
  5847.     if(!player || player->isRemoved() || !player->getParty() || player->getParty()->getLeader() != player)
  5848.         return false;
  5849.  
  5850.     if(player->hasCondition(CONDITION_EXHAUST, EXHAUST_PARTY))
  5851.     {
  5852.         player->sendTextMessage(MSG_STATUS_SMALL, "You have a few seconds to pass the party's leadership again.");
  5853.         return false;
  5854.     }
  5855.  
  5856.     if(Condition* conditionparty = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 1000, 0, false, EXHAUST_PARTY))
  5857.         player->addCondition(conditionparty);
  5858.  
  5859.     Player* newLeader = getPlayerByID(newLeaderId);
  5860.     if(!newLeader || newLeader->isRemoved() || !newLeader->getParty() || newLeader->getParty() != player->getParty())
  5861.         return false;
  5862.  
  5863.     return player->getParty()->passLeadership(newLeader);
  5864. }
  5865.  
  5866. bool Game::playerLeaveParty(uint32_t playerId, bool forced/* = false*/)
  5867. {
  5868.     Player* player = getPlayerByID(playerId);
  5869.     if(!player || player->isRemoved() || !player->getParty() || (player->hasCondition(CONDITION_INFIGHT) && !forced))
  5870.         return false;
  5871.  
  5872.     return player->getParty()->leave(player);
  5873. }
  5874.  
  5875. bool Game::playerSharePartyExperience(uint32_t playerId, bool activate)
  5876. {
  5877.     Player* player = getPlayerByID(playerId);
  5878.     if(!player || player->isRemoved())
  5879.         return false;
  5880.  
  5881.     if(!player->getParty() || (!player->hasFlag(PlayerFlag_NotGainInFight)
  5882.         && player->hasCondition(CONDITION_INFIGHT)))
  5883.         return false;
  5884.  
  5885.     return player->getParty()->setSharedExperience(player, activate);
  5886. }
  5887.  
  5888. bool Game::playerReportBug(uint32_t playerId, std::string comment)
  5889. {
  5890.     Player* player = getPlayerByID(playerId);
  5891.     if(!player || player->isRemoved())
  5892.         return false;
  5893.  
  5894.     if(!player->hasFlag(PlayerFlag_CanReportBugs))
  5895.         return false;
  5896.  
  5897.     CreatureEventList reportBugEvents = player->getCreatureEvents(CREATURE_EVENT_REPORTBUG);
  5898.     for(CreatureEventList::iterator it = reportBugEvents.begin(); it != reportBugEvents.end(); ++it)
  5899.         (*it)->executeReportBug(player, comment);
  5900.  
  5901.     return true;
  5902. }
  5903.  
  5904. bool Game::playerReportViolation(uint32_t playerId, ReportType_t type, uint8_t reason, const std::string& name,
  5905.     const std::string& comment, const std::string& translation, uint32_t statementId)
  5906. {
  5907.     Player* player = getPlayerByID(playerId);
  5908.     if(!player || player->isRemoved())
  5909.         return false;
  5910.  
  5911.     CreatureEventList reportViolationEvents = player->getCreatureEvents(CREATURE_EVENT_REPORTVIOLATION);
  5912.     for(CreatureEventList::iterator it = reportViolationEvents.begin(); it != reportViolationEvents.end(); ++it)
  5913.         (*it)->executeReportViolation(player, type, reason, name, comment, translation, statementId);
  5914.  
  5915.     return true;
  5916. }
  5917.  
  5918. bool Game::playerViolationWindow(uint32_t playerId, std::string name, uint8_t reason, ViolationAction_t action,
  5919.     std::string comment, std::string statement, uint32_t statementId, bool ipBanishment)
  5920. {
  5921.     Player* player = getPlayerByID(playerId);
  5922.     if(!player || player->isRemoved())
  5923.         return false;
  5924.  
  5925.     Group* group = player->getGroup();
  5926.     if(!group)
  5927.         return false;
  5928.  
  5929.     time_t length[3] = {0, 0, 0};
  5930.     int32_t pos = 0, start = comment.find("{");
  5931.     while((start = comment.find("{")) > 0 && pos < 4)
  5932.     {
  5933.         std::string::size_type end = comment.find("}", start);
  5934.         if(end == std::string::npos)
  5935.             break;
  5936.  
  5937.         std::string data = comment.substr(start + 1, end - 1);
  5938.         comment = comment.substr(end + 1);
  5939.  
  5940.         ++pos;
  5941.         if(data.empty())
  5942.             continue;
  5943.  
  5944.         if(data == "delete")
  5945.         {
  5946.             action = ACTION_DELETION;
  5947.             continue;
  5948.         }
  5949.  
  5950.         time_t banTime = time(NULL);
  5951.         StringVec vec = explodeString(";", data);
  5952.         for(StringVec::iterator it = vec.begin(); it != vec.end(); ++it)
  5953.         {
  5954.             StringVec tmp = explodeString(",", *it);
  5955.             uint32_t count = 1;
  5956.             if(tmp.size() > 1)
  5957.             {
  5958.                 count = atoi(tmp[1].c_str());
  5959.                 if(!count)
  5960.                     count = 1;
  5961.             }
  5962.  
  5963.             if(tmp[0][0] == 's')
  5964.                 banTime += count;
  5965.             if(tmp[0][0] == 'm')
  5966.                 banTime += count * 60;
  5967.             if(tmp[0][0] == 'h')
  5968.                 banTime += count * 3600;
  5969.             if(tmp[0][0] == 'd')
  5970.                 banTime += count * 86400;
  5971.             if(tmp[0][0] == 'w')
  5972.                 banTime += count * 604800;
  5973.             if(tmp[0][0] == 'm')
  5974.                 banTime += count * 2592000;
  5975.             if(tmp[0][0] == 'y')
  5976.                 banTime += count * 31536000;
  5977.         }
  5978.  
  5979.         if(action == ACTION_DELETION)
  5980.             length[pos - 2] = banTime;
  5981.         else
  5982.             length[pos - 1] = banTime;
  5983.     }
  5984.  
  5985.     int16_t nameFlags = group->getNameViolationFlags(), statementFlags = group->getStatementViolationFlags();
  5986.     if((ipBanishment && ((nameFlags & IPBAN_FLAG) != IPBAN_FLAG || (statementFlags & IPBAN_FLAG) != IPBAN_FLAG)) ||
  5987.         !(nameFlags & (1 << action) || statementFlags & (1 << action)) || reason > group->getViolationReasons())
  5988.     {
  5989.         player->sendCancel("You do not have authorization for this action.");
  5990.         return false;
  5991.     }
  5992.  
  5993.     uint32_t commentSize = g_config.getNumber(ConfigManager::MAX_VIOLATIONCOMMENT_SIZE);
  5994.     if(comment.size() > commentSize)
  5995.     {
  5996.         char buffer[90];
  5997.         sprintf(buffer, "The comment may not exceed limit of %d characters.", commentSize);
  5998.  
  5999.         player->sendCancel(buffer);
  6000.         return false;
  6001.     }
  6002.  
  6003.     toLowerCaseString(name);
  6004.     Player* target = getPlayerByNameEx(name);
  6005.     if(!target || name == "account manager")
  6006.     {
  6007.         player->sendCancel("A player with this name does not exist.");
  6008.         return false;
  6009.     }
  6010.  
  6011.     if(target->hasFlag(PlayerFlag_CannotBeBanned))
  6012.     {
  6013.         player->sendCancel("You do not have authorization for this action.");
  6014.         return false;
  6015.     }
  6016.  
  6017.     Account account = IOLoginData::getInstance()->loadAccount(target->getAccount(), true);
  6018.     enum KickAction {
  6019.         NONE = 1,
  6020.         KICK = 2,
  6021.         FULL_KICK = 3,
  6022.     } kickAction = FULL_KICK;
  6023.  
  6024.     pos = 1;
  6025.     switch(action)
  6026.     {
  6027.         case ACTION_STATEMENT:
  6028.         {
  6029.             StatementMap::iterator it = g_chat.statementMap.find(statementId);
  6030.             if(it == g_chat.statementMap.end())
  6031.             {
  6032.                 player->sendCancel("Statement has been already reported.");
  6033.                 return false;
  6034.             }
  6035.  
  6036.             IOBan::getInstance()->addStatement(target->getGUID(), reason, comment,
  6037.                 player->getGUID(), -1, statement);
  6038.             g_chat.statementMap.erase(it);
  6039.  
  6040.             kickAction = NONE;
  6041.             break;
  6042.         }
  6043.  
  6044.         case ACTION_NAMEREPORT:
  6045.         {
  6046.             int64_t banTime = -1;
  6047.             PlayerBan_t tmp = (PlayerBan_t)g_config.getNumber(ConfigManager::NAME_REPORT_TYPE);
  6048.             if(tmp == PLAYERBAN_BANISHMENT)
  6049.             {
  6050.                 if(!length[0])
  6051.                     banTime = time(NULL) + g_config.getNumber(ConfigManager::BAN_LENGTH);
  6052.                 else
  6053.                     banTime = length[0];
  6054.             }
  6055.  
  6056.             if(!IOBan::getInstance()->addPlayerBanishment(target->getGUID(), banTime, reason, action,
  6057.                 comment, player->getGUID(), tmp))
  6058.             {
  6059.                 player->sendCancel("Player has been already reported.");
  6060.                 return false;
  6061.             }
  6062.             else if(tmp == PLAYERBAN_BANISHMENT)
  6063.                 account.warnings++;
  6064.  
  6065.             kickAction = (KickAction)tmp;
  6066.             break;
  6067.         }
  6068.  
  6069.         case ACTION_NOTATION:
  6070.         {
  6071.             if(!IOBan::getInstance()->addNotation(account.number, reason,
  6072.                 comment, player->getGUID(), target->getGUID()))
  6073.             {
  6074.                 player->sendCancel("Unable to perform action.");
  6075.                 return false;
  6076.             }
  6077.  
  6078.             if(IOBan::getInstance()->getNotationsCount(account.number) < (uint32_t)
  6079.                 g_config.getNumber(ConfigManager::NOTATIONS_TO_BAN))
  6080.             {
  6081.                 kickAction = NONE;
  6082.                 break;
  6083.             }
  6084.  
  6085.             action = ACTION_BANISHMENT;
  6086.         }
  6087.  
  6088.         case ACTION_BANISHMENT:
  6089.         case ACTION_BANREPORT:
  6090.         {
  6091.             bool deny = action != ACTION_BANREPORT;
  6092.             int64_t banTime = -1;
  6093.             pos = 2;
  6094.  
  6095.             account.warnings++;
  6096.             if(account.warnings >= g_config.getNumber(ConfigManager::WARNINGS_TO_DELETION))
  6097.                 action = ACTION_DELETION;
  6098.             else if(length[0])
  6099.                 banTime = length[0];
  6100.             else if(account.warnings >= g_config.getNumber(ConfigManager::WARNINGS_TO_FINALBAN))
  6101.                 banTime = time(NULL) + g_config.getNumber(ConfigManager::FINALBAN_LENGTH);
  6102.             else
  6103.                 banTime = time(NULL) + g_config.getNumber(ConfigManager::BAN_LENGTH);
  6104.  
  6105.             if(!IOBan::getInstance()->addAccountBanishment(account.number, banTime, reason, action,
  6106.                 comment, player->getGUID(), target->getGUID()))
  6107.             {
  6108.                 account.warnings--;
  6109.                 player->sendCancel("Account is already banned.");
  6110.                 return false;
  6111.             }
  6112.  
  6113.             if(deny)
  6114.                 break;
  6115.  
  6116.             banTime = -1;
  6117.             PlayerBan_t tmp = (PlayerBan_t)g_config.getNumber(ConfigManager::NAME_REPORT_TYPE);
  6118.             if(tmp == PLAYERBAN_BANISHMENT)
  6119.             {
  6120.                 if(!length[1])
  6121.                     banTime = time(NULL) + g_config.getNumber(ConfigManager::FINALBAN_LENGTH);
  6122.                 else
  6123.                     banTime = length[1];
  6124.             }
  6125.  
  6126.             IOBan::getInstance()->addPlayerBanishment(target->getGUID(), banTime, reason, action, comment,
  6127.                 player->getGUID(), tmp);
  6128.             break;
  6129.         }
  6130.  
  6131.         case ACTION_BANFINAL:
  6132.         case ACTION_BANREPORTFINAL:
  6133.         {
  6134.             bool allow = action == ACTION_BANREPORTFINAL;
  6135.             int64_t banTime = -1;
  6136.  
  6137.             account.warnings++;
  6138.             if(account.warnings >= g_config.getNumber(ConfigManager::WARNINGS_TO_DELETION))
  6139.                 action = ACTION_DELETION;
  6140.             else if(length[0])
  6141.                 banTime = length[0];
  6142.             else
  6143.                 banTime = time(NULL) + g_config.getNumber(ConfigManager::FINALBAN_LENGTH);
  6144.  
  6145.             if(!IOBan::getInstance()->addAccountBanishment(account.number, banTime, reason, action,
  6146.                 comment, player->getGUID(), target->getGUID()))
  6147.             {
  6148.                 account.warnings--;
  6149.                 player->sendCancel("Account is already banned.");
  6150.                 return false;
  6151.             }
  6152.  
  6153.             if(action != ACTION_DELETION)
  6154.                 account.warnings += (g_config.getNumber(ConfigManager::WARNINGS_TO_FINALBAN) - 1);
  6155.  
  6156.             if(allow)
  6157.                 IOBan::getInstance()->addPlayerBanishment(target->getGUID(), -1, reason, action, comment,
  6158.                     player->getGUID(), (PlayerBan_t)g_config.getNumber(
  6159.                     ConfigManager::NAME_REPORT_TYPE));
  6160.  
  6161.             break;
  6162.         }
  6163.  
  6164.         case ACTION_DELETION:
  6165.         {
  6166.             //completely internal
  6167.             account.warnings++;
  6168.             if(!IOBan::getInstance()->addAccountBanishment(account.number, -1, reason, ACTION_DELETION,
  6169.                 comment, player->getGUID(), target->getGUID()))
  6170.             {
  6171.                 account.warnings--;
  6172.                 player->sendCancel("Account is currently banned or already deleted.");
  6173.                 return false;
  6174.             }
  6175.  
  6176.             break;
  6177.         }
  6178.  
  6179.         default:
  6180.             // these just shouldn't occur in rvw
  6181.             return false;
  6182.     }
  6183.  
  6184.     if(ipBanishment && target->getIP())
  6185.     {
  6186.         if(!length[pos])
  6187.             length[pos] = time(NULL) + g_config.getNumber(ConfigManager::IPBAN_LENGTH);
  6188.  
  6189.         IOBan::getInstance()->addIpBanishment(target->getIP(), length[pos], reason, comment, player->getGUID(), 0xFFFFFFFF);
  6190.     }
  6191.  
  6192.     if(kickAction == FULL_KICK)
  6193.         IOBan::getInstance()->removeNotations(account.number);
  6194.  
  6195.     std::ostringstream ss;
  6196.     if(g_config.getBool(ConfigManager::BROADCAST_BANISHMENTS))
  6197.         ss << player->getName() << " has";
  6198.     else
  6199.         ss << "You have";
  6200.  
  6201.     ss << " taken the action \"" << getAction(action, ipBanishment) << "\"";
  6202.     switch(action)
  6203.     {
  6204.         case ACTION_NOTATION:
  6205.         {
  6206.             ss << " (" << (g_config.getNumber(ConfigManager::NOTATIONS_TO_BAN) - IOBan::getInstance()->getNotationsCount(
  6207.                 account.number)) << " left to banishment)";
  6208.             break;
  6209.         }
  6210.         case ACTION_STATEMENT:
  6211.         {
  6212.             ss << " for the statement: \"" << statement << "\"";
  6213.             break;
  6214.         }
  6215.         default:
  6216.             break;
  6217.     }
  6218.  
  6219.     ss << " against: " << name << " (Warnings: " << account.warnings << "), with reason: \"" << getReason(
  6220.         reason) << "\", and comment: \"" << comment << "\".";
  6221.     if(g_config.getBool(ConfigManager::BROADCAST_BANISHMENTS))
  6222.         broadcastMessage(ss.str(), MSG_STATUS_WARNING);
  6223.     else
  6224.         player->sendTextMessage(MSG_STATUS_CONSOLE_RED, ss.str());
  6225.  
  6226.     if(target->isVirtual())
  6227.     {
  6228.         delete target;
  6229.         target = NULL;
  6230.     }
  6231.     else if(kickAction > NONE)
  6232.     {
  6233.         char buffer[30];
  6234.         sprintf(buffer, "You have been %s.", (kickAction > KICK ? "banished" : "namelocked"));
  6235.         target->sendTextMessage(MSG_INFO_DESCR, buffer);
  6236.  
  6237.         addMagicEffect(target->getPosition(), MAGIC_EFFECT_WRAPS_GREEN);
  6238.         Scheduler::getInstance().addEvent(createSchedulerTask(1000, boost::bind(&Game::kickPlayer, this, target->getID(), false)));
  6239.     }
  6240.  
  6241.     IOLoginData::getInstance()->saveAccount(account);
  6242.     return true;
  6243. }
  6244.  
  6245. void Game::kickPlayer(uint32_t playerId, bool displayEffect)
  6246. {
  6247.     Player* player = getPlayerByID(playerId);
  6248.     if(!player || player->isRemoved())
  6249.         return;
  6250.  
  6251.     player->kick(displayEffect, true);
  6252. }
  6253.  
  6254. bool Game::broadcastMessage(const std::string& text, MessageClasses type)
  6255. {
  6256.     std::clog << "> Broadcasted message: \"" << text << "\"." << std::endl;
  6257.     for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
  6258.         it->second->sendTextMessage(type, text);
  6259.  
  6260.     return true;
  6261. }
  6262.  
  6263. Position Game::getClosestFreeTile(Creature* creature, Position pos, bool extended/* = false*/, bool ignoreHouse/* = true*/)
  6264. {
  6265.     PairVector relList;
  6266.     relList.push_back(PositionPair(0, 0));
  6267.     relList.push_back(PositionPair(-1, -1));
  6268.     relList.push_back(PositionPair(-1, 0));
  6269.     relList.push_back(PositionPair(-1, 1));
  6270.     relList.push_back(PositionPair(0, -1));
  6271.     relList.push_back(PositionPair(0, 1));
  6272.     relList.push_back(PositionPair(1, -1));
  6273.     relList.push_back(PositionPair(1, 0));
  6274.     relList.push_back(PositionPair(1, 1));
  6275.  
  6276.     if(extended)
  6277.     {
  6278.         relList.push_back(PositionPair(-2, 0));
  6279.         relList.push_back(PositionPair(0, -2));
  6280.         relList.push_back(PositionPair(0, 2));
  6281.         relList.push_back(PositionPair(2, 0));
  6282.     }
  6283.  
  6284.     std::random_shuffle(relList.begin() + 1, relList.end());
  6285.     if(Player* player = creature->getPlayer())
  6286.     {
  6287.         for(PairVector::iterator it = relList.begin(); it != relList.end(); ++it)
  6288.         {
  6289.             Tile* tile = map->getTile(Position((pos.x + it->first), (pos.y + it->second), pos.z));
  6290.             if(!tile || !tile->ground)
  6291.                 continue;
  6292.  
  6293.             ReturnValue ret = tile->__queryAdd(0, player, 1, FLAG_IGNOREBLOCKITEM);
  6294.             if(ret == RET_NOTENOUGHROOM || (ret == RET_NOTPOSSIBLE && !player->hasCustomFlag(
  6295.                 PlayerCustomFlag_CanMoveAnywhere)) || (ret == RET_PLAYERISNOTINVITED && !ignoreHouse))
  6296.                 continue;
  6297.  
  6298.             return tile->getPosition();
  6299.         }
  6300.     }
  6301.     else
  6302.     {
  6303.         for(PairVector::iterator it = relList.begin(); it != relList.end(); ++it)
  6304.         {
  6305.             Tile* tile = NULL;
  6306.             if((tile = map->getTile(Position((pos.x + it->first), (pos.y + it->second), pos.z)))
  6307.                 && tile->__queryAdd(0, creature, 1, FLAG_IGNOREBLOCKITEM) == RET_NOERROR)
  6308.                 return tile->getPosition();
  6309.         }
  6310.     }
  6311.  
  6312.     return Position(0, 0, 0);
  6313. }
  6314.  
  6315. std::string Game::getSearchString(const Position& fromPos, const Position& toPos, bool fromIsCreature/* = false*/, bool toIsCreature/* = false*/)
  6316. {
  6317.     /*
  6318.      * When the position is on same level and 0 to 4 squares away, they are "[toIsCreature: standing] next to you"
  6319.      * When the position is on same level and 5 to 100 squares away they are "to the north/west/south/east."
  6320.      * When the position is on any level and 101 to 274 squares away they are "far to the north/west/south/east."
  6321.      * When the position is on any level and 275+ squares away they are "very far to the north/west/south/east."
  6322.      * When the position is not directly north/west/south/east of you they are "((very) far) to the north-west/south-west/south-east/north-east."
  6323.      * When the position is on a lower or higher level and 5 to 100 squares away they are "on a lower (or) higher level to the north/west/south/east."
  6324.      * When the position is on a lower or higher level and 0 to 4 squares away they are "below (or) above you."
  6325.      */
  6326.  
  6327.     enum direction_t
  6328.     {
  6329.         DIR_N, DIR_S, DIR_E, DIR_W,
  6330.         DIR_NE, DIR_NW, DIR_SE, DIR_SW
  6331.     };
  6332.  
  6333.     enum distance_t
  6334.     {
  6335.         DISTANCE_BESIDE,
  6336.         DISTANCE_CLOSE,
  6337.         DISTANCE_FAR,
  6338.         DISTANCE_VERYFAR
  6339.     };
  6340.  
  6341.     enum level_t
  6342.     {
  6343.         LEVEL_HIGHER,
  6344.         LEVEL_LOWER,
  6345.         LEVEL_SAME
  6346.     };
  6347.  
  6348.     direction_t direction;
  6349.     distance_t distance;
  6350.     level_t level;
  6351.  
  6352.     int32_t dx = fromPos.x - toPos.x, dy = fromPos.y - toPos.y, dz = fromPos.z - toPos.z;
  6353.     if(dz > 0)
  6354.         level = LEVEL_HIGHER;
  6355.     else if(dz < 0)
  6356.         level = LEVEL_LOWER;
  6357.     else
  6358.         level = LEVEL_SAME;
  6359.  
  6360.     if(std::abs(dx) < 5 && std::abs(dy) < 5)
  6361.         distance = DISTANCE_BESIDE;
  6362.     else
  6363.     {
  6364.         int32_t tmp = dx * dx + dy * dy;
  6365.         if(tmp < 10000)
  6366.             distance = DISTANCE_CLOSE;
  6367.         else if(tmp < 75625)
  6368.             distance = DISTANCE_FAR;
  6369.         else
  6370.             distance = DISTANCE_VERYFAR;
  6371.     }
  6372.  
  6373.     float tan;
  6374.     if(dx)
  6375.         tan = (float)dy / (float)dx;
  6376.     else
  6377.         tan = 10.;
  6378.  
  6379.     if(std::abs(tan) < 0.4142)
  6380.     {
  6381.         if(dx > 0)
  6382.             direction = DIR_W;
  6383.         else
  6384.             direction = DIR_E;
  6385.     }
  6386.     else if(std::abs(tan) < 2.4142)
  6387.     {
  6388.         if(tan > 0)
  6389.         {
  6390.             if(dy > 0)
  6391.                 direction = DIR_NW;
  6392.             else
  6393.                 direction = DIR_SE;
  6394.         }
  6395.         else
  6396.         {
  6397.             if(dx > 0)
  6398.                 direction = DIR_SW;
  6399.             else
  6400.                 direction = DIR_NE;
  6401.         }
  6402.     }
  6403.     else
  6404.     {
  6405.         if(dy > 0)
  6406.             direction = DIR_N;
  6407.         else
  6408.             direction = DIR_S;
  6409.     }
  6410.  
  6411.     std::ostringstream ss;
  6412.     switch(distance)
  6413.     {
  6414.         case DISTANCE_BESIDE:
  6415.         {
  6416.             switch(level)
  6417.             {
  6418.                 case LEVEL_SAME:
  6419.                 {
  6420.                     ss << "is ";
  6421.                     if(toIsCreature)
  6422.                         ss << "standing ";
  6423.  
  6424.                     ss << "next to you";
  6425.                     break;
  6426.                 }
  6427.  
  6428.                 case LEVEL_HIGHER:
  6429.                 {
  6430.                     ss << "is above ";
  6431.                     if(fromIsCreature)
  6432.                         ss << "you";
  6433.  
  6434.                     break;
  6435.                 }
  6436.  
  6437.                 case LEVEL_LOWER:
  6438.                 {
  6439.                     ss << "is below ";
  6440.                     if(fromIsCreature)
  6441.                         ss << "you";
  6442.  
  6443.                     break;
  6444.                 }
  6445.  
  6446.                 default:
  6447.                     break;
  6448.             }
  6449.  
  6450.             break;
  6451.         }
  6452.  
  6453.         case DISTANCE_CLOSE:
  6454.         {
  6455.             switch(level)
  6456.             {
  6457.                 case LEVEL_SAME:
  6458.                     ss << "is to the";
  6459.                     break;
  6460.                 case LEVEL_HIGHER:
  6461.                     ss << "is on a higher level to the";
  6462.                     break;
  6463.                 case LEVEL_LOWER:
  6464.                     ss << "is on a lower level to the";
  6465.                     break;
  6466.                 default:
  6467.                     break;
  6468.             }
  6469.  
  6470.             break;
  6471.         }
  6472.  
  6473.         case DISTANCE_FAR:
  6474.             ss << "is far to the";
  6475.             break;
  6476.  
  6477.         case DISTANCE_VERYFAR:
  6478.             ss << "is very far to the";
  6479.             break;
  6480.  
  6481.         default:
  6482.             break;
  6483.     }
  6484.  
  6485.     if(distance != DISTANCE_BESIDE)
  6486.     {
  6487.         ss << " ";
  6488.         switch(direction)
  6489.         {
  6490.             case DIR_N:
  6491.                 ss << "north";
  6492.                 break;
  6493.  
  6494.             case DIR_S:
  6495.                 ss << "south";
  6496.                 break;
  6497.  
  6498.             case DIR_E:
  6499.                 ss << "east";
  6500.                 break;
  6501.  
  6502.             case DIR_W:
  6503.                 ss << "west";
  6504.                 break;
  6505.  
  6506.             case DIR_NE:
  6507.                 ss << "north-east";
  6508.                 break;
  6509.  
  6510.             case DIR_NW:
  6511.                 ss << "north-west";
  6512.                 break;
  6513.  
  6514.             case DIR_SE:
  6515.                 ss << "south-east";
  6516.                 break;
  6517.  
  6518.             case DIR_SW:
  6519.                 ss << "south-west";
  6520.                 break;
  6521.  
  6522.             default:
  6523.                 break;
  6524.         }
  6525.     }
  6526.  
  6527.     return ss.str();
  6528. }
  6529.  
  6530. double Game::getExperienceStage(uint32_t level, double divider/* = 1.*/)
  6531. {
  6532.     if(!g_config.getBool(ConfigManager::EXPERIENCE_STAGES))
  6533.         return g_config.getDouble(ConfigManager::RATE_EXPERIENCE) * divider;
  6534.  
  6535.     if(lastStageLevel && level >= lastStageLevel)
  6536.         return stages[lastStageLevel] * divider;
  6537.  
  6538.     return stages[level] * divider;
  6539. }
  6540.  
  6541. bool Game::loadExperienceStages()
  6542. {
  6543.     if(!g_config.getBool(ConfigManager::EXPERIENCE_STAGES))
  6544.     {
  6545.         if(!stages.empty())
  6546.             stages.clear();
  6547.  
  6548.         return true;
  6549.     }
  6550.  
  6551.     xmlDocPtr doc = xmlParseFile(getFilePath(FILE_TYPE_XML, "stages.xml").c_str());
  6552.     if(!doc)
  6553.     {
  6554.         std::clog << "[Warning - Game::loadExperienceStages] Cannot load stages file."
  6555.             << std::endl << getLastXMLError() << std::endl;
  6556.         return false;
  6557.     }
  6558.  
  6559.     xmlNodePtr q, p, root = xmlDocGetRootElement(doc);
  6560.     if(xmlStrcmp(root->name, (const xmlChar*)"stages"))
  6561.     {
  6562.         std::clog << "[Error - Game::loadExperienceStages] Malformed stages file" << std::endl;
  6563.         xmlFreeDoc(doc);
  6564.         return false;
  6565.     }
  6566.  
  6567.     int32_t intValue, low = 0, high = 0;
  6568.     float floatValue, mul = 1.0f, defStageMultiplier;
  6569.     std::string strValue;
  6570.  
  6571.     lastStageLevel = 0;
  6572.     stages.clear();
  6573.  
  6574.     q = root->children;
  6575.     while(q)
  6576.     {
  6577.         if(!xmlStrcmp(q->name, (const xmlChar*)"world"))
  6578.         {
  6579.             if(readXMLString(q, "id", strValue))
  6580.             {
  6581.                 IntegerVec intVector;
  6582.                 if(!parseIntegerVec(strValue, intVector) || std::find(intVector.begin(),
  6583.                     intVector.end(), g_config.getNumber(ConfigManager::WORLD_ID)) == intVector.end())
  6584.                 {
  6585.                     q = q->next;
  6586.                     continue;
  6587.                 }
  6588.             }
  6589.  
  6590.             defStageMultiplier = 1.0f;
  6591.             if(readXMLFloat(q, "multiplier", floatValue))
  6592.                 defStageMultiplier = floatValue;
  6593.  
  6594.             p = q->children;
  6595.             while(p)
  6596.             {
  6597.                 if(!xmlStrcmp(p->name, (const xmlChar*)"stage"))
  6598.                 {
  6599.                     low = 1;
  6600.                     if(readXMLInteger(p, "minlevel", intValue) || readXMLInteger(p, "minLevel", intValue))
  6601.                         low = intValue;
  6602.  
  6603.                     high = 0;
  6604.                     if(readXMLInteger(p, "maxlevel", intValue) || readXMLInteger(p, "maxLevel", intValue))
  6605.                         high = intValue;
  6606.                     else
  6607.                         lastStageLevel = low;
  6608.  
  6609.                     mul = 1.0f;
  6610.                     if(readXMLFloat(p, "multiplier", floatValue))
  6611.                         mul = floatValue;
  6612.  
  6613.                     mul *= defStageMultiplier;
  6614.                     if(lastStageLevel && lastStageLevel == (uint32_t)low)
  6615.                         stages[lastStageLevel] = mul;
  6616.                     else
  6617.                     {
  6618.                         for(int32_t i = low; i <= high; ++i)
  6619.                             stages[i] = mul;
  6620.                     }
  6621.                 }
  6622.  
  6623.                 p = p->next;
  6624.             }
  6625.         }
  6626.  
  6627.         if(!xmlStrcmp(q->name, (const xmlChar*)"stage"))
  6628.         {
  6629.             low = 1;
  6630.             if(readXMLInteger(q, "minlevel", intValue))
  6631.                 low = intValue;
  6632.             else
  6633.  
  6634.             high = 0;
  6635.             if(readXMLInteger(q, "maxlevel", intValue))
  6636.                 high = intValue;
  6637.             else
  6638.                 lastStageLevel = low;
  6639.  
  6640.             mul = 1.0f;
  6641.             if(readXMLFloat(q, "multiplier", floatValue))
  6642.                 mul = floatValue;
  6643.  
  6644.             if(lastStageLevel && lastStageLevel == (uint32_t)low)
  6645.                 stages[lastStageLevel] = mul;
  6646.             else
  6647.             {
  6648.                 for(int32_t i = low; i <= high; ++i)
  6649.                     stages[i] = mul;
  6650.             }
  6651.         }
  6652.  
  6653.         q = q->next;
  6654.     }
  6655.  
  6656.     xmlFreeDoc(doc);
  6657.     return true;
  6658. }
  6659.  
  6660. bool Game::reloadHighscores()
  6661. {
  6662.     lastHighscoreCheck = time(NULL);
  6663.     for(int16_t i = 0; i < 8; ++i)
  6664.         highscoreStorage[i] = getHighscore(i);
  6665.  
  6666.     return true;
  6667. }
  6668.  
  6669. void Game::checkHighscores()
  6670. {
  6671.     reloadHighscores();
  6672.     uint32_t tmp = g_config.getNumber(ConfigManager::HIGHSCORES_UPDATETIME) * 60 * 1000;
  6673.     if(tmp <= 0)
  6674.         return;
  6675.  
  6676.     Scheduler::getInstance().addEvent(createSchedulerTask(tmp, boost::bind(&Game::checkHighscores, this)));
  6677. }
  6678.  
  6679. std::string Game::getHighscoreString(uint16_t skill)
  6680. {
  6681.     Highscore hs = highscoreStorage[skill];
  6682.     std::ostringstream ss;
  6683.     ss << "Highscore for " << getSkillName(skill) << "\n\nRank Level - Player Name";
  6684.     for(uint32_t i = 0; i < hs.size(); ++i)
  6685.         ss << "\n" << (i + 1) << ".  " << hs[i].second << "  -  " << hs[i].first;
  6686.  
  6687.     ss << "\n\nLast updated on:\n" << std::ctime(&lastHighscoreCheck);
  6688.     return ss.str();
  6689. }
  6690.  
  6691. Highscore Game::getHighscore(uint16_t skill)
  6692. {
  6693.     Database* db = Database::getInstance();
  6694.     DBResult* result;
  6695.     std::ostringstream query;
  6696.  
  6697.     Highscore hs;
  6698.     if(skill >= SKILL__MAGLEVEL)
  6699.     {
  6700.         if(skill == SKILL__MAGLEVEL)
  6701.             query << "SELECT `maglevel`, `name` FROM `players` ORDER BY `maglevel` DESC, `manaspent` DESC LIMIT " << g_config.getNumber(ConfigManager::HIGHSCORES_TOP);
  6702.         else
  6703.             query << "SELECT `level`, `name` FROM `players` ORDER BY `level` DESC, `experience` DESC LIMIT " << g_config.getNumber(ConfigManager::HIGHSCORES_TOP);
  6704.  
  6705.         if(!(result = db->storeQuery(query.str())))
  6706.             return hs;
  6707.  
  6708.         do
  6709.         {
  6710.             uint32_t level;
  6711.             if(skill == SKILL__MAGLEVEL)
  6712.                 level = result->getDataInt("maglevel");
  6713.             else
  6714.                 level = result->getDataInt("level");
  6715.  
  6716.             std::string name = result->getDataString("name");
  6717.             if(name.length() > 0)
  6718.                 hs.push_back(std::make_pair(name, level));
  6719.         }
  6720.         while(result->next());
  6721.         result->free();
  6722.     }
  6723.     else
  6724.     {
  6725.         query << "SELECT `player_skills`.`value`, `players`.`name` FROM `player_skills`,`players` WHERE `player_skills`.`skillid`=" << skill << " AND `player_skills`.`player_id`=`players`.`id` ORDER BY `player_skills`.`value` DESC, `player_skills`.`count` DESC LIMIT " << g_config.getNumber(ConfigManager::HIGHSCORES_TOP);
  6726.         if(!(result = db->storeQuery(query.str())))
  6727.             return hs;
  6728.  
  6729.         do
  6730.         {
  6731.             std::string name = result->getDataString("name");
  6732.             if(name.length() > 0)
  6733.                 hs.push_back(std::make_pair(name, result->getDataInt("value")));
  6734.         }
  6735.         while(result->next());
  6736.         result->free();
  6737.     }
  6738.  
  6739.     return hs;
  6740. }
  6741.  
  6742. int32_t Game::getMotdId()
  6743. {
  6744.     if(lastMotd.length() == g_config.getString(ConfigManager::MOTD).length())
  6745.     {
  6746.         if(lastMotd == g_config.getString(ConfigManager::MOTD))
  6747.             return lastMotdId;
  6748.     }
  6749.  
  6750.     lastMotd = g_config.getString(ConfigManager::MOTD);
  6751.     Database* db = Database::getInstance();
  6752.  
  6753.     std::ostringstream query;
  6754.     query << "INSERT INTO `server_motd` (`id`, `world_id`, `text`) VALUES (" << lastMotdId + 1 << ", " << g_config.getNumber(ConfigManager::WORLD_ID) << ", " << db->escapeString(lastMotd) << ")";
  6755.     if(db->query(query.str()))
  6756.         ++lastMotdId;
  6757.  
  6758.     return lastMotdId;
  6759. }
  6760.  
  6761. void Game::loadMotd()
  6762. {
  6763.     Database* db = Database::getInstance();
  6764.     std::ostringstream query;
  6765.     query << "SELECT `id`, `text` FROM `server_motd` WHERE `world_id` = " << g_config.getNumber(ConfigManager::WORLD_ID) << " ORDER BY `id` DESC LIMIT 1";
  6766.  
  6767.     DBResult* result;
  6768.     if(!(result = db->storeQuery(query.str())))
  6769.     {
  6770.         std::clog << "> ERROR: Failed to load motd!" << std::endl;
  6771.         lastMotdId = random_range(5, 500);
  6772.         return;
  6773.     }
  6774.  
  6775.     lastMotdId = result->getDataInt("id");
  6776.     lastMotd = result->getDataString("text");
  6777.     result->free();
  6778. }
  6779.  
  6780. void Game::checkPlayersRecord(Player* player)
  6781. {
  6782.     uint32_t count = getPlayersOnline();
  6783.     if(count <= playersRecord)
  6784.         return;
  6785.  
  6786.     GlobalEventMap recordEvents = g_globalEvents->getEventMap(GLOBALEVENT_RECORD);
  6787.     for(GlobalEventMap::iterator it = recordEvents.begin(); it != recordEvents.end(); ++it)
  6788.         it->second->executeRecord(count, playersRecord, player);
  6789.  
  6790.     playersRecord = count;
  6791. }
  6792.  
  6793. void Game::loadPlayersRecord()
  6794. {
  6795.     Database* db = Database::getInstance();
  6796.     std::ostringstream query;
  6797.     query << "SELECT `record` FROM `server_record` WHERE `world_id` = " << g_config.getNumber(ConfigManager::WORLD_ID) << " ORDER BY `timestamp` DESC LIMIT 1";
  6798.  
  6799.     DBResult* result;
  6800.     if(!(result = db->storeQuery(query.str())))
  6801.     {
  6802.         std::clog << "> ERROR: Failed to load players record!" << std::endl;
  6803.         return;
  6804.     }
  6805.  
  6806.     playersRecord = result->getDataInt("record");
  6807.     result->free();
  6808. }
  6809.  
  6810. bool Game::reloadInfo(ReloadInfo_t reload, uint32_t playerId/* = 0*/, bool completeReload/* = false*/)
  6811. {
  6812.     bool done = false;
  6813.     switch(reload)
  6814.     {
  6815.         case RELOAD_ACTIONS:
  6816.         {
  6817.             if(g_actions->reload())
  6818.                 done = true;
  6819.             else
  6820.                 std::clog << "[Error - Game::reloadInfo] Failed to reload actions." << std::endl;
  6821.  
  6822.             break;
  6823.         }
  6824.  
  6825.         case RELOAD_CHAT:
  6826.         {
  6827.             if(g_chat.reload())
  6828.                 done = true;
  6829.             else
  6830.                 std::clog << "[Error - Game::reloadInfo] Failed to reload chat." << std::endl;
  6831.  
  6832.             break;
  6833.         }
  6834.  
  6835.         case RELOAD_CONFIG:
  6836.         {
  6837.             if(g_config.reload())
  6838.                 done = true;
  6839.             else
  6840.                 std::clog << "[Error - Game::reloadInfo] Failed to reload config." << std::endl;
  6841.  
  6842.             break;
  6843.         }
  6844.  
  6845.         case RELOAD_CREATUREEVENTS:
  6846.         {
  6847.             if(g_creatureEvents->reload())
  6848.                 done = true;
  6849.             else
  6850.                 std::clog << "[Error - Game::reloadInfo] Failed to reload creature events." << std::endl;
  6851.  
  6852.             break;
  6853.         }
  6854.  
  6855. #ifdef __LOGIN_SERVER__
  6856.         case RELOAD_GAMESERVERS:
  6857.         {
  6858.             if(GameServers::getInstance()->reload())
  6859.                 done = true;
  6860.             else
  6861.                 std::clog << "[Error - Game::reloadInfo] Failed to reload game servers." << std::endl;
  6862.  
  6863.             break;
  6864.         }
  6865. #endif
  6866.  
  6867.         case RELOAD_GLOBALEVENTS:
  6868.         {
  6869.             if(g_globalEvents->reload())
  6870.                 done = true;
  6871.             else
  6872.                 std::clog << "[Error - Game::reloadInfo] Failed to reload global events." << std::endl;
  6873.  
  6874.             break;
  6875.         }
  6876.  
  6877.         case RELOAD_HIGHSCORES:
  6878.         {
  6879.             if(reloadHighscores())
  6880.                 done = true;
  6881.             else
  6882.                 std::clog << "[Error - Game::reloadInfo] Failed to reload highscores." << std::endl;
  6883.  
  6884.             break;
  6885.         }
  6886.  
  6887.         case RELOAD_GROUPS:
  6888.         {
  6889.             break;
  6890.         }
  6891.  
  6892.         case RELOAD_ITEMS:
  6893.         {
  6894.             std::clog << "[Notice - Game::reloadInfo] Reload type does not work." << std::endl;
  6895.             done = true;
  6896.             break;
  6897.         }
  6898.  
  6899.         case RELOAD_MODS:
  6900.         {
  6901.             if(ScriptManager::getInstance()->reloadMods())
  6902.                 done = true;
  6903.             else
  6904.                 std::clog << "[Error - Game::reloadInfo] Failed to reload mods." << std::endl;
  6905.  
  6906.             break;
  6907.         }
  6908.  
  6909.         case RELOAD_MONSTERS:
  6910.         {
  6911.             if(g_monsters.reload())
  6912.                 done = true;
  6913.             else
  6914.                 std::clog << "[Error - Game::reloadInfo] Failed to reload monsters." << std::endl;
  6915.  
  6916.             break;
  6917.         }
  6918.  
  6919.         case RELOAD_MOVEEVENTS:
  6920.         {
  6921.             if(g_moveEvents->reload())
  6922.                 done = true;
  6923.             else
  6924.                 std::clog << "[Error - Game::reloadInfo] Failed to reload move events." << std::endl;
  6925.  
  6926.             break;
  6927.         }
  6928.  
  6929.         case RELOAD_NPCS:
  6930.         {
  6931.             g_npcs.reload();
  6932.             done = true;
  6933.             break;
  6934.         }
  6935.  
  6936.         case RELOAD_OUTFITS:
  6937.         {
  6938.             std::clog << "[Notice - Game::reloadInfo] Reload type does not work." << std::endl;
  6939.             done = true;
  6940.             break;
  6941.         }
  6942.  
  6943.         case RELOAD_QUESTS:
  6944.         {
  6945.             if(Quests::getInstance()->reload())
  6946.                 done = true;
  6947.             else
  6948.                 std::clog << "[Error - Game::reloadInfo] Failed to reload quests." << std::endl;
  6949.  
  6950.             break;
  6951.         }
  6952.  
  6953.         case RELOAD_RAIDS:
  6954.         {
  6955.             if(!Raids::getInstance()->reload())
  6956.                 std::clog << "[Error - Game::reloadInfo] Failed to reload raids." << std::endl;
  6957.             else if(!Raids::getInstance()->startup())
  6958.                 std::clog << "[Error - Game::reloadInfo] Failed to startup raids when reloading." << std::endl;
  6959.             else
  6960.                 done = true;
  6961.  
  6962.             break;
  6963.         }
  6964.  
  6965.         case RELOAD_SPELLS:
  6966.         {
  6967.             if(!g_spells->reload())
  6968.                 std::clog << "[Error - Game::reloadInfo] Failed to reload spells." << std::endl;
  6969.             else if(!g_monsters.reload())
  6970.                 std::clog << "[Error - Game::reloadInfo] Failed to reload monsters when reloading spells." << std::endl;
  6971.             else
  6972.                 done = true;
  6973.  
  6974.             break;
  6975.         }
  6976.  
  6977.         case RELOAD_STAGES:
  6978.         {
  6979.             if(loadExperienceStages())
  6980.                 done = true;
  6981.             else
  6982.                 std::clog << "[Error - Game::reloadInfo] Failed to reload stages." << std::endl;
  6983.  
  6984.             break;
  6985.         }
  6986.  
  6987.         case RELOAD_TALKACTIONS:
  6988.         {
  6989.             if(g_talkActions->reload())
  6990.                 done = true;
  6991.             else
  6992.                 std::clog << "[Error - Game::reloadInfo] Failed to reload talk actions." << std::endl;
  6993.  
  6994.             break;
  6995.         }
  6996.  
  6997.         case RELOAD_VOCATIONS:
  6998.         {
  6999.             break;
  7000.         }
  7001.  
  7002.         case RELOAD_WEAPONS:
  7003.         {
  7004.             std::clog << "[Notice - Game::reloadInfo] Reload type does not work." << std::endl;
  7005.             done = true;
  7006.             break;
  7007.         }
  7008.  
  7009.         case RELOAD_ALL:
  7010.         {
  7011.             done = true;
  7012.             for(int32_t i = RELOAD_FIRST; i <= RELOAD_LAST; ++i)
  7013.             {
  7014.                 if(!reloadInfo((ReloadInfo_t)i, 0, true) && done)
  7015.                     done = false;
  7016.             }
  7017.  
  7018.             if(!ScriptManager::getInstance()->reloadMods() && done)
  7019.                 done = false;
  7020.  
  7021.             break;
  7022.         }
  7023.  
  7024.         default:
  7025.         {
  7026.             std::clog << "[Warning - Game::reloadInfo] Reload type not found." << std::endl;
  7027.             break;
  7028.         }
  7029.     }
  7030.  
  7031.     if(reload != RELOAD_CONFIG && reload != RELOAD_MODS && !completeReload && !ScriptManager::getInstance()->reloadMods())
  7032.         std::clog << "[Error - Game::reloadInfo] Failed to reload mods." << std::endl;
  7033.  
  7034.     if(!playerId)
  7035.         return done;
  7036.  
  7037.     Player* player = getPlayerByID(playerId);
  7038.     if(!player || player->isRemoved())
  7039.         return done;
  7040.  
  7041.     if(done)
  7042.     {
  7043.         player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "Reloaded successfully.");
  7044.         return true;
  7045.     }
  7046.  
  7047.     if(reload == RELOAD_ALL)
  7048.         player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "Failed to reload some parts.");
  7049.     else
  7050.         player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "Failed to reload.");
  7051.  
  7052.     return false;
  7053. }
  7054.  
  7055. void Game::prepareGlobalSave(uint8_t minutes)
  7056. {
  7057.     std::clog << "Game::prepareGlobalSave in " << (uint32_t)minutes << " minutes" << std::endl;
  7058.     switch(minutes)
  7059.     {
  7060.         case 5:
  7061.             setGameState(GAMESTATE_CLOSING);
  7062.             broadcastMessage("Server is going down for a global save within 5 minutes. Please logout.", MSG_STATUS_WARNING);
  7063.             Scheduler::getInstance().addEvent(createSchedulerTask(2 * 60000, boost::bind(&Game::prepareGlobalSave, this, 3)));
  7064.             break;
  7065.  
  7066.         case 3:
  7067.             broadcastMessage("Server is going down for a global save within 3 minutes. Please logout.", MSG_STATUS_WARNING);
  7068.             Scheduler::getInstance().addEvent(createSchedulerTask(2 * 60000, boost::bind(&Game::prepareGlobalSave, this, 1)));
  7069.             break;
  7070.  
  7071.         case 1:
  7072.             broadcastMessage("Server is going down for a global save in one minute, please logout!", MSG_STATUS_WARNING);
  7073.             Scheduler::getInstance().addEvent(createSchedulerTask(60000, boost::bind(&Game::prepareGlobalSave, this, 0)));
  7074.             break;
  7075.  
  7076.         case 0:
  7077.             globalSave();
  7078.             break;
  7079.  
  7080.         default:
  7081.             if(minutes > 5)
  7082.                 Scheduler::getInstance().addEvent(createSchedulerTask((minutes - 5) * 1000, boost::bind(&Game::prepareGlobalSave, this, 5)));
  7083.             break;
  7084.     }
  7085. }
  7086.  
  7087. void Game::globalSave()
  7088. {
  7089.     bool close = g_config.getBool(ConfigManager::SHUTDOWN_AT_GLOBALSAVE);
  7090.     if(!close) // check are we're going to close the server
  7091.         Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::setGameState, this, GAMESTATE_CLOSED)));
  7092.  
  7093.     // call the global event
  7094.     g_globalEvents->execute(GLOBALEVENT_GLOBALSAVE);
  7095.     if(close)
  7096.     {
  7097.         //shutdown server
  7098.         Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::setGameState, this, GAMESTATE_SHUTDOWN)));
  7099.         return;
  7100.     }
  7101.  
  7102.     //pay houses
  7103.     Houses::getInstance()->check();
  7104.     //clean map if configured to
  7105.     if(g_config.getBool(ConfigManager::CLEAN_MAP_AT_GLOBALSAVE))
  7106.         cleanMap();
  7107.  
  7108.     //remove premium days globally if configured to
  7109.     if(g_config.getBool(ConfigManager::INIT_PREMIUM_UPDATE))
  7110.         IOLoginData::getInstance()->updatePremiumDays();
  7111.  
  7112.     //reload everything
  7113.     reloadInfo(RELOAD_ALL);
  7114.     //prepare for next global save after 24 hours
  7115.     Scheduler::getInstance().addEvent(createSchedulerTask(((24 * 60 * 60) - (5 * 60)) * 1000, boost::bind(&Game::prepareGlobalSave, this, 5)));
  7116.     //open server
  7117.     Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::setGameState, this, GAMESTATE_NORMAL)));
  7118. }
  7119.  
  7120. void Game::shutdown()
  7121. {
  7122.     std::clog << "Preparing";
  7123.     Scheduler::getInstance().shutdown();
  7124.     std::clog << " to";
  7125.     Dispatcher::getInstance().shutdown();
  7126.     std::clog << " shutdown";
  7127.     Spawns::getInstance()->clear();
  7128.     std::clog << " the";
  7129.     Raids::getInstance()->clear();
  7130.     std::clog << " server... ";
  7131.     cleanup();
  7132.     std::clog << "(done)." << std::endl;
  7133.     if(services)
  7134.         services->stop();
  7135.  
  7136.     exit(0);
  7137.     return;
  7138. }
  7139.  
  7140. void Game::cleanup()
  7141. {
  7142.     //free memory
  7143.     for(std::vector<Thing*>::iterator it = releaseThings.begin(); it != releaseThings.end(); ++it)
  7144.         (*it)->unRef();
  7145.  
  7146.     releaseThings.clear();
  7147.     for(DecayList::iterator it = toDecayItems.begin(); it != toDecayItems.end(); ++it)
  7148.     {
  7149.         int32_t dur = (*it)->getDuration();
  7150.         if(dur >= EVENT_DECAYINTERVAL * EVENT_DECAYBUCKETS)
  7151.             decayItems[lastBucket].push_back(*it);
  7152.         else
  7153.             decayItems[(lastBucket + 1 + (*it)->getDuration() / 1000) % EVENT_DECAYBUCKETS].push_back(*it);
  7154.     }
  7155.  
  7156.     toDecayItems.clear();
  7157. }
  7158.  
  7159. void Game::freeThing(Thing* thing)
  7160. {
  7161.     releaseThings.push_back(thing);
  7162. }
  7163.  
  7164. void Game::showHotkeyUseMessage(Player* player, Item* item)
  7165. {
  7166.     const ItemType& it = Item::items[item->getID()];
  7167.     uint32_t count = player->__getItemTypeCount(item->getID(), item->isFluidContainer() ? item->getFluidType() : -1);
  7168.  
  7169.     std::ostringstream stream;
  7170.     if(!it.showCount)
  7171.         stream << "Using one of " << it.name << "...";
  7172.     else if(count == 1)
  7173.         stream << "Using the last " << it.name.c_str() << "...";
  7174.     else
  7175.         stream << "Using one of " << count << " " << it.pluralName.c_str() << "...";
  7176.  
  7177.     player->sendTextMessage(MSG_HOTKEY_USE, stream.str().c_str());
  7178. }
  7179.  
  7180. void Game::parsePlayerExtendedOpcode(uint32_t playerId, uint8_t opcode, const std::string& buffer)
  7181. {
  7182.     Player* player = getPlayerByID(playerId);
  7183.     if(!player || player->isRemoved())
  7184.         return;
  7185.  
  7186.     CreatureEventList extendedOpcodeEvents = player->getCreatureEvents(CREATURE_EVENT_EXTENDED_OPCODE);
  7187.     for(CreatureEventList::iterator it = extendedOpcodeEvents.begin(); it != extendedOpcodeEvents.end(); ++it)
  7188.         (*it)->executeExtendedOpcode(player, opcode, buffer);
  7189. }
  7190.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement