Advertisement
Guest User

Untitled

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