Advertisement
Guest User

player.cpp

a guest
Jun 28th, 2015
242
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 136.19 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 <iostream>
  19.  
  20. #include "player.h"
  21. #include "manager.h"
  22.  
  23. #include "iologindata.h"
  24. #include "ioban.h"
  25.  
  26. #include "town.h"
  27. #include "house.h"
  28. #include "beds.h"
  29.  
  30. #include "combat.h"
  31. #include "movement.h"
  32. #include "weapons.h"
  33. #include "creatureevent.h"
  34.  
  35. #include "configmanager.h"
  36. #include "game.h"
  37. #include "chat.h"
  38.  
  39. extern ConfigManager g_config;
  40. extern Game g_game;
  41. extern Chat g_chat;
  42. extern MoveEvents* g_moveEvents;
  43. extern Weapons* g_weapons;
  44. extern CreatureEvents* g_creatureEvents;
  45.  
  46. AutoList<Player> Player::autoList;
  47. #ifdef __ENABLE_SERVER_DIAGNOSTIC__
  48. uint32_t Player::playerCount = 0;
  49. #endif
  50. MuteCountMap Player::muteCountMap;
  51.  
  52. Player::Player(const std::string& _name, ProtocolGame* p):
  53.     Creature(), transferContainer(ITEM_LOCKER), name(_name), nameDescription(_name), client(p)
  54. {
  55.     if(client)
  56.         client->setPlayer(this);
  57.  
  58.     pzLocked = isConnecting = addAttackSkillPoint = requestedOutfit = false;
  59.     saving = true;
  60.  
  61.     lastAttackBlockType = BLOCK_NONE;
  62.     chaseMode = CHASEMODE_STANDSTILL;
  63.     fightMode = FIGHTMODE_ATTACK;
  64.     tradeState = TRADE_NONE;
  65.     accountManager = MANAGER_NONE;
  66.     guildLevel = GUILDLEVEL_NONE;
  67.  
  68.     promotionLevel = walkTaskEvent = actionTaskEvent = nextStepEvent = bloodHitCount = shieldBlockCount = 0;
  69.     lastAttack = idleTime = marriage = blessings = balance = premiumDays = mana = manaMax = manaSpent = 0;
  70.     soul = guildId = levelPercent = magLevelPercent = magLevel = experience = damageImmunities = 0;
  71.     conditionImmunities = conditionSuppressions = groupId = vocationId = managerNumber2 = town = skullEnd = 0;
  72.     lastLogin = lastLogout = lastIP = messageTicks = messageBuffer = nextAction = 0;
  73.     editListId = maxWriteLen = windowTextId = rankId = 0;
  74.  
  75.     purchaseCallback = saleCallback = -1;
  76.     level = shootRange = 1;
  77.     rates[SKILL__MAGLEVEL] = rates[SKILL__LEVEL] = 1.0f;
  78.     soulMax = 100;
  79.     capacity = 400.00;
  80.     stamina = STAMINA_MAX;
  81.     lastLoad = lastPing = lastPong = OTSYS_TIME();
  82.  
  83.     writeItem = NULL;
  84.     group = NULL;
  85.     editHouse = NULL;
  86.     shopOwner = NULL;
  87.     tradeItem = NULL;
  88.     tradePartner = NULL;
  89.     walkTask = NULL;
  90.     weapon = NULL;
  91.  
  92.     setVocation(0);
  93.     setParty(NULL);
  94.  
  95.     transferContainer.setParent(NULL);
  96.     for(int32_t i = 0; i < 11; i++)
  97.     {
  98.         inventory[i] = NULL;
  99.         inventoryAbilities[i] = false;
  100.     }
  101.  
  102.     for(int32_t i = SKILL_FIRST; i <= SKILL_LAST; ++i)
  103.     {
  104.         skills[i][SKILL_LEVEL] = 10;
  105.         skills[i][SKILL_TRIES] = skills[i][SKILL_PERCENT] = 0;
  106.         rates[i] = 1.0f;
  107.     }
  108.  
  109.     for(int32_t i = SKILL_FIRST; i <= SKILL_LAST; ++i)
  110.         varSkills[i] = 0;
  111.  
  112.     for(int32_t i = STAT_FIRST; i <= STAT_LAST; ++i)
  113.         varStats[i] = 0;
  114.  
  115.     for(int32_t i = LOSS_FIRST; i <= LOSS_LAST; ++i)
  116.         lossPercent[i] = 100;
  117.  
  118.     for(int32_t i = 0; i <= 12; i++)
  119.         talkState[i] = false;
  120. #ifdef __ENABLE_SERVER_DIAGNOSTIC__
  121.  
  122.     playerCount++;
  123. #endif
  124. }
  125.  
  126. Player::~Player()
  127. {
  128. #ifdef __ENABLE_SERVER_DIAGNOSTIC__
  129.     playerCount--;
  130. #endif
  131.     setWriteItem(NULL);
  132.     for(int32_t i = 0; i < 11; i++)
  133.     {
  134.         if(inventory[i])
  135.         {
  136.             inventory[i]->setParent(NULL);
  137.             inventory[i]->unRef();
  138.  
  139.             inventory[i] = NULL;
  140.             inventoryAbilities[i] = false;
  141.         }
  142.     }
  143.  
  144.     setNextWalkActionTask(NULL);
  145.     transferContainer.setParent(NULL);
  146.     for(DepotMap::iterator it = depots.begin(); it != depots.end(); it++)
  147.         it->second.first->unRef();
  148. }
  149.  
  150. void Player::setVocation(uint32_t id)
  151. {
  152.     vocationId = id;
  153.     vocation = Vocations::getInstance()->getVocation(id);
  154.  
  155.     soulMax = vocation->getGain(GAIN_SOUL);
  156.     if(Condition* condition = getCondition(CONDITION_REGENERATION, CONDITIONID_DEFAULT))
  157.     {
  158.         condition->setParam(CONDITIONPARAM_HEALTHGAIN, vocation->getGainAmount(GAIN_HEALTH));
  159.         condition->setParam(CONDITIONPARAM_HEALTHTICKS, (vocation->getGainTicks(GAIN_HEALTH) * 1000));
  160.         condition->setParam(CONDITIONPARAM_MANAGAIN, vocation->getGainAmount(GAIN_MANA));
  161.         condition->setParam(CONDITIONPARAM_MANATICKS, (vocation->getGainTicks(GAIN_MANA) * 1000));
  162.     }
  163. }
  164.  
  165. bool Player::isPushable() const
  166. {
  167.     return accountManager == MANAGER_NONE && !hasFlag(PlayerFlag_CannotBePushed) && Creature::isPushable();
  168. }
  169.  
  170. std::string Player::getDescription(int32_t lookDistance) const
  171. {
  172.     std::stringstream s;
  173.     if(lookDistance == -1)
  174.     {
  175.         s << "yourself.";
  176.         if(hasFlag(PlayerFlag_ShowGroupNameInsteadOfVocation))
  177.             s << " You are " << group->getName();
  178.         else if(vocationId != 0)
  179.             s << " You are " << vocation->getDescription();
  180.         else
  181.             s << " You have no vocation";
  182.     }
  183.     else
  184.     {
  185.         s << nameDescription;
  186.         if(!hasCustomFlag(PlayerCustomFlag_HideLevel))
  187.             s << " (Level " << level << ")";
  188.  
  189.         s << ". " << (sex % 2 ? "He" : "She");
  190.         if(hasFlag(PlayerFlag_ShowGroupNameInsteadOfVocation))
  191.             s << " is " << group->getName();
  192.         else if(vocationId != 0)
  193.             s << " is " << vocation->getDescription();
  194.         else
  195.             s << " has no vocation";
  196.  
  197.         s << getSpecialDescription();
  198.     }
  199.  
  200.     std::string tmp;
  201.     if(marriage && IOLoginData::getInstance()->getNameByGuid(marriage, tmp))
  202.     {
  203.         s << ", ";
  204.         if(vocationId == 0)
  205.         {
  206.             if(lookDistance == -1)
  207.                 s << "and you are";
  208.             else
  209.                 s << "and is";
  210.  
  211.             s << " ";
  212.         }
  213.  
  214.         s << (sex % 2 ? "husband" : "wife") << " of " << tmp;
  215.     }
  216.  
  217.     s << ".";
  218.     if(guildId)
  219.     {
  220.         if(lookDistance == -1)
  221.             s << " You are ";
  222.         else
  223.             s << " " << (sex % 2 ? "He" : "She") << " is ";
  224.  
  225.         s << (rankName.empty() ? "a member" : rankName)<< " of the " << guildName;
  226.         if(!guildNick.empty())
  227.             s << " (" << guildNick << ")";
  228.  
  229.         s << ".";
  230.     }
  231.  
  232.     return s.str();
  233. }
  234.  
  235. Item* Player::getInventoryItem(slots_t slot) const
  236. {
  237.     if(slot > SLOT_PRE_FIRST && slot < SLOT_LAST)
  238.         return inventory[slot];
  239.  
  240.     if(slot == SLOT_HAND)
  241.         return inventory[SLOT_LEFT] ? inventory[SLOT_LEFT] : inventory[SLOT_RIGHT];
  242.  
  243.     return NULL;
  244. }
  245.  
  246. Item* Player::getEquippedItem(slots_t slot) const
  247. {
  248.     Item* item = getInventoryItem(slot);
  249.     if(!item)
  250.         return NULL;
  251.  
  252.     switch(slot)
  253.     {
  254.         case SLOT_LEFT:
  255.         case SLOT_RIGHT:
  256.             return item->getWieldPosition() == SLOT_HAND ? item : NULL;
  257.  
  258.         default:
  259.             break;
  260.     }
  261.  
  262.     return item->getWieldPosition() == slot ? item : NULL;
  263. }
  264.  
  265. void Player::setConditionSuppressions(uint32_t conditions, bool remove)
  266. {
  267.     if(remove)
  268.         conditionSuppressions &= ~conditions;
  269.     else
  270.         conditionSuppressions |= conditions;
  271. }
  272.  
  273. Item* Player::getWeapon(bool ignoreAmmo)
  274. {
  275.     if(weapon)
  276.         return weapon;
  277.  
  278.     Item* item = NULL;
  279.     for(int32_t slot = SLOT_RIGHT; slot <= SLOT_LEFT; ++slot)
  280.     {
  281.         if(!(item = getEquippedItem((slots_t)slot)) || item->getWeaponType() != WEAPON_DIST)
  282.             continue;
  283.  
  284.         if(!ignoreAmmo && item->getAmmoType() != AMMO_NONE)
  285.         {
  286.             Item* ammoItem = getInventoryItem(SLOT_AMMO);
  287.             if(ammoItem && ammoItem->getAmmoType() == item->getAmmoType())
  288.             {
  289.                 if(g_weapons->getWeapon(ammoItem))
  290.                 {
  291.                     shootRange = item->getShootRange();
  292.                     return ammoItem;
  293.                 }
  294.             }
  295.         }
  296.         else if(g_weapons->getWeapon(item))
  297.         {
  298.             shootRange = item->getShootRange();
  299.             return item;
  300.         }
  301.     }
  302.  
  303.     return NULL;
  304. }
  305.  
  306. ItemVector Player::getWeapons() const
  307. {
  308.     Item* item = NULL;
  309.     ItemVector weapons;
  310.     for(int32_t slot = SLOT_RIGHT; slot <= SLOT_LEFT; ++slot)
  311.     {
  312.         if(!(item = getEquippedItem((slots_t)slot)))
  313.             continue;
  314.  
  315.         switch(item->getWeaponType())
  316.         {
  317.             case WEAPON_DIST:
  318.                 if(item->getAmmoType() != AMMO_NONE)
  319.                     break;
  320.  
  321.             case WEAPON_SWORD:
  322.             case WEAPON_CLUB:
  323.             case WEAPON_AXE:
  324.             case WEAPON_FIST:
  325.             case WEAPON_WAND:
  326.             {
  327.                 if(g_weapons->getWeapon(item))
  328.                     weapons.push_back(item);
  329.  
  330.                 break;
  331.             }
  332.  
  333.             default:
  334.                 break;
  335.         }
  336.     }
  337.  
  338.     return weapons;
  339. }
  340.  
  341. void Player::updateWeapon()
  342. {
  343.     ItemVector weapons = getWeapons();
  344.     if(weapons.empty())
  345.         weapon = NULL;
  346.     else if(!weapon || weapons.size() == 1 || weapons[1] == weapon)
  347.         weapon = weapons[0];
  348.     else if(weapons[0] == weapon)
  349.         weapon = weapons[1];
  350.     else
  351.         weapon = NULL;
  352.  
  353.     if(weapon)
  354.         shootRange = weapon->getShootRange();
  355. }
  356.  
  357. WeaponType_t Player::getWeaponType()
  358. {
  359.     if(Item* item = getWeapon(false))
  360.         return item->getWeaponType();
  361.  
  362.     return WEAPON_NONE;
  363. }
  364.  
  365. int32_t Player::getWeaponSkill(const Item* item) const
  366. {
  367.     if(!item)
  368.         return getSkill(SKILL_FIST, SKILL_LEVEL);
  369.  
  370.     switch(item->getWeaponType())
  371.     {
  372.         case WEAPON_SWORD:
  373.             return getSkill(SKILL_SWORD, SKILL_LEVEL);
  374.  
  375.         case WEAPON_CLUB:
  376.             return getSkill(SKILL_CLUB, SKILL_LEVEL);
  377.  
  378.         case WEAPON_AXE:
  379.             return getSkill(SKILL_AXE, SKILL_LEVEL);
  380.  
  381.         case WEAPON_FIST:
  382.             return getSkill(SKILL_FIST, SKILL_LEVEL);
  383.  
  384.         case WEAPON_DIST:
  385.             return getSkill(SKILL_DIST, SKILL_LEVEL);
  386.  
  387.         default:
  388.             break;
  389.     }
  390.  
  391.     return 0;
  392. }
  393.  
  394. int32_t Player::getArmor() const
  395. {
  396.     int32_t i = SLOT_FIRST, armor = 0;
  397.     for(; i < SLOT_LAST; ++i)
  398.     {
  399.         if(Item* item = getInventoryItem((slots_t)i))
  400.             armor += item->getArmor();
  401.     }
  402.  
  403.     if(vocation->getMultiplier(MULTIPLIER_ARMOR) != 1.0)
  404.         return int32_t(armor * vocation->getMultiplier(MULTIPLIER_ARMOR));
  405.  
  406.     return armor;
  407. }
  408.  
  409. void Player::getShieldAndWeapon(const Item* &_shield, const Item* &_weapon) const
  410. {
  411.     _shield = NULL;
  412.     Item* item = NULL;
  413.     for(uint32_t slot = SLOT_RIGHT; slot <= SLOT_LEFT; ++slot)
  414.     {
  415.         if(!(item = getInventoryItem((slots_t)slot)) || item->getWeaponType() != WEAPON_SHIELD)
  416.             continue;
  417.  
  418.         if(!_shield || (_shield && item->getDefense() > _shield->getDefense()))
  419.             _shield = item;
  420.     }
  421.  
  422.     _weapon = weapon;
  423. }
  424.  
  425. int32_t Player::getDefense() const
  426. {
  427.     int32_t baseDefense = 5, defenseValue = 0, defenseSkill = 0, extraDefense = 0;
  428.     float defenseFactor = getDefenseFactor();
  429.  
  430.     const Item *_weapon = NULL, *_shield = NULL;
  431.     getShieldAndWeapon(_shield, _weapon);
  432.     if(_weapon)
  433.     {
  434.         extraDefense = _weapon->getExtraDefense();
  435.         defenseValue = baseDefense + _weapon->getDefense();
  436.         defenseSkill = getWeaponSkill(_weapon);
  437.     }
  438.  
  439.     if(_shield && _shield->getDefense() > defenseValue)
  440.     {
  441.         if(_shield->getExtraDefense() > extraDefense)
  442.             extraDefense = _shield->getExtraDefense();
  443.  
  444.         defenseValue = baseDefense + _shield->getDefense();
  445.         defenseSkill = getSkill(SKILL_SHIELD, SKILL_LEVEL);
  446.     }
  447.  
  448.     if(!defenseSkill)
  449.         return 0;
  450.  
  451.     defenseValue += extraDefense;
  452.     if(vocation->getMultiplier(MULTIPLIER_DEFENSE) != 1.0)
  453.         defenseValue = int32_t(defenseValue * vocation->getMultiplier(MULTIPLIER_DEFENSE));
  454.  
  455.     return ((int32_t)std::ceil(((float)(defenseSkill * (defenseValue * 0.015)) + (defenseValue * 0.1)) * defenseFactor));
  456. }
  457.  
  458. float Player::getAttackFactor() const
  459. {
  460.     switch(fightMode)
  461.     {
  462.         case FIGHTMODE_BALANCED:
  463.             return 1.2f;
  464.  
  465.         case FIGHTMODE_DEFENSE:
  466.             return 2.0f;
  467.  
  468.         case FIGHTMODE_ATTACK:
  469.         default:
  470.             break;
  471.     }
  472.  
  473.     return 1.0f;
  474. }
  475.  
  476. float Player::getDefenseFactor() const
  477. {
  478.     switch(fightMode)
  479.     {
  480.         case FIGHTMODE_BALANCED:
  481.             return 1.2f;
  482.  
  483.         case FIGHTMODE_DEFENSE:
  484.         {
  485.             if((OTSYS_TIME() - lastAttack) < getAttackSpeed()) //attacking will cause us to get into normal defense
  486.                 return 1.0f;
  487.  
  488.             return 2.0f;
  489.         }
  490.  
  491.         case FIGHTMODE_ATTACK:
  492.         default:
  493.             break;
  494.     }
  495.  
  496.     return 1.0f;
  497. }
  498.  
  499. void Player::sendIcons() const
  500. {
  501.     if(!client)
  502.         return;
  503.  
  504.     uint32_t icons = 0;
  505.     for(ConditionList::const_iterator it = conditions.begin(); it != conditions.end(); ++it)
  506.     {
  507.         if(!isSuppress((*it)->getType()))
  508.             icons |= (*it)->getIcons();
  509.     }
  510.  
  511.     if(getZone() == ZONE_PROTECTION)
  512.         icons |= ICON_PROTECTIONZONE;
  513.  
  514.     if(pzLocked)
  515.         icons |= ICON_PZ;
  516.  
  517.     client->sendIcons(icons);
  518. }
  519.  
  520. void Player::updateInventoryWeight()
  521. {
  522.     inventoryWeight = 0.00;
  523.     if(hasFlag(PlayerFlag_HasInfiniteCapacity))
  524.         return;
  525.  
  526.     for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i)
  527.     {
  528.         if(Item* item = getInventoryItem((slots_t)i))
  529.             inventoryWeight += item->getWeight();
  530.     }
  531. }
  532.  
  533. void Player::updateInventoryGoods(uint32_t itemId)
  534. {
  535.     if(Item::items[itemId].worth)
  536.     {
  537.         sendGoods();
  538.         return;
  539.     }
  540.  
  541.     for(ShopInfoList::iterator it = shopOffer.begin(); it != shopOffer.end(); ++it)
  542.     {
  543.         if(it->itemId != itemId)
  544.             continue;
  545.  
  546.         sendGoods();
  547.         break;
  548.     }
  549. }
  550.  
  551. int32_t Player::getPlayerInfo(playerinfo_t playerinfo) const
  552. {
  553.     switch(playerinfo)
  554.     {
  555.         case PLAYERINFO_LEVEL:
  556.             return level;
  557.         case PLAYERINFO_LEVELPERCENT:
  558.             return levelPercent;
  559.         case PLAYERINFO_MAGICLEVEL:
  560.             return std::max((int32_t)0, ((int32_t)magLevel + varStats[STAT_MAGICLEVEL]));
  561.         case PLAYERINFO_MAGICLEVELPERCENT:
  562.             return magLevelPercent;
  563.         case PLAYERINFO_HEALTH:
  564.             return health;
  565.         case PLAYERINFO_MAXHEALTH:
  566.             return std::max((int32_t)1, ((int32_t)healthMax + varStats[STAT_MAXHEALTH]));
  567.         case PLAYERINFO_MANA:
  568.             return mana;
  569.         case PLAYERINFO_MAXMANA:
  570.             return std::max((int32_t)0, ((int32_t)manaMax + varStats[STAT_MAXMANA]));
  571.         case PLAYERINFO_SOUL:
  572.             return std::max((int32_t)0, ((int32_t)soul + varStats[STAT_SOUL]));
  573.         default:
  574.             break;
  575.     }
  576.  
  577.     return 0;
  578. }
  579.  
  580. int32_t Player::getSkill(skills_t skilltype, skillsid_t skillinfo) const
  581. {
  582.     int32_t ret = skills[skilltype][skillinfo];
  583.     if(skillinfo == SKILL_LEVEL)
  584.         ret += varSkills[skilltype];
  585.  
  586.     return std::max((int32_t)0, ret);
  587. }
  588.  
  589. void Player::addSkillAdvance(skills_t skill, uint64_t count, bool useMultiplier/* = true*/)
  590. {
  591.     if(!count)
  592.         return;
  593.  
  594.     //player has reached max skill
  595.     uint64_t currReqTries = vocation->getReqSkillTries(skill, skills[skill][SKILL_LEVEL]),
  596.         nextReqTries = vocation->getReqSkillTries(skill, skills[skill][SKILL_LEVEL] + 1);
  597.     if(currReqTries > nextReqTries)
  598.         return;
  599.  
  600.     if(useMultiplier)
  601.         count = uint64_t((double)count * rates[skill] * g_config.getDouble(ConfigManager::RATE_SKILL));
  602.  
  603.     std::stringstream s;
  604.     while(skills[skill][SKILL_TRIES] + count >= nextReqTries)
  605.     {
  606.         count -= nextReqTries - skills[skill][SKILL_TRIES];
  607.         skills[skill][SKILL_TRIES] = skills[skill][SKILL_PERCENT] = 0;
  608.         skills[skill][SKILL_LEVEL]++;
  609.  
  610.         s.str("");
  611.         s << "You advanced in " << getSkillName(skill);
  612.         if(g_config.getBool(ConfigManager::ADVANCING_SKILL_LEVEL))
  613.             s << " [" << skills[skill][SKILL_LEVEL] << "]";
  614.  
  615.         s << ".";
  616.         sendTextMessage(MSG_EVENT_ADVANCE, s.str().c_str());
  617.  
  618.         CreatureEventList advanceEvents = getCreatureEvents(CREATURE_EVENT_ADVANCE);
  619.         for(CreatureEventList::iterator it = advanceEvents.begin(); it != advanceEvents.end(); ++it)
  620.             (*it)->executeAdvance(this, skill, (skills[skill][SKILL_LEVEL] - 1), skills[skill][SKILL_LEVEL]);
  621.  
  622.         currReqTries = nextReqTries;
  623.         nextReqTries = vocation->getReqSkillTries(skill, skills[skill][SKILL_LEVEL] + 1);
  624.         if(currReqTries > nextReqTries)
  625.         {
  626.             count = 0;
  627.             break;
  628.         }
  629.     }
  630.  
  631.     if(count)
  632.         skills[skill][SKILL_TRIES] += count;
  633.  
  634.     //update percent
  635.     uint16_t newPercent = Player::getPercentLevel(skills[skill][SKILL_TRIES], nextReqTries);
  636.     if(skills[skill][SKILL_PERCENT] != newPercent)
  637.     {
  638.         skills[skill][SKILL_PERCENT] = newPercent;
  639.         sendSkills();
  640.     }
  641.     else if(!s.str().empty())
  642.         sendSkills();
  643. }
  644.  
  645. void Player::setVarStats(stats_t stat, int32_t modifier)
  646. {
  647.     varStats[stat] += modifier;
  648.     switch(stat)
  649.     {
  650.         case STAT_MAXHEALTH:
  651.         {
  652.             if(getHealth() > getMaxHealth())
  653.                 Creature::changeHealth(getMaxHealth() - getHealth());
  654.             else
  655.                 g_game.addCreatureHealth(this);
  656.  
  657.             break;
  658.         }
  659.  
  660.         case STAT_MAXMANA:
  661.         {
  662.             if(getMana() > getMaxMana())
  663.                 Creature::changeMana(getMaxMana() - getMana());
  664.  
  665.             break;
  666.         }
  667.  
  668.         default:
  669.             break;
  670.     }
  671. }
  672.  
  673. int32_t Player::getDefaultStats(stats_t stat)
  674. {
  675.     switch(stat)
  676.     {
  677.         case STAT_MAGICLEVEL:
  678.             return getMagicLevel() - getVarStats(STAT_MAGICLEVEL);
  679.         case STAT_MAXHEALTH:
  680.             return getMaxHealth() - getVarStats(STAT_MAXHEALTH);
  681.         case STAT_MAXMANA:
  682.             return getMaxMana() - getVarStats(STAT_MAXMANA);
  683.         case STAT_SOUL:
  684.             return getSoul() - getVarStats(STAT_SOUL);
  685.         default:
  686.             break;
  687.     }
  688.  
  689.     return 0;
  690. }
  691.  
  692. Container* Player::getContainer(uint32_t cid)
  693. {
  694.     for(ContainerVector::iterator it = containerVec.begin(); it != containerVec.end(); ++it)
  695.     {
  696.         if(it->first == cid)
  697.             return it->second;
  698.     }
  699.  
  700.     return NULL;
  701. }
  702.  
  703. int32_t Player::getContainerID(const Container* container) const
  704. {
  705.     for(ContainerVector::const_iterator cl = containerVec.begin(); cl != containerVec.end(); ++cl)
  706.     {
  707.         if(cl->second == container)
  708.             return cl->first;
  709.     }
  710.  
  711.     return -1;
  712. }
  713.  
  714. void Player::addContainer(uint32_t cid, Container* container)
  715. {
  716. #ifdef __DEBUG__
  717.     std::clog << getName() << ", addContainer: " << (int32_t)cid << std::endl;
  718. #endif
  719.     if(cid > 0xF)
  720.         return;
  721.  
  722.     for(ContainerVector::iterator cl = containerVec.begin(); cl != containerVec.end(); ++cl)
  723.     {
  724.         if(cl->first == cid)
  725.         {
  726.             cl->second = container;
  727.             return;
  728.         }
  729.     }
  730.  
  731.     containerVec.push_back(std::make_pair(cid, container));
  732. }
  733.  
  734. void Player::closeContainer(uint32_t cid)
  735. {
  736.     for(ContainerVector::iterator cl = containerVec.begin(); cl != containerVec.end(); ++cl)
  737.     {
  738.         if(cl->first == cid)
  739.         {
  740.             containerVec.erase(cl);
  741.             break;
  742.         }
  743.     }
  744. #ifdef __DEBUG__
  745.  
  746.     std::clog << getName() << ", closeContainer: " << (int32_t)cid << std::endl;
  747. #endif
  748. }
  749.  
  750. bool Player::canOpenCorpse(uint32_t ownerId)
  751. {
  752.     return guid == ownerId || (party && party->canOpenCorpse(ownerId)) || hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges);
  753. }
  754.  
  755. uint16_t Player::getLookCorpse() const
  756. {
  757.     if(sex % 2)
  758.         return ITEM_MALE_CORPSE;
  759.  
  760.     return ITEM_FEMALE_CORPSE;
  761. }
  762.  
  763. void Player::dropLoot(Container* corpse)
  764. {
  765.     if(!corpse || lootDrop != LOOT_DROP_FULL)
  766.         return;
  767.  
  768.     uint32_t loss = lossPercent[LOSS_CONTAINERS];
  769.     if(g_config.getBool(ConfigManager::BLESSINGS))
  770.     {
  771.         uint32_t start = g_config.getNumber(ConfigManager::BLESS_REDUCTION_BASE), bless = getBlessings();
  772.         while(bless > 0 && loss > 0)
  773.         {
  774.             loss -= start;
  775.             start -= g_config.getNumber(ConfigManager::BLESS_REDUCTION_DECREMENT);
  776.             bless--;
  777.         }
  778.     }
  779.  
  780.     uint32_t itemLoss = (uint32_t)std::floor((5. + loss) * lossPercent[LOSS_ITEMS] / 1000.);
  781.     for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i)
  782.     {
  783.         Item* item = inventory[i];
  784.         if(!item)
  785.             continue;
  786.  
  787.         uint32_t tmp = random_range(1, 100);
  788.         if(skull > SKULL_BLACK || (item->getContainer() && tmp < loss) || (!item->getContainer() && tmp < itemLoss))
  789.         {
  790.             g_game.internalMoveItem(NULL, this, corpse, INDEX_WHEREEVER, item, item->getItemCount(), 0);
  791.             sendRemoveInventoryItem((slots_t)i, inventory[(slots_t)i]);
  792.         }
  793.     }
  794. }
  795.  
  796. bool Player::setStorage(const std::string& key, const std::string& value)
  797. {
  798.     uint32_t numericKey = atol(key.c_str());
  799.     if(!IS_IN_KEYRANGE(numericKey, RESERVED_RANGE))
  800.         return Creature::setStorage(key, value);
  801.  
  802.     if(IS_IN_KEYRANGE(numericKey, OUTFITS_RANGE))
  803.     {
  804.         uint32_t lookType = atoi(value.c_str()) >> 16, addons = atoi(value.c_str()) & 0xFF;
  805.         if(addons < 4)
  806.         {
  807.             Outfit outfit;
  808.             if(Outfits::getInstance()->getOutfit(lookType, outfit))
  809.                 return addOutfit(outfit.outfitId, addons);
  810.         }
  811.         else
  812.             std::clog << "[Warning - Player::setStorage] Invalid addons value key: " << key
  813.                 << ", value: " << value << " for player: " << getName() << std::endl;
  814.     }
  815.     else if(IS_IN_KEYRANGE(numericKey, OUTFITSID_RANGE))
  816.     {
  817.         uint32_t outfitId = atoi(value.c_str()) >> 16, addons = atoi(value.c_str()) & 0xFF;
  818.         if(addons < 4)
  819.             return addOutfit(outfitId, addons);
  820.         else
  821.             std::clog << "[Warning - Player::setStorage] Invalid addons value key: " << key
  822.                 << ", value: " << value << " for player: " << getName() << std::endl;
  823.     }
  824.     else
  825.         std::clog << "[Warning - Player::setStorage] Unknown reserved key: " << key << " for player: " << getName() << std::endl;
  826.  
  827.     return false;
  828. }
  829.  
  830. void Player::eraseStorage(const std::string& key)
  831. {
  832.     Creature::eraseStorage(key);
  833.     if(IS_IN_KEYRANGE(atol(key.c_str()), RESERVED_RANGE))
  834.         std::clog << "[Warning - Player::eraseStorage] Unknown reserved key: " << key << " for player: " << name << std::endl;
  835. }
  836.  
  837. bool Player::canSee(const Position& pos) const
  838. {
  839.     if(client)
  840.         return client->canSee(pos);
  841.  
  842.     return false;
  843. }
  844.  
  845. bool Player::canSeeCreature(const Creature* creature) const
  846. {
  847.     if(creature == this)
  848.         return true;
  849.  
  850.     if(const Player* player = creature->getPlayer())
  851.         return !player->isGhost() || getGhostAccess() >= player->getGhostAccess();
  852.  
  853.     return !creature->isInvisible() || canSeeInvisibility();
  854. }
  855.  
  856. bool Player::canWalkthrough(const Creature* creature) const
  857. {
  858.     if(creature == this || creature->isWalkable() ||
  859.         (creature->getMaster() && creature->getMaster() != this && canWalkthrough(creature->getMaster())))
  860.         return true;
  861.        
  862.     if(creature->getNpc())
  863.         return true;
  864.        
  865.     const Player* player = creature->getPlayer();
  866.     if(!player)
  867.         return false;
  868.  
  869.     if(
  870.         (
  871.             (
  872.                 (
  873.                     (
  874.                         player->getVocation()->isAttackable() &&
  875.                         player->getLevel() < (uint32_t)g_config.getNumber(ConfigManager::PROTECTION_LEVEL)
  876.                     )
  877.                     || (
  878.                         player->getTile()->hasFlag(TILESTATE_PROTECTIONZONE) &&
  879.                         !player->getTile()->hasFlag(TILESTATE_HOUSE)
  880.                     )
  881.                 )
  882.             ) && player->getTile()->ground &&
  883.                 player->getTile()->ground->getID() != 11063
  884.         ) && (
  885.             !player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges)
  886.             || player->getAccess() <= getAccess()
  887.         )
  888.     ) return true;
  889.  
  890.        
  891.     if((((g_game.getWorldType() == WORLDTYPE_OPTIONAL &&
  892. #ifdef __WAR_SYSTEM__
  893.         !player->isEnemy(this, true) &&
  894. #endif
  895.         player->getVocation()->isAttackable()) || (player->getVocation()->isAttackable() &&
  896.         player->getLevel() < (uint32_t)g_config.getNumber(ConfigManager::PROTECTION_LEVEL))) && player->getTile()->ground &&
  897.         Item::items[player->getTile()->ground->getID()].walkStack) && (!player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges)
  898.         || player->getAccess() <= getAccess()))
  899.         return true;
  900.  
  901.     return (player->isGhost() && getGhostAccess() < player->getGhostAccess())
  902.         || (isGhost() && getGhostAccess() > player->getGhostAccess());
  903. }
  904.  
  905. Depot* Player::getDepot(uint32_t depotId, bool autoCreateDepot)
  906. {
  907.     DepotMap::iterator it = depots.find(depotId);
  908.     if(it != depots.end())
  909.         return it->second.first;
  910.  
  911.     //create a new depot?
  912.     if(autoCreateDepot)
  913.     {
  914.         Item* locker = Item::CreateItem(ITEM_LOCKER);
  915.         if(Container* container = locker->getContainer())
  916.         {
  917.             if(Depot* depot = container->getDepot())
  918.             {
  919.                 container->__internalAddThing(Item::CreateItem(ITEM_DEPOT));
  920.                 addDepot(depot, depotId);
  921.                 return depot;
  922.             }
  923.         }
  924.  
  925.         g_game.freeThing(locker);
  926.         std::clog << "Failure: Creating a new depot with id: " << depotId <<
  927.             ", for player: " << getName() << std::endl;
  928.     }
  929.  
  930.     return NULL;
  931. }
  932.  
  933. bool Player::addDepot(Depot* depot, uint32_t depotId)
  934. {
  935.     if(getDepot(depotId, false))
  936.         return false;
  937.  
  938.     depots[depotId] = std::make_pair(depot, false);
  939.     depot->setMaxDepotLimit((group != NULL ? group->getDepotLimit(isPremium()) : 1000));
  940.     return true;
  941. }
  942.  
  943. void Player::useDepot(uint32_t depotId, bool value)
  944. {
  945.     DepotMap::iterator it = depots.find(depotId);
  946.     if(it != depots.end())
  947.         depots[depotId] = std::make_pair(it->second.first, value);
  948. }
  949.  
  950. void Player::sendCancelMessage(ReturnValue message) const
  951. {
  952.     switch(message)
  953.     {
  954.         case RET_DESTINATIONOUTOFREACH:
  955.             sendCancel("Destination is out of reach.");
  956.             break;
  957.  
  958.         case RET_NOTMOVABLE:
  959.             sendCancel("You cannot move this object.");
  960.             break;
  961.  
  962.         case RET_DROPTWOHANDEDITEM:
  963.             sendCancel("Drop the double-handed object first.");
  964.             break;
  965.  
  966.         case RET_BOTHHANDSNEEDTOBEFREE:
  967.             sendCancel("Both hands need to be free.");
  968.             break;
  969.  
  970.         case RET_CANNOTBEDRESSED:
  971.             sendCancel("You cannot dress this object there.");
  972.             break;
  973.  
  974.         case RET_PUTTHISOBJECTINYOURHAND:
  975.             sendCancel("Put this object in your hand.");
  976.             break;
  977.  
  978.         case RET_PUTTHISOBJECTINBOTHHANDS:
  979.             sendCancel("Put this object in both hands.");
  980.             break;
  981.  
  982.         case RET_CANONLYUSEONEWEAPON:
  983.             sendCancel("You may use only one weapon.");
  984.             break;
  985.  
  986.         case RET_TOOFARAWAY:
  987.             sendCancel("Too far away.");
  988.             break;
  989.  
  990.         case RET_FIRSTGODOWNSTAIRS:
  991.             sendCancel("First go downstairs.");
  992.             break;
  993.  
  994.         case RET_FIRSTGOUPSTAIRS:
  995.             sendCancel("First go upstairs.");
  996.             break;
  997.  
  998.         case RET_NOTENOUGHCAPACITY:
  999.             sendCancel("This object is too heavy for you to carry.");
  1000.             break;
  1001.  
  1002.         case RET_CONTAINERNOTENOUGHROOM:
  1003.             sendCancel("You cannot put more objects in this container.");
  1004.             break;
  1005.  
  1006.         case RET_NEEDEXCHANGE:
  1007.         case RET_NOTENOUGHROOM:
  1008.             sendCancel("There is not enough room.");
  1009.             break;
  1010.  
  1011.         case RET_CANNOTPICKUP:
  1012.             sendCancel("You cannot take this object.");
  1013.             break;
  1014.  
  1015.         case RET_CANNOTTHROW:
  1016.             sendCancel("You cannot throw there.");
  1017.             break;
  1018.  
  1019.         case RET_THEREISNOWAY:
  1020.             sendCancel("There is no way.");
  1021.             break;
  1022.  
  1023.         case RET_THISISIMPOSSIBLE:
  1024.             sendCancel("This is impossible.");
  1025.             break;
  1026.  
  1027.         case RET_PLAYERISPZLOCKED:
  1028.             sendCancel("You cannot enter a protection zone after attacking another player.");
  1029.             break;
  1030.  
  1031.         case RET_PLAYERISNOTINVITED:
  1032.             sendCancel("You are not invited.");
  1033.             break;
  1034.  
  1035.         case RET_CREATUREDOESNOTEXIST:
  1036.             sendCancel("Creature does not exist.");
  1037.             break;
  1038.  
  1039.         case RET_DEPOTISFULL:
  1040.             sendCancel("You cannot put more items in this depot.");
  1041.             break;
  1042.  
  1043.         case RET_CANNOTUSETHISOBJECT:
  1044.             sendCancel("You cannot use this object.");
  1045.             break;
  1046.  
  1047.         case RET_PLAYERWITHTHISNAMEISNOTONLINE:
  1048.             sendCancel("A player with this name is not online.");
  1049.             break;
  1050.  
  1051.         case RET_NOTREQUIREDLEVELTOUSERUNE:
  1052.             sendCancel("You do not have the required magic level to use this rune.");
  1053.             break;
  1054.  
  1055.         case RET_YOUAREALREADYTRADING:
  1056.             sendCancel("You are already trading.");
  1057.             break;
  1058.  
  1059.         case RET_THISPLAYERISALREADYTRADING:
  1060.             sendCancel("This player is already trading.");
  1061.             break;
  1062.  
  1063.         case RET_YOUMAYNOTLOGOUTDURINGAFIGHT:
  1064.             sendCancel("You may not logout during or immediately after a fight!");
  1065.             break;
  1066.  
  1067.         case RET_DIRECTPLAYERSHOOT:
  1068.             sendCancel("You are not allowed to shoot directly on players.");
  1069.             break;
  1070.  
  1071.         case RET_NOTENOUGHLEVEL:
  1072.             sendCancel("You do not have enough level.");
  1073.             break;
  1074.  
  1075.         case RET_NOTENOUGHMAGICLEVEL:
  1076.             sendCancel("You do not have enough magic level.");
  1077.             break;
  1078.  
  1079.         case RET_NOTENOUGHMANA:
  1080.             sendCancel("You do not have enough mana.");
  1081.             break;
  1082.  
  1083.         case RET_NOTENOUGHSOUL:
  1084.             sendCancel("You do not have enough soul.");
  1085.             break;
  1086.  
  1087.         case RET_YOUAREEXHAUSTED:
  1088.             sendCancel("You are exhausted.");
  1089.             break;
  1090.  
  1091.         case RET_CANONLYUSETHISRUNEONCREATURES:
  1092.             sendCancel("You can only use this rune on creatures.");
  1093.             break;
  1094.  
  1095.         case RET_PLAYERISNOTREACHABLE:
  1096.             sendCancel("Player is not reachable.");
  1097.             break;
  1098.  
  1099.         case RET_CREATUREISNOTREACHABLE:
  1100.             sendCancel("Creature is not reachable.");
  1101.             break;
  1102.  
  1103.         case RET_ACTIONNOTPERMITTEDINPROTECTIONZONE:
  1104.             sendCancel("This action is not permitted in a protection zone.");
  1105.             break;
  1106.  
  1107.         case RET_YOUMAYNOTATTACKTHISPLAYER:
  1108.             sendCancel("You may not attack this player.");
  1109.             break;
  1110.  
  1111.         case RET_YOUMAYNOTATTACKTHISCREATURE:
  1112.             sendCancel("You may not attack this creature.");
  1113.             break;
  1114.  
  1115.         case RET_YOUMAYNOTATTACKAPERSONINPROTECTIONZONE:
  1116.             sendCancel("You may not attack a person in a protection zone.");
  1117.             break;
  1118.  
  1119.         case RET_YOUMAYNOTATTACKAPERSONWHILEINPROTECTIONZONE:
  1120.             sendCancel("You may not attack a person while you are in a protection zone.");
  1121.             break;
  1122.  
  1123.         case RET_YOUCANONLYUSEITONCREATURES:
  1124.             sendCancel("You can only use it on creatures.");
  1125.             break;
  1126.  
  1127.         case RET_TURNSECUREMODETOATTACKUNMARKEDPLAYERS:
  1128.             sendCancel("Turn secure mode off if you really want to attack unmarked players.");
  1129.             break;
  1130.  
  1131.         case RET_YOUNEEDPREMIUMACCOUNT:
  1132.             sendCancel("You need a premium account.");
  1133.             break;
  1134.  
  1135.         case RET_YOUNEEDTOLEARNTHISSPELL:
  1136.             sendCancel("You need to learn this spell first.");
  1137.             break;
  1138.  
  1139.         case RET_YOURVOCATIONCANNOTUSETHISSPELL:
  1140.             sendCancel("Your vocation cannot use this spell.");
  1141.             break;
  1142.  
  1143.         case RET_YOUNEEDAWEAPONTOUSETHISSPELL:
  1144.             sendCancel("You need to equip a weapon to use this spell.");
  1145.             break;
  1146.  
  1147.         case RET_PLAYERISPZLOCKEDLEAVEPVPZONE:
  1148.             sendCancel("You cannot leave a pvp zone after attacking another player.");
  1149.             break;
  1150.  
  1151.         case RET_PLAYERISPZLOCKEDENTERPVPZONE:
  1152.             sendCancel("You cannot enter a pvp zone after attacking another player.");
  1153.             break;
  1154.  
  1155.         case RET_ACTIONNOTPERMITTEDINANOPVPZONE:
  1156.             sendCancel("This action is not permitted in a safe zone.");
  1157.             break;
  1158.  
  1159.         case RET_YOUCANNOTLOGOUTHERE:
  1160.             sendCancel("You cannot logout here.");
  1161.             break;
  1162.  
  1163.         case RET_YOUNEEDAMAGICITEMTOCASTSPELL:
  1164.             sendCancel("You need a magic item to cast this spell.");
  1165.             break;
  1166.  
  1167.         case RET_CANNOTCONJUREITEMHERE:
  1168.             sendCancel("You cannot conjure items here.");
  1169.             break;
  1170.  
  1171.         case RET_NAMEISTOOAMBIGUOUS:
  1172.             sendCancel("Name is too ambiguous.");
  1173.             break;
  1174.  
  1175.         case RET_CANONLYUSEONESHIELD:
  1176.             sendCancel("You may use only one shield.");
  1177.             break;
  1178.  
  1179.         case RET_YOUARENOTTHEOWNER:
  1180.             sendCancel("You are not the owner.");
  1181.             break;
  1182.  
  1183.         case RET_YOUMAYNOTCASTAREAONBLACKSKULL:
  1184.             sendCancel("You may not cast area spells while you have a black skull.");
  1185.             break;
  1186.  
  1187.         case RET_TILEISFULL:
  1188.             sendCancel("You cannot add more items on this tile.");
  1189.             break;
  1190.  
  1191.         case RET_DONTSHOWMESSAGE:
  1192.             break;
  1193.  
  1194.         case RET_NOTPOSSIBLE:
  1195.         default:
  1196.             sendCancel("Sorry, not possible.");
  1197.             break;
  1198.     }
  1199. }
  1200.  
  1201. Item* Player::getWriteItem(uint32_t& _windowTextId, uint16_t& _maxWriteLen)
  1202. {
  1203.     _windowTextId = windowTextId;
  1204.     _maxWriteLen = maxWriteLen;
  1205.     return writeItem;
  1206. }
  1207.  
  1208. void Player::setWriteItem(Item* item, uint16_t _maxWriteLen/* = 0*/)
  1209. {
  1210.     windowTextId++;
  1211.     if(writeItem)
  1212.         writeItem->unRef();
  1213.  
  1214.     if(item)
  1215.     {
  1216.         writeItem = item;
  1217.         maxWriteLen = _maxWriteLen;
  1218.         writeItem->addRef();
  1219.     }
  1220.     else
  1221.     {
  1222.         writeItem = NULL;
  1223.         maxWriteLen = 0;
  1224.     }
  1225. }
  1226.  
  1227. House* Player::getEditHouse(uint32_t& _windowTextId, uint32_t& _listId)
  1228. {
  1229.     _windowTextId = windowTextId;
  1230.     _listId = editListId;
  1231.     return editHouse;
  1232. }
  1233.  
  1234. void Player::setEditHouse(House* house, uint32_t listId/* = 0*/)
  1235. {
  1236.     windowTextId++;
  1237.     editHouse = house;
  1238.     editListId = listId;
  1239. }
  1240.  
  1241. void Player::sendHouseWindow(House* house, uint32_t listId) const
  1242. {
  1243.     if(!client)
  1244.         return;
  1245.  
  1246.     std::string text;
  1247.     if(house->getAccessList(listId, text))
  1248.         client->sendHouseWindow(windowTextId, house, listId, text);
  1249. }
  1250.  
  1251. void Player::sendCreatureChangeVisible(const Creature* creature, Visible_t visible)
  1252. {
  1253.     if(!client)
  1254.         return;
  1255.  
  1256.     const Player* player = creature->getPlayer();
  1257.     if(player == this || (player && (visible < VISIBLE_GHOST_APPEAR || getGhostAccess() >= player->getGhostAccess()))
  1258.         || (!player && canSeeInvisibility()))
  1259.         sendCreatureChangeOutfit(creature, creature->getCurrentOutfit());
  1260.     else if(visible == VISIBLE_DISAPPEAR || visible == VISIBLE_GHOST_DISAPPEAR)
  1261.         sendCreatureDisappear(creature, creature->getTile()->getClientIndexOfThing(this, creature));
  1262.     else
  1263.         sendCreatureAppear(creature);
  1264. }
  1265.  
  1266. void Player::sendAddContainerItem(const Container* container, const Item* item)
  1267. {
  1268.     if(!client)
  1269.         return;
  1270.  
  1271.     for(ContainerVector::const_iterator cl = containerVec.begin(); cl != containerVec.end(); ++cl)
  1272.     {
  1273.         if(cl->second == container)
  1274.             client->sendAddContainerItem(cl->first, item);
  1275.     }
  1276. }
  1277.  
  1278. void Player::sendUpdateContainerItem(const Container* container, uint8_t slot, const Item*, const Item* newItem)
  1279. {
  1280.     if(!client)
  1281.         return;
  1282.  
  1283.     for(ContainerVector::const_iterator cl = containerVec.begin(); cl != containerVec.end(); ++cl)
  1284.     {
  1285.         if(cl->second == container)
  1286.             client->sendUpdateContainerItem(cl->first, slot, newItem);
  1287.     }
  1288. }
  1289.  
  1290. void Player::sendRemoveContainerItem(const Container* container, uint8_t slot, const Item*)
  1291. {
  1292.     if(!client)
  1293.         return;
  1294.  
  1295.     for(ContainerVector::const_iterator cl = containerVec.begin(); cl != containerVec.end(); ++cl)
  1296.     {
  1297.         if(cl->second == container)
  1298.             client->sendRemoveContainerItem(cl->first, slot);
  1299.     }
  1300. }
  1301.  
  1302. void Player::onUpdateTileItem(const Tile* tile, const Position& pos, const Item* oldItem,
  1303.     const ItemType& oldType, const Item* newItem, const ItemType& newType)
  1304. {
  1305.     Creature::onUpdateTileItem(tile, pos, oldItem, oldType, newItem, newType);
  1306.     if(oldItem != newItem)
  1307.         onRemoveTileItem(tile, pos, oldType, oldItem);
  1308.  
  1309.     if(tradeState != TRADE_TRANSFER && tradeItem && oldItem == tradeItem)
  1310.         g_game.internalCloseTrade(this);
  1311. }
  1312.  
  1313. void Player::onRemoveTileItem(const Tile* tile, const Position& pos, const ItemType& iType, const Item* item)
  1314. {
  1315.     Creature::onRemoveTileItem(tile, pos, iType, item);
  1316.     if(tradeState == TRADE_TRANSFER)
  1317.         return;
  1318.  
  1319.     checkTradeState(item);
  1320.     if(tradeItem)
  1321.     {
  1322.         const Container* container = item->getContainer();
  1323.         if(container && container->isHoldingItem(tradeItem))
  1324.             g_game.internalCloseTrade(this);
  1325.     }
  1326. }
  1327.  
  1328. void Player::onCreatureAppear(const Creature* creature)
  1329. {
  1330.     Creature::onCreatureAppear(creature);
  1331.     if(creature != this)
  1332.         return;
  1333.  
  1334.     Item* item = NULL;
  1335.     for(int32_t slot = SLOT_FIRST; slot < SLOT_LAST; ++slot)
  1336.     {
  1337.         if(!(item = getInventoryItem((slots_t)slot)))
  1338.             continue;
  1339.  
  1340.         item->__startDecaying();
  1341.         g_moveEvents->onPlayerEquip(this, item, (slots_t)slot, false);
  1342.     }
  1343.  
  1344.     updateWeapon();
  1345.     if(BedItem* bed = Beds::getInstance()->getBedBySleeper(guid))
  1346.         bed->wakeUp();
  1347.  
  1348.     Outfit outfit;
  1349.     if(Outfits::getInstance()->getOutfit(defaultOutfit.lookType, outfit))
  1350.         outfitAttributes = Outfits::getInstance()->addAttributes(getID(), outfit.outfitId, sex, defaultOutfit.lookAddons);
  1351.  
  1352.     if(lastLogout && stamina < STAMINA_MAX)
  1353.     {
  1354.         int64_t ticks = (int64_t)time(NULL) - lastLogout - 600;
  1355.         if(ticks > 0)
  1356.         {
  1357.             ticks = (int64_t)((double)(ticks * 1000) / g_config.getDouble(ConfigManager::RATE_STAMINA_GAIN));
  1358.             int64_t premium = g_config.getNumber(ConfigManager::STAMINA_LIMIT_TOP) * STAMINA_MULTIPLIER, period = ticks;
  1359.             if((int64_t)stamina <= premium)
  1360.             {
  1361.                 period += stamina;
  1362.                 if(period > premium)
  1363.                     period -= premium;
  1364.                 else
  1365.                     period = 0;
  1366.  
  1367.                 useStamina(ticks - period);
  1368.             }
  1369.  
  1370.             if(period > 0)
  1371.             {
  1372.                 ticks = (int64_t)((g_config.getDouble(ConfigManager::RATE_STAMINA_GAIN) * period)
  1373.                     / g_config.getDouble(ConfigManager::RATE_STAMINA_THRESHOLD));
  1374.                 if(stamina + ticks > STAMINA_MAX)
  1375.                     ticks = STAMINA_MAX - stamina;
  1376.  
  1377.                 useStamina(ticks);
  1378.             }
  1379.  
  1380.             sendStats();
  1381.         }
  1382.     }
  1383.  
  1384.     g_game.checkPlayersRecord(this);
  1385.     if(!isGhost())
  1386.         IOLoginData::getInstance()->updateOnlineStatus(guid, true);
  1387.  
  1388.     if(g_config.getBool(ConfigManager::DISPLAY_LOGGING))
  1389.         std::clog << name << " has logged in." << std::endl;
  1390. }
  1391.  
  1392. void Player::onAttackedCreatureDisappear(bool isLogout)
  1393. {
  1394.     sendCancelTarget();
  1395.     if(!isLogout)
  1396.         sendTextMessage(MSG_STATUS_SMALL, "Target lost.");
  1397. }
  1398.  
  1399. void Player::onFollowCreatureDisappear(bool isLogout)
  1400. {
  1401.     sendCancelTarget();
  1402.     if(!isLogout)
  1403.         sendTextMessage(MSG_STATUS_SMALL, "Target lost.");
  1404. }
  1405.  
  1406. void Player::onChangeZone(ZoneType_t zone)
  1407. {
  1408.     if(attackedCreature && zone == ZONE_PROTECTION && !hasFlag(PlayerFlag_IgnoreProtectionZone))
  1409.     {
  1410.         setAttackedCreature(NULL);
  1411.         onAttackedCreatureDisappear(false);
  1412.     }
  1413.     sendIcons();
  1414. }
  1415.  
  1416. void Player::onAttackedCreatureChangeZone(ZoneType_t zone)
  1417. {
  1418.     if(zone == ZONE_PROTECTION && !hasFlag(PlayerFlag_IgnoreProtectionZone))
  1419.     {
  1420.         setAttackedCreature(NULL);
  1421.         onAttackedCreatureDisappear(false);
  1422.     }
  1423.     else if(zone == ZONE_OPTIONAL && attackedCreature->getPlayer() && !hasFlag(PlayerFlag_IgnoreProtectionZone))
  1424.     {
  1425.         setAttackedCreature(NULL);
  1426.         onAttackedCreatureDisappear(false);
  1427.     }
  1428.     else if(zone == ZONE_OPEN && g_game.getWorldType() == WORLDTYPE_OPTIONAL && attackedCreature->getPlayer()
  1429. #ifdef __WAR_SYSTEM__
  1430.         && !attackedCreature->getPlayer()->isEnemy(this, true)
  1431. #endif
  1432.         )
  1433.     {
  1434.         //attackedCreature can leave a pvp zone if not pzlocked
  1435.         setAttackedCreature(NULL);
  1436.         onAttackedCreatureDisappear(false);
  1437.     }
  1438. }
  1439.  
  1440. void Player::onCreatureDisappear(const Creature* creature, bool isLogout)
  1441. {
  1442.     Creature::onCreatureDisappear(creature, isLogout);
  1443.     if(creature != this)
  1444.         return;
  1445.  
  1446.     if(isLogout)
  1447.     {
  1448.         loginPosition = getPosition();
  1449.         lastLogout = time(NULL);
  1450.     }
  1451.  
  1452.     if(eventWalk)
  1453.         setFollowCreature(NULL);
  1454.  
  1455.     closeShopWindow();
  1456.     if(tradePartner)
  1457.         g_game.internalCloseTrade(this);
  1458.  
  1459.     clearPartyInvitations();
  1460.     if(party)
  1461.         party->leave(this);
  1462.  
  1463.     g_game.cancelRuleViolation(this);
  1464.     if(hasFlag(PlayerFlag_CanAnswerRuleViolations))
  1465.     {
  1466.         PlayerVector closeReportList;
  1467.         for(RuleViolationsMap::const_iterator it = g_game.getRuleViolations().begin(); it != g_game.getRuleViolations().end(); ++it)
  1468.         {
  1469.             if(it->second->gamemaster == this)
  1470.                 closeReportList.push_back(it->second->reporter);
  1471.         }
  1472.  
  1473.         for(PlayerVector::iterator it = closeReportList.begin(); it != closeReportList.end(); ++it)
  1474.             g_game.closeRuleViolation(*it);
  1475.     }
  1476.  
  1477.     g_chat.removeUserFromAllChannels(this);
  1478.     if(!isGhost())
  1479.         IOLoginData::getInstance()->updateOnlineStatus(guid, false);
  1480.  
  1481.     if(g_config.getBool(ConfigManager::DISPLAY_LOGGING))
  1482.         std::clog << getName() << " has logged out." << std::endl;
  1483.  
  1484.     bool saved = false;
  1485.     for(uint32_t tries = 0; !saved && tries < 3; ++tries)
  1486.     {
  1487.         if(IOLoginData::getInstance()->savePlayer(this))
  1488.             saved = true;
  1489. #ifdef __DEBUG__
  1490.         else
  1491.             std::clog << "Error while saving player: " << getName() << ", strike " << tries << "." << std::endl;
  1492. #endif
  1493.     }
  1494.  
  1495.     if(!saved)
  1496. #ifndef __DEBUG__
  1497.         std::clog << "Error while saving player: " << getName() << "." << std::endl;
  1498. #else
  1499.         std::clog << "Player " << getName() << " couldn't be saved." << std::endl;
  1500. #endif
  1501. }
  1502.  
  1503. void Player::openShopWindow()
  1504. {
  1505.     sendShop();
  1506.     sendGoods();
  1507. }
  1508.  
  1509. void Player::closeShopWindow(bool send/* = true*/, Npc* npc/* = NULL*/, int32_t onBuy/* = -1*/, int32_t onSell/* = -1*/)
  1510. {
  1511.     if(npc || (npc = getShopOwner(onBuy, onSell)))
  1512.         npc->onPlayerEndTrade(this, onBuy, onSell);
  1513.  
  1514.     if(shopOwner)
  1515.     {
  1516.         shopOwner = NULL;
  1517.         if(send)
  1518.             sendCloseShop();
  1519.     }
  1520.  
  1521.     purchaseCallback = saleCallback = -1;
  1522.     shopOffer.clear();
  1523. }
  1524.  
  1525. bool Player::canShopItem(uint16_t itemId, uint8_t subType, ShopEvent_t event)
  1526. {
  1527.     for(ShopInfoList::iterator sit = shopOffer.begin(); sit != shopOffer.end(); ++sit)
  1528.     {
  1529.         if(sit->itemId != itemId || ((event != SHOPEVENT_BUY || sit->buyPrice < 0)
  1530.             && (event != SHOPEVENT_SELL || sit->sellPrice < 0)))
  1531.             continue;
  1532.  
  1533.         if(event == SHOPEVENT_SELL)
  1534.             return true;
  1535.  
  1536.         const ItemType& it = Item::items[id];
  1537.         if(it.isFluidContainer() || it.isSplash())
  1538.             return sit->subType == subType;
  1539.  
  1540.         return true;
  1541.     }
  1542.  
  1543.     return false;
  1544. }
  1545.  
  1546. void Player::onWalk(Direction& dir)
  1547. {
  1548.     Creature::onWalk(dir);
  1549.     setNextActionTask(NULL);
  1550.     setNextAction(OTSYS_TIME() + getStepDuration(dir));
  1551. }
  1552.  
  1553. void Player::onCreatureMove(const Creature* creature, const Tile* newTile, const Position& newPos,
  1554.     const Tile* oldTile, const Position& oldPos, bool teleport)
  1555. {
  1556.     Creature::onCreatureMove(creature, newTile, newPos, oldTile, oldPos, teleport);
  1557.     if(creature != this)
  1558.         return;
  1559.  
  1560.     if(getParty())
  1561.         getParty()->updateSharedExperience();
  1562.  
  1563.     //check if we should close trade
  1564.     if(tradeState != TRADE_TRANSFER && ((tradeItem && !Position::areInRange<1,1,0>(tradeItem->getPosition(), getPosition()))
  1565.         || (tradePartner && !Position::areInRange<2,2,0>(tradePartner->getPosition(), getPosition()))))
  1566.         g_game.internalCloseTrade(this);
  1567.  
  1568.     if((teleport || oldPos.z != newPos.z) && !hasCustomFlag(PlayerCustomFlag_CanStairhop))
  1569.     {
  1570.         int32_t ticks = g_config.getNumber(ConfigManager::STAIRHOP_DELAY);
  1571.         if(ticks > 0)
  1572.         {
  1573.             addExhaust(ticks, EXHAUST_COMBAT);
  1574.             if(Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_PACIFIED, ticks))
  1575.                 addCondition(condition);
  1576.         }
  1577.     }
  1578. }
  1579.  
  1580. void Player::onAddContainerItem(const Container*, const Item* item)
  1581. {
  1582.     checkTradeState(item);
  1583. }
  1584.  
  1585. void Player::onUpdateContainerItem(const Container* container, uint8_t slot,
  1586.     const Item* oldItem, const ItemType&, const Item* newItem, const ItemType&)
  1587. {
  1588.     if(oldItem != newItem)
  1589.         onRemoveContainerItem(container, slot, oldItem);
  1590.  
  1591.     if(tradeState != TRADE_TRANSFER)
  1592.         checkTradeState(oldItem);
  1593. }
  1594.  
  1595. void Player::onRemoveContainerItem(const Container* container, uint8_t, const Item* item)
  1596. {
  1597.     if(tradeState == TRADE_TRANSFER)
  1598.         return;
  1599.  
  1600.     checkTradeState(item);
  1601.     if(tradeItem)
  1602.     {
  1603.         if(tradeItem->getParent() != container && container->isHoldingItem(tradeItem))
  1604.             g_game.internalCloseTrade(this);
  1605.     }
  1606. }
  1607.  
  1608. void Player::onCloseContainer(const Container* container)
  1609. {
  1610.     if(!client)
  1611.         return;
  1612.  
  1613.     for(ContainerVector::const_iterator cl = containerVec.begin(); cl != containerVec.end(); ++cl)
  1614.     {
  1615.         if(cl->second == container)
  1616.             client->sendCloseContainer(cl->first);
  1617.     }
  1618. }
  1619.  
  1620. void Player::onSendContainer(const Container* container)
  1621. {
  1622.     if(!client)
  1623.         return;
  1624.  
  1625.     bool hasParent = dynamic_cast<const Container*>(container->getParent()) != NULL;
  1626.     for(ContainerVector::const_iterator cl = containerVec.begin(); cl != containerVec.end(); ++cl)
  1627.     {
  1628.         if(cl->second == container)
  1629.             client->sendContainer(cl->first, container, hasParent);
  1630.     }
  1631. }
  1632.  
  1633. void Player::onUpdateInventoryItem(slots_t slot, Item* oldItem, const ItemType& ,
  1634.     Item* newItem, const ItemType&)
  1635. {
  1636.     if(oldItem != newItem)
  1637.         onRemoveInventoryItem(slot, oldItem);
  1638.  
  1639.     if(tradeState != TRADE_TRANSFER)
  1640.         checkTradeState(oldItem);
  1641. }
  1642.  
  1643. void Player::onRemoveInventoryItem(slots_t, Item* item)
  1644. {
  1645.     if(tradeState == TRADE_TRANSFER)
  1646.         return;
  1647.  
  1648.     checkTradeState(item);
  1649.     if(tradeItem)
  1650.     {
  1651.         const Container* container = item->getContainer();
  1652.         if(container && container->isHoldingItem(tradeItem))
  1653.             g_game.internalCloseTrade(this);
  1654.     }
  1655. }
  1656.  
  1657. void Player::checkTradeState(const Item* item)
  1658. {
  1659.     if(!tradeItem || tradeState == TRADE_TRANSFER)
  1660.         return;
  1661.  
  1662.     if(tradeItem != item)
  1663.     {
  1664.         const Container* container = dynamic_cast<const Container*>(item->getParent());
  1665.         while(container != NULL)
  1666.         {
  1667.             if(container == tradeItem)
  1668.             {
  1669.                 g_game.internalCloseTrade(this);
  1670.                 break;
  1671.             }
  1672.  
  1673.             container = dynamic_cast<const Container*>(container->getParent());
  1674.         }
  1675.     }
  1676.     else
  1677.         g_game.internalCloseTrade(this);
  1678. }
  1679.  
  1680. void Player::setNextWalkActionTask(SchedulerTask* task)
  1681. {
  1682.     if(walkTaskEvent)
  1683.     {
  1684.         Scheduler::getInstance().stopEvent(walkTaskEvent);
  1685.         walkTaskEvent = 0;
  1686.     }
  1687.  
  1688.     delete walkTask;
  1689.     walkTask = task;
  1690.     setIdleTime(0);
  1691. }
  1692.  
  1693. void Player::setNextWalkTask(SchedulerTask* task)
  1694. {
  1695.     if(nextStepEvent)
  1696.     {
  1697.         Scheduler::getInstance().stopEvent(nextStepEvent);
  1698.         nextStepEvent = 0;
  1699.     }
  1700.  
  1701.     if(task)
  1702.     {
  1703.         nextStepEvent = Scheduler::getInstance().addEvent(task);
  1704.         setIdleTime(0);
  1705.     }
  1706. }
  1707.  
  1708. void Player::setNextActionTask(SchedulerTask* task)
  1709. {
  1710.     if(actionTaskEvent)
  1711.     {
  1712.         Scheduler::getInstance().stopEvent(actionTaskEvent);
  1713.         actionTaskEvent = 0;
  1714.     }
  1715.  
  1716.     if(task)
  1717.     {
  1718.         actionTaskEvent = Scheduler::getInstance().addEvent(task);
  1719.         setIdleTime(0);
  1720.     }
  1721. }
  1722.  
  1723. uint32_t Player::getNextActionTime() const
  1724. {
  1725.     return (uint32_t)std::max((int64_t)SCHEDULER_MINTICKS, ((int64_t)nextAction - OTSYS_TIME()));
  1726. }
  1727.  
  1728. void Player::onThink(uint32_t interval)
  1729. {
  1730.     Creature::onThink(interval);
  1731.     int64_t timeNow = OTSYS_TIME();
  1732.     if(timeNow - lastPing >= 5000)
  1733.     {
  1734.         lastPing = timeNow;
  1735.         if(client)
  1736.             client->sendPing();
  1737.         else if(g_config.getBool(ConfigManager::STOP_ATTACK_AT_EXIT))
  1738.             setAttackedCreature(NULL);
  1739.     }
  1740.  
  1741.     if((timeNow - lastPong) >= 60000 && !getTile()->hasFlag(TILESTATE_NOLOGOUT)
  1742.         && !isConnecting && !pzLocked && !hasCondition(CONDITION_INFIGHT))
  1743.     {
  1744.         if(client)
  1745.             client->logout(true, true);
  1746.         else if(g_creatureEvents->playerLogout(this, false))
  1747.             g_game.removeCreature(this, true);
  1748.     }
  1749.  
  1750.     messageTicks += interval;
  1751.     if(messageTicks >= 1500)
  1752.     {
  1753.         messageTicks = 0;
  1754.         addMessageBuffer();
  1755.     }
  1756. }
  1757.  
  1758. bool Player::isMuted(uint16_t channelId, SpeakClasses type, uint32_t& time)
  1759. {
  1760.     time = 0;
  1761.     if(hasFlag(PlayerFlag_CannotBeMuted))
  1762.         return false;
  1763.  
  1764.     int32_t muteTicks = 0;
  1765.     for(ConditionList::iterator it = conditions.begin(); it != conditions.end(); ++it)
  1766.     {
  1767.         if((*it)->getType() == CONDITION_MUTED && (*it)->getSubId() == 0 && (*it)->getTicks() > muteTicks)
  1768.             muteTicks = (*it)->getTicks();
  1769.     }
  1770.  
  1771.     time = (uint32_t)muteTicks / 1000;
  1772.     return type != SPEAK_PRIVATE_PN && (type != SPEAK_CHANNEL_Y || (channelId != CHANNEL_GUILD && !g_chat.isPrivateChannel(channelId)));
  1773. }
  1774.  
  1775. void Player::addMessageBuffer()
  1776. {
  1777.     if(!hasFlag(PlayerFlag_CannotBeMuted) && g_config.getNumber(ConfigManager::MAX_MESSAGEBUFFER) && messageBuffer)
  1778.         messageBuffer--;
  1779. }
  1780.  
  1781. void Player::removeMessageBuffer()
  1782. {
  1783.     if(hasFlag(PlayerFlag_CannotBeMuted))
  1784.         return;
  1785.  
  1786.     int32_t maxBuffer = g_config.getNumber(ConfigManager::MAX_MESSAGEBUFFER);
  1787.     if(!maxBuffer || messageBuffer > maxBuffer + 1 || ++messageBuffer <= maxBuffer)
  1788.         return;
  1789.  
  1790.     uint32_t muteCount = 1;
  1791.     MuteCountMap::iterator it = muteCountMap.find(guid);
  1792.     if(it != muteCountMap.end())
  1793.         muteCount = it->second;
  1794.  
  1795.     uint32_t muteTime = 5 * muteCount * muteCount;
  1796.     muteCountMap[guid] = muteCount + 1;
  1797.     if(Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_MUTED, muteTime * 1000))
  1798.         addCondition(condition);
  1799.  
  1800.     char buffer[50];
  1801.     sprintf(buffer, "You are muted for %d seconds.", muteTime);
  1802.     sendTextMessage(MSG_STATUS_SMALL, buffer);
  1803. }
  1804.  
  1805. void Player::drainHealth(Creature* attacker, CombatType_t combatType, int32_t damage)
  1806. {
  1807.     Creature::drainHealth(attacker, combatType, damage);
  1808.     char buffer[150];
  1809.     if(attacker)
  1810.         sprintf(buffer, "You lose %d hitpoint%s due to an attack by %s.", damage, (damage != 1 ? "s" : ""), attacker->getNameDescription().c_str());
  1811.     else
  1812.         sprintf(buffer, "You lose %d hitpoint%s.", damage, (damage != 1 ? "s" : ""));
  1813.  
  1814.     sendStats();
  1815.     sendTextMessage(MSG_EVENT_DEFAULT, buffer);
  1816. }
  1817.  
  1818. void Player::drainMana(Creature* attacker, CombatType_t combatType, int32_t damage)
  1819. {
  1820.     Creature::drainMana(attacker, combatType, damage);
  1821.     char buffer[150];
  1822.     if(attacker)
  1823.         sprintf(buffer, "You lose %d mana blocking an attack by %s.", damage, attacker->getNameDescription().c_str());
  1824.     else
  1825.         sprintf(buffer, "You lose %d mana.", damage);
  1826.  
  1827.     sendStats();
  1828.     sendTextMessage(MSG_EVENT_DEFAULT, buffer);
  1829. }
  1830.  
  1831. void Player::addManaSpent(uint64_t amount, bool useMultiplier/* = true*/)
  1832. {
  1833.     if(!amount)
  1834.         return;
  1835.  
  1836.     uint64_t currReqMana = vocation->getReqMana(magLevel), nextReqMana = vocation->getReqMana(magLevel + 1);
  1837.     if(currReqMana > nextReqMana) //player has reached max magic level
  1838.         return;
  1839.  
  1840.     if(useMultiplier)
  1841.         amount = uint64_t((double)amount * rates[SKILL__MAGLEVEL] * g_config.getDouble(ConfigManager::RATE_MAGIC));
  1842.  
  1843.     bool advance = false;
  1844.     while(manaSpent + amount >= nextReqMana)
  1845.     {
  1846.         amount -= nextReqMana - manaSpent;
  1847.         manaSpent = 0;
  1848.         magLevel++;
  1849.  
  1850.         char advMsg[50];
  1851.         sprintf(advMsg, "You advanced to magic level %d.", magLevel);
  1852.         sendTextMessage(MSG_EVENT_ADVANCE, advMsg);
  1853.  
  1854.         advance = true;
  1855.         CreatureEventList advanceEvents = getCreatureEvents(CREATURE_EVENT_ADVANCE);
  1856.         for(CreatureEventList::iterator it = advanceEvents.begin(); it != advanceEvents.end(); ++it)
  1857.             (*it)->executeAdvance(this, SKILL__MAGLEVEL, (magLevel - 1), magLevel);
  1858.  
  1859.         currReqMana = nextReqMana;
  1860.         nextReqMana = vocation->getReqMana(magLevel + 1);
  1861.         if(currReqMana > nextReqMana)
  1862.         {
  1863.             amount = 0;
  1864.             break;
  1865.         }
  1866.     }
  1867.  
  1868.     if(amount)
  1869.         manaSpent += amount;
  1870.  
  1871.     uint16_t newPercent = Player::getPercentLevel(manaSpent, nextReqMana);
  1872.     if(magLevelPercent != newPercent)
  1873.     {
  1874.         magLevelPercent = newPercent;
  1875.         sendStats();
  1876.     }
  1877.     else if(advance)
  1878.         sendStats();
  1879. }
  1880.  
  1881. void Player::addExperience(uint64_t exp)
  1882. {
  1883.     uint32_t prevLevel = level;
  1884.     uint64_t nextLevelExp = Player::getExpForLevel(level + 1);
  1885.     if(Player::getExpForLevel(level) > nextLevelExp)
  1886.     {
  1887.         //player has reached max level
  1888.         levelPercent = 0;
  1889.         sendStats();
  1890.         return;
  1891.     }
  1892.  
  1893.     experience += exp;
  1894.     while(experience >= nextLevelExp)
  1895.     {
  1896.         healthMax += vocation->getGain(GAIN_HEALTH);
  1897.         health += vocation->getGain(GAIN_HEALTH);
  1898.         manaMax += vocation->getGain(GAIN_MANA);
  1899.         mana += vocation->getGain(GAIN_MANA);
  1900.         capacity += vocation->getGainCap();
  1901.  
  1902.         ++level;
  1903.         nextLevelExp = Player::getExpForLevel(level + 1);
  1904.         if(Player::getExpForLevel(level) > nextLevelExp) //player has reached max level
  1905.             break;
  1906.     }
  1907.  
  1908.     if(prevLevel != level)
  1909.     {
  1910.         updateBaseSpeed();
  1911.         g_game.changeSpeed(this, 0);
  1912.  
  1913.         g_game.addCreatureHealth(this);
  1914.         if(party)
  1915.             party->updateSharedExperience();
  1916.  
  1917.         char advMsg[60];
  1918.         sprintf(advMsg, "You advanced from Level %d to Level %d.", prevLevel, level);
  1919.         sendTextMessage(MSG_EVENT_ADVANCE, advMsg);
  1920.  
  1921.         CreatureEventList advanceEvents = getCreatureEvents(CREATURE_EVENT_ADVANCE);
  1922.         for(CreatureEventList::iterator it = advanceEvents.begin(); it != advanceEvents.end(); ++it)
  1923.             (*it)->executeAdvance(this, SKILL__LEVEL, prevLevel, level);
  1924.     }
  1925.  
  1926.     uint64_t currLevelExp = Player::getExpForLevel(level);
  1927.     nextLevelExp = Player::getExpForLevel(level + 1);
  1928.     levelPercent = 0;
  1929.     if(nextLevelExp > currLevelExp)
  1930.         levelPercent = Player::getPercentLevel(experience - currLevelExp, nextLevelExp - currLevelExp);
  1931.  
  1932.     sendStats();
  1933. }
  1934.  
  1935. void Player::removeExperience(uint64_t exp, bool updateStats/* = true*/)
  1936. {
  1937.     uint32_t prevLevel = level;
  1938.     experience -= std::min(exp, experience);
  1939.     while(level > 1 && experience < Player::getExpForLevel(level))
  1940.     {
  1941.         level--;
  1942.         healthMax = std::max((int32_t)0, (healthMax - (int32_t)vocation->getGain(GAIN_HEALTH)));
  1943.         manaMax = std::max((int32_t)0, (manaMax - (int32_t)vocation->getGain(GAIN_MANA)));
  1944.         capacity = std::max((double)0, (capacity - (double)vocation->getGainCap()));
  1945.     }
  1946.  
  1947.     if(prevLevel != level)
  1948.     {
  1949.         if(updateStats)
  1950.         {
  1951.             updateBaseSpeed();
  1952.             g_game.changeSpeed(this, 0);
  1953.             g_game.addCreatureHealth(this);
  1954.         }
  1955.  
  1956.         char advMsg[90];
  1957.         sprintf(advMsg, "You were downgraded from Level %d to Level %d.", prevLevel, level);
  1958.         sendTextMessage(MSG_EVENT_ADVANCE, advMsg);
  1959.     }
  1960.  
  1961.     uint64_t currLevelExp = Player::getExpForLevel(level),
  1962.         nextLevelExp = Player::getExpForLevel(level + 1);
  1963.     if(nextLevelExp > currLevelExp)
  1964.         levelPercent = Player::getPercentLevel(experience - currLevelExp, nextLevelExp - currLevelExp);
  1965.     else
  1966.         levelPercent = 0;
  1967.  
  1968.     if(updateStats)
  1969.         sendStats();
  1970. }
  1971.  
  1972. uint16_t Player::getPercentLevel(uint64_t count, uint64_t nextLevelCount)
  1973. {
  1974.     if(nextLevelCount > 0)
  1975.         return std::min((uint32_t)100, std::max((uint32_t)0, uint32_t(count * 100 / nextLevelCount)));
  1976.  
  1977.     return 0;
  1978. }
  1979.  
  1980. void Player::onBlockHit(BlockType_t)
  1981. {
  1982.     if(shieldBlockCount > 0)
  1983.     {
  1984.         --shieldBlockCount;
  1985.         if(hasShield())
  1986.             addSkillAdvance(SKILL_SHIELD, 1);
  1987.     }
  1988. }
  1989.  
  1990. void Player::onAttackedCreatureBlockHit(Creature* target, BlockType_t blockType)
  1991. {
  1992.     Creature::onAttackedCreatureBlockHit(target, blockType);
  1993.     lastAttackBlockType = blockType;
  1994.     switch(blockType)
  1995.     {
  1996.         case BLOCK_NONE:
  1997.         {
  1998.             bloodHitCount = shieldBlockCount = 30;
  1999.             addAttackSkillPoint = true;
  2000.             break;
  2001.         }
  2002.  
  2003.         case BLOCK_DEFENSE:
  2004.         case BLOCK_ARMOR:
  2005.         {
  2006.             //need to draw blood every 30 hits
  2007.             if(bloodHitCount > 0)
  2008.             {
  2009.                 addAttackSkillPoint = true;
  2010.                 --bloodHitCount;
  2011.             }
  2012.             else
  2013.                 addAttackSkillPoint = false;
  2014.  
  2015.             break;
  2016.         }
  2017.  
  2018.         default:
  2019.         {
  2020.             addAttackSkillPoint = false;
  2021.             break;
  2022.         }
  2023.     }
  2024. }
  2025.  
  2026. bool Player::hasShield() const
  2027. {
  2028.     Item* item = getInventoryItem(SLOT_LEFT);
  2029.     return (item && item->getWeaponType() == WEAPON_SHIELD) || ((item = getInventoryItem(SLOT_RIGHT)) && item->getWeaponType() == WEAPON_SHIELD);
  2030. }
  2031.  
  2032. BlockType_t Player::blockHit(Creature* attacker, CombatType_t combatType, int32_t& damage,
  2033.     bool checkDefense/* = false*/, bool checkArmor/* = false*/, bool reflect/* = true*/)
  2034. {
  2035.     BlockType_t blockType = Creature::blockHit(attacker, combatType, damage, checkDefense, checkArmor);
  2036.     if(attacker)
  2037.     {
  2038.         int16_t color = g_config.getNumber(ConfigManager::SQUARE_COLOR);
  2039.         if(color < 0)
  2040.             color = random_range(0, 254);
  2041.  
  2042.         sendCreatureSquare(attacker, color);
  2043.     }
  2044.  
  2045.     if(blockType != BLOCK_NONE)
  2046.         return blockType;
  2047.  
  2048.     if(vocation->getMultiplier(MULTIPLIER_MAGICDEFENSE) != 1.0 && combatType != COMBAT_NONE &&
  2049.         combatType != COMBAT_PHYSICALDAMAGE && combatType != COMBAT_UNDEFINEDDAMAGE &&
  2050.         combatType != COMBAT_DROWNDAMAGE)
  2051.         damage -= (int32_t)std::ceil((double)(damage * vocation->getMultiplier(MULTIPLIER_MAGICDEFENSE)) / 100.);
  2052.  
  2053.     if(damage <= 0)
  2054.         return blockType;
  2055.  
  2056.     int32_t blocked = 0, reflected = 0;
  2057.     if(reflect)
  2058.         reflect = attacker && !attacker->isRemoved() && attacker->getHealth() > 0;
  2059.  
  2060.     Item* item = NULL;
  2061.     for(int32_t slot = SLOT_FIRST; slot < SLOT_LAST; ++slot)
  2062.     {
  2063.         if(!(item = getInventoryItem((slots_t)slot)) || item->isRemoved() ||
  2064.             (g_moveEvents->hasEquipEvent(item) && !isItemAbilityEnabled((slots_t)slot)))
  2065.             continue;
  2066.  
  2067.         const ItemType& it = Item::items[item->getID()];
  2068.         if(it.abilities.absorb[combatType])
  2069.         {
  2070.             blocked += (int32_t)std::ceil((double)(damage * it.abilities.absorb[combatType]) / 100.);
  2071.             if(item->hasCharges())
  2072.                 g_game.transformItem(item, item->getID(), std::max((int32_t)0, (int32_t)item->getCharges() - 1));
  2073.         }
  2074.  
  2075.         if(!reflect)
  2076.             continue;
  2077.  
  2078.         if(it.abilities.reflect[REFLECT_PERCENT][combatType] && random_range(1, 100) < it.abilities.reflect[REFLECT_CHANCE][combatType])
  2079.         {
  2080.             reflected += (int32_t)std::ceil((double)(damage * it.abilities.reflect[REFLECT_PERCENT][combatType]) / 100.);
  2081.             if(item->hasCharges() && !it.abilities.absorb[combatType])
  2082.                 g_game.transformItem(item, item->getID(), std::max((int32_t)0, (int32_t)item->getCharges() - 1));
  2083.         }
  2084.     }
  2085.  
  2086.     if(outfitAttributes)
  2087.     {
  2088.         uint32_t tmp = Outfits::getInstance()->getOutfitAbsorb(defaultOutfit.lookType, sex, combatType);
  2089.         if(tmp)
  2090.             blocked += (int32_t)std::ceil((double)(damage * tmp) / 100.);
  2091.  
  2092.         if(reflect)
  2093.         {
  2094.             tmp = Outfits::getInstance()->getOutfitReflect(defaultOutfit.lookType, sex, combatType);
  2095.             if(tmp)
  2096.                 reflected += (int32_t)std::ceil((double)(damage * tmp) / 100.);
  2097.         }
  2098.     }
  2099.  
  2100.     if(vocation->getAbsorb(combatType))
  2101.         blocked += (int32_t)std::ceil((double)(damage * vocation->getAbsorb(combatType)) / 100.);
  2102.  
  2103.     if(reflect && vocation->getReflect(combatType))
  2104.         reflected += (int32_t)std::ceil((double)(damage * vocation->getReflect(combatType)) / 100.);
  2105.  
  2106.     damage -= blocked;
  2107.     if(damage <= 0)
  2108.     {
  2109.         damage = 0;
  2110.         blockType = BLOCK_DEFENSE;
  2111.     }
  2112.  
  2113.     if(reflected)
  2114.     {
  2115.         if(combatType != COMBAT_HEALING)
  2116.             reflected = -reflected;
  2117.  
  2118.         if(attacker->blockHit(this, combatType, reflected, false, false, false) == BLOCK_NONE)
  2119.             g_game.combatChangeHealth(combatType, NULL, attacker, reflected);
  2120.     }
  2121.  
  2122.     return blockType;
  2123. }
  2124.  
  2125. uint32_t Player::getIP() const
  2126. {
  2127.     if(client)
  2128.         return client->getIP();
  2129.  
  2130.     return lastIP;
  2131. }
  2132.  
  2133. bool Player::onDeath()
  2134. {
  2135.     Item* preventLoss = NULL;
  2136.     Item* preventDrop = NULL;
  2137.     if(getZone() == ZONE_HARDCORE)
  2138.     {
  2139.         setDropLoot(LOOT_DROP_NONE);
  2140.         setLossSkill(false);
  2141.     }
  2142.     else if(skull < SKULL_RED)
  2143.     {
  2144.         Item* item = NULL;
  2145.         for(int32_t i = SLOT_FIRST; ((skillLoss || lootDrop == LOOT_DROP_FULL) && i < SLOT_LAST); ++i)
  2146.         {
  2147.             if(!(item = getInventoryItem((slots_t)i)) || item->isRemoved() ||
  2148.                 (g_moveEvents->hasEquipEvent(item) && !isItemAbilityEnabled((slots_t)i)))
  2149.                 continue;
  2150.  
  2151.             const ItemType& it = Item::items[item->getID()];
  2152.             if(lootDrop == LOOT_DROP_FULL && it.abilities.preventDrop)
  2153.             {
  2154.                 setDropLoot(LOOT_DROP_PREVENT);
  2155.                 preventDrop = item;
  2156.             }
  2157.  
  2158.             if(skillLoss && !preventLoss && it.abilities.preventLoss)
  2159.                 preventLoss = item;
  2160.         }
  2161.     }
  2162.  
  2163.     if(!Creature::onDeath())
  2164.     {
  2165.         if(preventDrop)
  2166.             setDropLoot(LOOT_DROP_FULL);
  2167.  
  2168.         return false;
  2169.     }
  2170.  
  2171.     if(preventLoss)
  2172.     {
  2173.         setLossSkill(false);
  2174.         if(preventLoss->getCharges() > 1) //weird, but transform failed to remove for some hosters
  2175.             g_game.transformItem(preventLoss, preventLoss->getID(), std::max(0, ((int32_t)preventLoss->getCharges() - 1)));
  2176.         else
  2177.             g_game.internalRemoveItem(NULL, preventDrop);
  2178.     }
  2179.  
  2180.     if(preventDrop && preventDrop != preventLoss)
  2181.     {
  2182.         if(preventDrop->getCharges() > 1) //weird, but transform failed to remove for some hosters
  2183.             g_game.transformItem(preventDrop, preventDrop->getID(), std::max(0, ((int32_t)preventDrop->getCharges() - 1)));
  2184.         else
  2185.             g_game.internalRemoveItem(NULL, preventDrop);
  2186.     }
  2187.  
  2188.     removeConditions(CONDITIONEND_DEATH);
  2189.     if(skillLoss)
  2190.     {
  2191.         uint64_t lossExperience = getLostExperience();
  2192.         removeExperience(lossExperience, false);
  2193.         double percent = 1. - ((double)(experience - lossExperience) / experience);
  2194.  
  2195.         //Magic level loss
  2196.         uint64_t sumMana = 0, lostMana = 0;
  2197.         for(uint32_t i = 1; i <= magLevel; ++i)
  2198.             sumMana += vocation->getReqMana(i);
  2199.  
  2200.         sumMana += manaSpent;
  2201.         lostMana = (uint64_t)std::ceil(sumMana * ((double)(percent * lossPercent[LOSS_MANA]) / 100.));
  2202.         while(lostMana > manaSpent && magLevel > 0)
  2203.         {
  2204.             lostMana -= manaSpent;
  2205.             manaSpent = vocation->getReqMana(magLevel);
  2206.             magLevel--;
  2207.         }
  2208.  
  2209.         manaSpent -= std::max((int32_t)0, (int32_t)lostMana);
  2210.         uint64_t nextReqMana = vocation->getReqMana(magLevel + 1);
  2211.         if(nextReqMana > vocation->getReqMana(magLevel))
  2212.             magLevelPercent = Player::getPercentLevel(manaSpent, nextReqMana);
  2213.         else
  2214.             magLevelPercent = 0;
  2215.  
  2216.         //Skill loss
  2217.         uint64_t lostSkillTries, sumSkillTries;
  2218.         for(int16_t i = 0; i < 7; ++i) //for each skill
  2219.         {
  2220.             lostSkillTries = sumSkillTries = 0;
  2221.             for(uint32_t c = 11; c <= skills[i][SKILL_LEVEL]; ++c) //sum up all required tries for all skill levels
  2222.                 sumSkillTries += vocation->getReqSkillTries(i, c);
  2223.  
  2224.             sumSkillTries += skills[i][SKILL_TRIES];
  2225.             lostSkillTries = (uint64_t)std::ceil(sumSkillTries * ((double)(percent * lossPercent[LOSS_SKILLS]) / 100.));
  2226.             while(lostSkillTries > skills[i][SKILL_TRIES])
  2227.             {
  2228.                 lostSkillTries -= skills[i][SKILL_TRIES];
  2229.                 skills[i][SKILL_TRIES] = vocation->getReqSkillTries(i, skills[i][SKILL_LEVEL]);
  2230.                 if(skills[i][SKILL_LEVEL] < 11)
  2231.                 {
  2232.                     skills[i][SKILL_LEVEL] = 10;
  2233.                     skills[i][SKILL_TRIES] = lostSkillTries = 0;
  2234.                     break;
  2235.                 }
  2236.                 else
  2237.                     skills[i][SKILL_LEVEL]--;
  2238.             }
  2239.  
  2240.             skills[i][SKILL_TRIES] = std::max((int32_t)0, (int32_t)(skills[i][SKILL_TRIES] - lostSkillTries));
  2241.         }
  2242.  
  2243.         blessings = 0;
  2244.         loginPosition = masterPosition;
  2245.         if(!inventory[SLOT_BACKPACK])
  2246.             __internalAddThing(SLOT_BACKPACK, Item::CreateItem(g_config.getNumber(ConfigManager::DEATH_CONTAINER)));
  2247.  
  2248.         sendIcons();
  2249.         sendStats();
  2250.         sendSkills();
  2251.  
  2252.         g_creatureEvents->playerLogout(this, true);
  2253.         g_game.removeCreature(this, false);
  2254.         sendReLoginWindow();
  2255.     }
  2256.     else
  2257.     {
  2258.         setLossSkill(true);
  2259.         if(preventLoss)
  2260.         {
  2261.             loginPosition = masterPosition;
  2262.             g_creatureEvents->playerLogout(this, true);
  2263.             g_game.removeCreature(this, false);
  2264.             sendReLoginWindow();
  2265.         }
  2266.     }
  2267.  
  2268.     return true;
  2269. }
  2270.  
  2271. void Player::dropCorpse(DeathList deathList)
  2272. {
  2273.     if(lootDrop == LOOT_DROP_NONE)
  2274.     {
  2275.         pzLocked = false;
  2276.         if(health <= 0)
  2277.         {
  2278.             health = healthMax;
  2279.             mana = manaMax;
  2280.         }
  2281.  
  2282.         setDropLoot(LOOT_DROP_FULL);
  2283.         sendStats();
  2284.         sendIcons();
  2285.  
  2286.         onIdleStatus();
  2287.         g_game.addCreatureHealth(this);
  2288.         g_game.internalTeleport(this, masterPosition, false);
  2289.     }
  2290.     else
  2291.     {
  2292.         Creature::dropCorpse(deathList);
  2293.         if(g_config.getBool(ConfigManager::DEATH_LIST))
  2294.             IOLoginData::getInstance()->playerDeath(this, deathList);
  2295.     }
  2296. }
  2297.  
  2298. Item* Player::createCorpse(DeathList deathList)
  2299. {
  2300.     Item* corpse = Creature::createCorpse(deathList);
  2301.     if(!corpse)
  2302.         return NULL;
  2303.  
  2304.     std::stringstream ss;
  2305.     ss << "You recognize " << getNameDescription() << ". " << (sex % 2 ? "He" : "She") << " was killed by ";
  2306.     if(deathList[0].isCreatureKill())
  2307.     {
  2308.         ss << deathList[0].getKillerCreature()->getNameDescription();
  2309.         if(deathList[0].getKillerCreature()->getMaster())
  2310.             ss << " summoned by " << deathList[0].getKillerCreature()->getMaster()->getNameDescription();
  2311.     }
  2312.     else
  2313.         ss << deathList[0].getKillerName();
  2314.  
  2315.     if(deathList.size() > 1)
  2316.     {
  2317.         if(deathList[0].getKillerType() != deathList[1].getKillerType())
  2318.         {
  2319.             if(deathList[1].isCreatureKill())
  2320.             {
  2321.                 ss << " and by " << deathList[1].getKillerCreature()->getNameDescription();
  2322.                 if(deathList[1].getKillerCreature()->getMaster())
  2323.                     ss << " summoned by " << deathList[1].getKillerCreature()->getMaster()->getNameDescription();
  2324.             }
  2325.             else
  2326.                 ss << " and by " << deathList[1].getKillerName();
  2327.         }
  2328.         else if(deathList[1].isCreatureKill())
  2329.         {
  2330.             if(deathList[0].getKillerCreature()->getName() != deathList[1].getKillerCreature()->getName())
  2331.             {
  2332.                 ss << " and by " << deathList[1].getKillerCreature()->getNameDescription();
  2333.                 if(deathList[1].getKillerCreature()->getMaster())
  2334.                     ss << " summoned by " << deathList[1].getKillerCreature()->getMaster()->getNameDescription();
  2335.             }
  2336.         }
  2337.         else if(asLowerCaseString(deathList[0].getKillerName()) != asLowerCaseString(deathList[1].getKillerName()))
  2338.             ss << " and by " << deathList[1].getKillerName();
  2339.     }
  2340.  
  2341.     ss << ".";
  2342.     corpse->setSpecialDescription(ss.str().c_str());
  2343.     return corpse;
  2344. }
  2345.  
  2346. void Player::addExhaust(uint32_t ticks, Exhaust_t type)
  2347. {
  2348.     if(Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT,
  2349.         CONDITION_EXHAUST, ticks, 0, false, (uint32_t)type))
  2350.         addCondition(condition);
  2351. }
  2352.  
  2353. void Player::addInFightTicks(bool pzLock, int32_t ticks/* = 0*/)
  2354. {
  2355.     if(hasFlag(PlayerFlag_NotGainInFight))
  2356.         return;
  2357.  
  2358.     if(!ticks)
  2359.         ticks = g_config.getNumber(ConfigManager::PZ_LOCKED);
  2360.     else
  2361.         ticks = std::max(-1, ticks);
  2362.  
  2363.     if(pzLock)
  2364.         pzLocked = true;
  2365.  
  2366.     if(Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT,
  2367.         CONDITION_INFIGHT, ticks))
  2368.         addCondition(condition);
  2369. }
  2370.  
  2371. void Player::addDefaultRegeneration(uint32_t addTicks)
  2372. {
  2373.     Condition* condition = getCondition(CONDITION_REGENERATION, CONDITIONID_DEFAULT);
  2374.     if(condition)
  2375.         condition->setTicks(condition->getTicks() + addTicks);
  2376.     else if((condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_REGENERATION, addTicks)))
  2377.     {
  2378.         condition->setParam(CONDITIONPARAM_HEALTHGAIN, vocation->getGainAmount(GAIN_HEALTH));
  2379.         condition->setParam(CONDITIONPARAM_HEALTHTICKS, vocation->getGainTicks(GAIN_HEALTH) * 1000);
  2380.         condition->setParam(CONDITIONPARAM_MANAGAIN, vocation->getGainAmount(GAIN_MANA));
  2381.         condition->setParam(CONDITIONPARAM_MANATICKS, vocation->getGainTicks(GAIN_MANA) * 1000);
  2382.         addCondition(condition);
  2383.     }
  2384. }
  2385.  
  2386. void Player::removeList()
  2387. {
  2388.     Manager::getInstance()->removeUser(id);
  2389.     autoList.erase(id);
  2390.     if(!isGhost())
  2391.     {
  2392.         for(AutoList<Player>::iterator it = autoList.begin(); it != autoList.end(); ++it)
  2393.             it->second->notifyLogOut(this);
  2394.     }
  2395.     else
  2396.     {
  2397.         for(AutoList<Player>::iterator it = autoList.begin(); it != autoList.end(); ++it)
  2398.         {
  2399.             if(it->second->canSeeCreature(this))
  2400.                 it->second->notifyLogOut(this);
  2401.         }
  2402.     }
  2403. }
  2404.  
  2405. void Player::addList()
  2406. {
  2407.     if(!isGhost())
  2408.     {
  2409.         for(AutoList<Player>::iterator it = autoList.begin(); it != autoList.end(); ++it)
  2410.             it->second->notifyLogIn(this);
  2411.     }
  2412.     else
  2413.     {
  2414.         for(AutoList<Player>::iterator it = autoList.begin(); it != autoList.end(); ++it)
  2415.         {
  2416.             if(it->second->canSeeCreature(this))
  2417.                 it->second->notifyLogIn(this);
  2418.         }
  2419.     }
  2420.  
  2421.     autoList[id] = this;
  2422.     Manager::getInstance()->addUser(this);
  2423. }
  2424.  
  2425. void Player::kick(bool displayEffect, bool forceLogout)
  2426. {
  2427.     if(!client)
  2428.     {
  2429.         if(g_creatureEvents->playerLogout(this, forceLogout))
  2430.             g_game.removeCreature(this);
  2431.     }
  2432.     else
  2433.         client->logout(displayEffect, forceLogout);
  2434. }
  2435.  
  2436. void Player::notifyLogIn(Player* loginPlayer)
  2437. {
  2438.     if(!client)
  2439.         return;
  2440.  
  2441.     VIPSet::iterator it = VIPList.find(loginPlayer->getGUID());
  2442.     if(it != VIPList.end())
  2443.         client->sendVIPLogIn(loginPlayer->getGUID());
  2444. }
  2445.  
  2446. void Player::notifyLogOut(Player* logoutPlayer)
  2447. {
  2448.     if(!client)
  2449.         return;
  2450.  
  2451.     VIPSet::iterator it = VIPList.find(logoutPlayer->getGUID());
  2452.     if(it != VIPList.end())
  2453.         client->sendVIPLogOut(logoutPlayer->getGUID());
  2454. }
  2455.  
  2456. bool Player::removeVIP(uint32_t _guid)
  2457. {
  2458.     VIPSet::iterator it = VIPList.find(_guid);
  2459.     if(it == VIPList.end())
  2460.         return false;
  2461.  
  2462.     VIPList.erase(it);
  2463.     return true;
  2464. }
  2465.  
  2466. bool Player::addVIP(uint32_t _guid, std::string& name, bool isOnline, bool internal/* = false*/)
  2467. {
  2468.     if(guid == _guid)
  2469.     {
  2470.         if(!internal)
  2471.             sendTextMessage(MSG_STATUS_SMALL, "You cannot add yourself.");
  2472.  
  2473.         return false;
  2474.     }
  2475.  
  2476.     if(VIPList.size() > (group ? group->getMaxVips(isPremium()) : g_config.getNumber(ConfigManager::VIPLIST_DEFAULT_LIMIT)))
  2477.     {
  2478.         if(!internal)
  2479.             sendTextMessage(MSG_STATUS_SMALL, "You cannot add more buddies.");
  2480.  
  2481.         return false;
  2482.     }
  2483.  
  2484.     VIPSet::iterator it = VIPList.find(_guid);
  2485.     if(it != VIPList.end())
  2486.     {
  2487.         if(!internal)
  2488.             sendTextMessage(MSG_STATUS_SMALL, "This player is already in your list.");
  2489.  
  2490.         return false;
  2491.     }
  2492.  
  2493.     VIPList.insert(_guid);
  2494.     if(client && !internal)
  2495.         client->sendVIP(_guid, name, isOnline);
  2496.  
  2497.     return true;
  2498. }
  2499.  
  2500. //close container and its child containers
  2501. void Player::autoCloseContainers(const Container* container)
  2502. {
  2503.     typedef std::vector<uint32_t> CloseList;
  2504.     CloseList closeList;
  2505.     for(ContainerVector::iterator it = containerVec.begin(); it != containerVec.end(); ++it)
  2506.     {
  2507.         Container* tmp = it->second;
  2508.         while(tmp != NULL)
  2509.         {
  2510.             if(tmp->isRemoved() || tmp == container)
  2511.             {
  2512.                 closeList.push_back(it->first);
  2513.                 break;
  2514.             }
  2515.  
  2516.             tmp = dynamic_cast<Container*>(tmp->getParent());
  2517.         }
  2518.     }
  2519.  
  2520.     for(CloseList::iterator it = closeList.begin(); it != closeList.end(); ++it)
  2521.     {
  2522.         closeContainer(*it);
  2523.         if(client)
  2524.             client->sendCloseContainer(*it);
  2525.     }
  2526. }
  2527.  
  2528. bool Player::hasCapacity(const Item* item, uint32_t count) const
  2529. {
  2530.     if(hasFlag(PlayerFlag_CannotPickupItem))
  2531.         return false;
  2532.  
  2533.     if(hasFlag(PlayerFlag_HasInfiniteCapacity) || item->getTopParent() == this)
  2534.         return true;
  2535.  
  2536.     double itemWeight = 0;
  2537.     if(item->isStackable())
  2538.         itemWeight = Item::items[item->getID()].weight * count;
  2539.     else
  2540.         itemWeight = item->getWeight();
  2541.  
  2542.     return (itemWeight < getFreeCapacity());
  2543. }
  2544.  
  2545. ReturnValue Player::__queryAdd(int32_t index, const Thing* thing, uint32_t count, uint32_t flags) const
  2546. {
  2547.     const Item* item = thing->getItem();
  2548.     if(!item)
  2549.         return RET_NOTPOSSIBLE;
  2550.  
  2551.     bool childOwner = ((flags & FLAG_CHILDISOWNER) == FLAG_CHILDISOWNER), skipLimit = ((flags & FLAG_NOLIMIT) == FLAG_NOLIMIT);
  2552.     if(childOwner)
  2553.     {
  2554.         //a child container is querying the player, just check if enough capacity
  2555.         if(skipLimit || hasCapacity(item, count))
  2556.             return RET_NOERROR;
  2557.  
  2558.         return RET_NOTENOUGHCAPACITY;
  2559.     }
  2560.  
  2561.     if(!item->isPickupable())
  2562.         return RET_CANNOTPICKUP;
  2563.  
  2564.     ReturnValue ret = RET_NOERROR;
  2565.     if((item->getSlotPosition() & SLOTP_HEAD) || (item->getSlotPosition() & SLOTP_NECKLACE) ||
  2566.         (item->getSlotPosition() & SLOTP_BACKPACK) || (item->getSlotPosition() & SLOTP_ARMOR) ||
  2567.         (item->getSlotPosition() & SLOTP_LEGS) || (item->getSlotPosition() & SLOTP_FEET) ||
  2568.         (item->getSlotPosition() & SLOTP_RING))
  2569.         ret = RET_CANNOTBEDRESSED;
  2570.     else if(item->getSlotPosition() & SLOTP_TWO_HAND)
  2571.         ret = RET_PUTTHISOBJECTINBOTHHANDS;
  2572.     else if((item->getSlotPosition() & SLOTP_RIGHT) || (item->getSlotPosition() & SLOTP_LEFT))
  2573.         ret = RET_PUTTHISOBJECTINYOURHAND;
  2574.  
  2575.     switch(index)
  2576.     {
  2577.         case SLOT_HEAD:
  2578.             if(item->getSlotPosition() & SLOTP_HEAD)
  2579.                 ret = RET_NOERROR;
  2580.             break;
  2581.         case SLOT_NECKLACE:
  2582.             if(item->getSlotPosition() & SLOTP_NECKLACE)
  2583.                 ret = RET_NOERROR;
  2584.             break;
  2585.         case SLOT_BACKPACK:
  2586.             if(item->getSlotPosition() & SLOTP_BACKPACK)
  2587.                 ret = RET_NOERROR;
  2588.             break;
  2589.         case SLOT_ARMOR:
  2590.             if(item->getSlotPosition() & SLOTP_ARMOR)
  2591.                 ret = RET_NOERROR;
  2592.             break;
  2593.         case SLOT_RIGHT:
  2594.             if(item->getSlotPosition() & SLOTP_RIGHT)
  2595.             {
  2596.                 //check if we already carry an item in the other hand
  2597.                 if(item->getSlotPosition() & SLOTP_TWO_HAND)
  2598.                 {
  2599.                     if(inventory[SLOT_LEFT] && inventory[SLOT_LEFT] != item)
  2600.                         ret = RET_BOTHHANDSNEEDTOBEFREE;
  2601.                     else
  2602.                         ret = RET_NOERROR;
  2603.                 }
  2604.                 else if(inventory[SLOT_LEFT])
  2605.                 {
  2606.                     const Item* leftItem = inventory[SLOT_LEFT];
  2607.                     WeaponType_t type = item->getWeaponType(), leftType = leftItem->getWeaponType();
  2608.                     if(leftItem->getSlotPosition() & SLOTP_TWO_HAND)
  2609.                         ret = RET_DROPTWOHANDEDITEM;
  2610.                     else if(item == leftItem && item->getItemCount() == count)
  2611.                         ret = RET_NOERROR;
  2612.                     else if(leftType == WEAPON_SHIELD && type == WEAPON_SHIELD)
  2613.                         ret = RET_CANONLYUSEONESHIELD;
  2614.                     else if(!leftItem->isWeapon() || !item->isWeapon() ||
  2615.                         leftType == WEAPON_AMMO || type == WEAPON_AMMO ||
  2616.                         leftType == WEAPON_SHIELD || type == WEAPON_SHIELD ||
  2617.                         (leftItem->isDualWield() && item->isDualWield()))
  2618.                         ret = RET_NOERROR;
  2619.                     else
  2620.                         ret = RET_CANONLYUSEONEWEAPON;
  2621.                 }
  2622.                 else
  2623.                     ret = RET_NOERROR;
  2624.             }
  2625.             break;
  2626.         case SLOT_LEFT:
  2627.             if(item->getSlotPosition() & SLOTP_LEFT)
  2628.             {
  2629.                 //check if we already carry an item in the other hand
  2630.                 if(item->getSlotPosition() & SLOTP_TWO_HAND)
  2631.                 {
  2632.                     if(inventory[SLOT_RIGHT] && inventory[SLOT_RIGHT] != item)
  2633.                         ret = RET_BOTHHANDSNEEDTOBEFREE;
  2634.                     else
  2635.                         ret = RET_NOERROR;
  2636.                 }
  2637.                 else if(inventory[SLOT_RIGHT])
  2638.                 {
  2639.                     const Item* rightItem = inventory[SLOT_RIGHT];
  2640.                     WeaponType_t type = item->getWeaponType(), rightType = rightItem->getWeaponType();
  2641.                     if(rightItem->getSlotPosition() & SLOTP_TWO_HAND)
  2642.                         ret = RET_DROPTWOHANDEDITEM;
  2643.                     else if(item == rightItem && item->getItemCount() == count)
  2644.                         ret = RET_NOERROR;
  2645.                     else if(rightType == WEAPON_SHIELD && type == WEAPON_SHIELD)
  2646.                         ret = RET_CANONLYUSEONESHIELD;
  2647.                     else if(!rightItem->isWeapon() || !item->isWeapon() ||
  2648.                         rightType == WEAPON_AMMO || type == WEAPON_AMMO ||
  2649.                         rightType == WEAPON_SHIELD || type == WEAPON_SHIELD ||
  2650.                         (rightItem->isDualWield() && item->isDualWield()))
  2651.                         ret = RET_NOERROR;
  2652.                     else
  2653.                         ret = RET_CANONLYUSEONEWEAPON;
  2654.                 }
  2655.                 else
  2656.                     ret = RET_NOERROR;
  2657.             }
  2658.             break;
  2659.         case SLOT_LEGS:
  2660.             if(item->getSlotPosition() & SLOTP_LEGS)
  2661.                 ret = RET_NOERROR;
  2662.             break;
  2663.         case SLOT_FEET:
  2664.             if(item->getSlotPosition() & SLOTP_FEET)
  2665.                 ret = RET_NOERROR;
  2666.             break;
  2667.         case SLOT_RING:
  2668.             if(item->getSlotPosition() & SLOTP_RING)
  2669.                 ret = RET_NOERROR;
  2670.             break;
  2671.         case SLOT_AMMO:
  2672.             if(item->getSlotPosition() & SLOTP_AMMO)
  2673.                 ret = RET_NOERROR;
  2674.             break;
  2675.         case SLOT_WHEREEVER:
  2676.         case -1:
  2677.             ret = RET_NOTENOUGHROOM;
  2678.             break;
  2679.         default:
  2680.             ret = RET_NOTPOSSIBLE;
  2681.             break;
  2682.     }
  2683.  
  2684.     if(ret == RET_NOERROR || ret == RET_NOTENOUGHROOM)
  2685.     {
  2686.         //need an exchange with source?
  2687.         if(getInventoryItem((slots_t)index) != NULL && (!getInventoryItem((slots_t)index)->isStackable()
  2688.             || getInventoryItem((slots_t)index)->getID() != item->getID()))
  2689.             return RET_NEEDEXCHANGE;
  2690.  
  2691.         if(!g_moveEvents->onPlayerEquip(const_cast<Player*>(this), const_cast<Item*>(item), (slots_t)index, true))
  2692.             return RET_CANNOTBEDRESSED;
  2693.  
  2694.         //check if enough capacity
  2695.         if(!hasCapacity(item, count))
  2696.             return RET_NOTENOUGHCAPACITY;
  2697.     }
  2698.  
  2699.     return ret;
  2700. }
  2701.  
  2702. ReturnValue Player::__queryMaxCount(int32_t index, const Thing* thing, uint32_t count, uint32_t& maxQueryCount,
  2703.     uint32_t flags) const
  2704. {
  2705.     const Item* item = thing->getItem();
  2706.     if(!item)
  2707.     {
  2708.         maxQueryCount = 0;
  2709.         return RET_NOTPOSSIBLE;
  2710.     }
  2711.  
  2712.     if(index == INDEX_WHEREEVER)
  2713.     {
  2714.         uint32_t n = 0;
  2715.         for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i)
  2716.         {
  2717.             if(Item* inventoryItem = inventory[i])
  2718.             {
  2719.                 if(Container* subContainer = inventoryItem->getContainer())
  2720.                 {
  2721.                     uint32_t queryCount = 0;
  2722.                     subContainer->__queryMaxCount(INDEX_WHEREEVER, item, item->getItemCount(), queryCount, flags);
  2723.  
  2724.                     //iterate through all items, including sub-containers (deep search)
  2725.                     n += queryCount;
  2726.                     for(ContainerIterator cit = subContainer->begin(); cit != subContainer->end(); ++cit)
  2727.                     {
  2728.                         if(Container* tmpContainer  = (*cit)->getContainer())
  2729.                         {
  2730.                             queryCount = 0;
  2731.                             tmpContainer->__queryMaxCount(INDEX_WHEREEVER, item, item->getItemCount(), queryCount, flags);
  2732.                             n += queryCount;
  2733.                         }
  2734.                     }
  2735.                 }
  2736.                 else if(inventoryItem->isStackable() && item->getID() == inventoryItem->getID() && inventoryItem->getItemCount() < 100)
  2737.                 {
  2738.                     uint32_t remainder = (100 - inventoryItem->getItemCount());
  2739.                     if(__queryAdd(i, item, remainder, flags) == RET_NOERROR)
  2740.                         n += remainder;
  2741.                 }
  2742.             }
  2743.             else if(__queryAdd(i, item, item->getItemCount(), flags) == RET_NOERROR)
  2744.             {
  2745.                 if(item->isStackable())
  2746.                     n += 100;
  2747.                 else
  2748.                     n += 1;
  2749.             }
  2750.         }
  2751.  
  2752.         maxQueryCount = n;
  2753.     }
  2754.     else
  2755.     {
  2756.         const Thing* destThing = __getThing(index);
  2757.         const Item* destItem = NULL;
  2758.         if(destThing)
  2759.             destItem = destThing->getItem();
  2760.  
  2761.         if(destItem)
  2762.         {
  2763.             if(destItem->isStackable() && item->getID() == destItem->getID() && destItem->getItemCount() < 100)
  2764.                 maxQueryCount = 100 - destItem->getItemCount();
  2765.             else
  2766.                 maxQueryCount = 0;
  2767.         }
  2768.         else if(__queryAdd(index, item, count, flags) == RET_NOERROR)
  2769.         {
  2770.             if(item->isStackable())
  2771.                 maxQueryCount = 100;
  2772.             else
  2773.                 maxQueryCount = 1;
  2774.  
  2775.             return RET_NOERROR;
  2776.         }
  2777.     }
  2778.  
  2779.     if(maxQueryCount < count)
  2780.         return RET_NOTENOUGHROOM;
  2781.  
  2782.     return RET_NOERROR;
  2783. }
  2784.  
  2785. ReturnValue Player::__queryRemove(const Thing* thing, uint32_t count, uint32_t flags) const
  2786. {
  2787.     int32_t index = __getIndexOfThing(thing);
  2788.     if(index == -1)
  2789.         return RET_NOTPOSSIBLE;
  2790.  
  2791.     const Item* item = thing->getItem();
  2792.     if(!item)
  2793.         return RET_NOTPOSSIBLE;
  2794.  
  2795.     if(!count || (item->isStackable() && count > item->getItemCount()))
  2796.         return RET_NOTPOSSIBLE;
  2797.  
  2798.      if(!item->isMovable() && !hasBitSet(FLAG_IGNORENOTMOVABLE, flags))
  2799.         return RET_NOTMOVABLE;
  2800.  
  2801.     return RET_NOERROR;
  2802. }
  2803.  
  2804. Cylinder* Player::__queryDestination(int32_t& index, const Thing* thing, Item** destItem,
  2805.     uint32_t& flags)
  2806. {
  2807.     if(!index /*drop to capacity window*/ || index == INDEX_WHEREEVER)
  2808.     {
  2809.         *destItem = NULL;
  2810.         const Item* item = thing->getItem();
  2811.         if(!item)
  2812.             return this;
  2813.  
  2814.         std::list<std::pair<Container*, int32_t> > containers;
  2815.         std::list<std::pair<Cylinder*, int32_t> > freeSlots;
  2816.  
  2817.         bool autoStack = !((flags & FLAG_IGNOREAUTOSTACK) == FLAG_IGNOREAUTOSTACK);
  2818.         for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i)
  2819.         {
  2820.             if(Item* invItem = inventory[i])
  2821.             {
  2822.                 if(invItem == item || invItem == tradeItem)
  2823.                     continue;
  2824.  
  2825.                 if(autoStack && item->isStackable() && __queryAdd(i, item, item->getItemCount(), 0)
  2826.                     == RET_NOERROR && invItem->getID() == item->getID() && invItem->getItemCount() < 100)
  2827.                 {
  2828.                     *destItem = invItem;
  2829.                     index = i;
  2830.                     return this;
  2831.                 }
  2832.  
  2833.                 if(Container* container = invItem->getContainer())
  2834.                 {
  2835.                     if(!autoStack && container->__queryAdd(INDEX_WHEREEVER,
  2836.                         item, item->getItemCount(), flags) == RET_NOERROR)
  2837.                     {
  2838.                         index = INDEX_WHEREEVER;
  2839.                         return container;
  2840.                     }
  2841.  
  2842.                     containers.push_back(std::make_pair(container, 0));
  2843.                 }
  2844.             }
  2845.             else if(!autoStack)
  2846.             {
  2847.                 if(__queryAdd(i, item, item->getItemCount(), 0) == RET_NOERROR)
  2848.                 {
  2849.                     index = i;
  2850.                     return this;
  2851.                 }
  2852.             }
  2853.             else
  2854.                 freeSlots.push_back(std::make_pair(this, i));
  2855.         }
  2856.  
  2857.         int32_t deepness = g_config.getNumber(ConfigManager::PLAYER_DEEPNESS);
  2858.         while(!containers.empty())
  2859.         {
  2860.             Container* tmpContainer = containers.front().first;
  2861.             int32_t level = containers.front().second;
  2862.  
  2863.             containers.pop_front();
  2864.             if(!tmpContainer)
  2865.                 continue;
  2866.  
  2867.             for(uint32_t n = 0; n < tmpContainer->capacity(); ++n)
  2868.             {
  2869.                 if(Item* tmpItem = tmpContainer->getItem(n))
  2870.                 {
  2871.                     if(tmpItem == item || tmpItem == tradeItem)
  2872.                         continue;
  2873.  
  2874.                     if(autoStack && item->isStackable() && tmpContainer->__queryAdd(n, item, item->getItemCount(),
  2875.                         0) == RET_NOERROR && tmpItem->getID() == item->getID() && tmpItem->getItemCount() < 100)
  2876.                     {
  2877.                         index = n;
  2878.                         *destItem = tmpItem;
  2879.                         return tmpContainer;
  2880.                     }
  2881.  
  2882.                     if(Container* container = tmpItem->getContainer())
  2883.                     {
  2884.                         if(!autoStack && container->__queryAdd(INDEX_WHEREEVER,
  2885.                             item, item->getItemCount(), flags) == RET_NOERROR)
  2886.                         {
  2887.                             index = INDEX_WHEREEVER;
  2888.                             return container;
  2889.                         }
  2890.  
  2891.                         if(deepness < 0 || level < deepness)
  2892.                             containers.push_back(std::make_pair(container, level + 1));
  2893.                     }
  2894.                 }
  2895.                 else
  2896.                 {
  2897.                     if(!autoStack)
  2898.                     {
  2899.                         if(tmpContainer->__queryAdd(n, item, item->getItemCount(), 0) == RET_NOERROR)
  2900.                         {
  2901.                             index = n;
  2902.                             return tmpContainer;
  2903.                         }
  2904.                     }
  2905.                     else
  2906.                         freeSlots.push_back(std::make_pair(tmpContainer, n));
  2907.  
  2908.                     break; // one slot to check is definitely enough.
  2909.                 }
  2910.             }
  2911.         }
  2912.  
  2913.         if(autoStack)
  2914.         {
  2915.             while(!freeSlots.empty())
  2916.             {
  2917.                 Cylinder* tmpCylinder = freeSlots.front().first;
  2918.                 int32_t i = freeSlots.front().second;
  2919.  
  2920.                 freeSlots.pop_front();
  2921.                 if(!tmpCylinder)
  2922.                     continue;
  2923.  
  2924.                 if(tmpCylinder->__queryAdd(i, item, item->getItemCount(), flags) == RET_NOERROR)
  2925.                 {
  2926.                     index = i;
  2927.                     return tmpCylinder;
  2928.                 }
  2929.             }
  2930.         }
  2931.  
  2932.         return this;
  2933.     }
  2934.  
  2935.     Thing* destThing = __getThing(index);
  2936.     if(destThing)
  2937.         *destItem = destThing->getItem();
  2938.  
  2939.     if(Cylinder* subCylinder = dynamic_cast<Cylinder*>(destThing))
  2940.     {
  2941.         index = INDEX_WHEREEVER;
  2942.         *destItem = NULL;
  2943.         return subCylinder;
  2944.     }
  2945.  
  2946.     return this;
  2947. }
  2948.  
  2949. void Player::__addThing(Creature* actor, Thing* thing)
  2950. {
  2951.     __addThing(actor, 0, thing);
  2952. }
  2953.  
  2954. void Player::__addThing(Creature*, int32_t index, Thing* thing)
  2955. {
  2956.     if(index < 0 || index > 11)
  2957.     {
  2958. #ifdef __DEBUG_MOVESYS__
  2959.         std::clog << "Failure: [Player::__addThing], " << "player: " << getName() << ", index: " << index << ", index < 0 || index > 11" << std::endl;
  2960. #endif
  2961.         return /*RET_NOTPOSSIBLE*/;
  2962.     }
  2963.  
  2964.     if(!index)
  2965.     {
  2966. #ifdef __DEBUG_MOVESYS__
  2967.         std::clog << "Failure: [Player::__addThing], " << "player: " << getName() << ", index == 0" << std::endl;
  2968. #endif
  2969.         return /*RET_NOTENOUGHROOM*/;
  2970.     }
  2971.  
  2972.     Item* item = thing->getItem();
  2973.     if(!item)
  2974.     {
  2975. #ifdef __DEBUG_MOVESYS__
  2976.         std::clog << "Failure: [Player::__addThing], " << "player: " << getName() << ", item == NULL" << std::endl;
  2977. #endif
  2978.         return /*RET_NOTPOSSIBLE*/;
  2979.     }
  2980.  
  2981.     item->setParent(this);
  2982.     inventory[index] = item;
  2983.  
  2984.     //send to client
  2985.     sendAddInventoryItem((slots_t)index, item);
  2986.     //event methods
  2987.     onAddInventoryItem((slots_t)index, item);
  2988. }
  2989.  
  2990. void Player::__updateThing(Thing* thing, uint16_t itemId, uint32_t count)
  2991. {
  2992.     int32_t index = __getIndexOfThing(thing);
  2993.     if(index == -1)
  2994.     {
  2995. #ifdef __DEBUG_MOVESYS__
  2996.         std::clog << "Failure: [Player::__updateThing], " << "player: " << getName() << ", index == -1" << std::endl;
  2997. #endif
  2998.         return /*RET_NOTPOSSIBLE*/;
  2999.     }
  3000.  
  3001.     Item* item = thing->getItem();
  3002.     if(!item)
  3003.     {
  3004. #ifdef __DEBUG_MOVESYS__
  3005.         std::clog << "Failure: [Player::__updateThing], " << "player: " << getName() << ", item == NULL" << std::endl;
  3006. #endif
  3007.         return /*RET_NOTPOSSIBLE*/;
  3008.     }
  3009.  
  3010.     const ItemType& oldType = Item::items[item->getID()];
  3011.     const ItemType& newType = Item::items[itemId];
  3012.  
  3013.     item->setID(itemId);
  3014.     item->setSubType(count);
  3015.  
  3016.     //send to client
  3017.     sendUpdateInventoryItem((slots_t)index, item, item);
  3018.     //event methods
  3019.     onUpdateInventoryItem((slots_t)index, item, oldType, item, newType);
  3020. }
  3021.  
  3022. void Player::__replaceThing(uint32_t index, Thing* thing)
  3023. {
  3024.     if(index > 11)
  3025.     {
  3026. #ifdef __DEBUG_MOVESYS__
  3027.         std::clog << "Failure: [Player::__replaceThing], " << "player: " << getName() << ", index: " << index << ", index < 0 || index > 11" << std::endl;
  3028. #endif
  3029.         return /*RET_NOTPOSSIBLE*/;
  3030.     }
  3031.  
  3032.     Item* oldItem = getInventoryItem((slots_t)index);
  3033.     if(!oldItem)
  3034.     {
  3035. #ifdef __DEBUG_MOVESYS__
  3036.         std::clog << "Failure: [Player::__updateThing], " << "player: " << getName() << ", oldItem == NULL" << std::endl;
  3037. #endif
  3038.         return /*RET_NOTPOSSIBLE*/;
  3039.     }
  3040.  
  3041.     Item* item = thing->getItem();
  3042.     if(!item)
  3043.     {
  3044. #ifdef __DEBUG_MOVESYS__
  3045.         std::clog << "Failure: [Player::__updateThing], " << "player: " << getName() << ", item == NULL" << std::endl;
  3046. #endif
  3047.         return /*RET_NOTPOSSIBLE*/;
  3048.     }
  3049.  
  3050.     const ItemType& oldType = Item::items[oldItem->getID()];
  3051.     const ItemType& newType = Item::items[item->getID()];
  3052.  
  3053.     //send to client
  3054.     sendUpdateInventoryItem((slots_t)index, oldItem, item);
  3055.     //event methods
  3056.     onUpdateInventoryItem((slots_t)index, oldItem, oldType, item, newType);
  3057.  
  3058.     item->setParent(this);
  3059.     inventory[index] = item;
  3060. }
  3061.  
  3062. void Player::__removeThing(Thing* thing, uint32_t count)
  3063. {
  3064.     Item* item = thing->getItem();
  3065.     if(!item)
  3066.     {
  3067. #ifdef __DEBUG_MOVESYS__
  3068.         std::clog << "Failure: [Player::__removeThing], " << "player: " << getName() << ", item == NULL" << std::endl;
  3069. #endif
  3070.         return /*RET_NOTPOSSIBLE*/;
  3071.     }
  3072.  
  3073.     int32_t index = __getIndexOfThing(thing);
  3074.     if(index == -1)
  3075.     {
  3076. #ifdef __DEBUG_MOVESYS__
  3077.         std::clog << "Failure: [Player::__removeThing], " << "player: " << getName() << ", index == -1" << std::endl;
  3078. #endif
  3079.         return /*RET_NOTPOSSIBLE*/;
  3080.     }
  3081.  
  3082.     if(item->isStackable())
  3083.     {
  3084.         if(count == item->getItemCount())
  3085.         {
  3086.             //send change to client
  3087.             sendRemoveInventoryItem((slots_t)index, item);
  3088.             //event methods
  3089.             onRemoveInventoryItem((slots_t)index, item);
  3090.  
  3091.             item->setParent(NULL);
  3092.             inventory[index] = NULL;
  3093.         }
  3094.         else
  3095.         {
  3096.             item->setItemCount(std::max(0, (int32_t)(item->getItemCount() - count)));
  3097.             const ItemType& it = Item::items[item->getID()];
  3098.  
  3099.             //send change to client
  3100.             sendUpdateInventoryItem((slots_t)index, item, item);
  3101.             //event methods
  3102.             onUpdateInventoryItem((slots_t)index, item, it, item, it);
  3103.         }
  3104.     }
  3105.     else
  3106.     {
  3107.         //send change to client
  3108.         sendRemoveInventoryItem((slots_t)index, item);
  3109.         //event methods
  3110.         onRemoveInventoryItem((slots_t)index, item);
  3111.  
  3112.         item->setParent(NULL);
  3113.         inventory[index] = NULL;
  3114.     }
  3115. }
  3116.  
  3117. Thing* Player::__getThing(uint32_t index) const
  3118. {
  3119.     if(index > SLOT_PRE_FIRST && index < SLOT_LAST)
  3120.         return inventory[index];
  3121.  
  3122.     return NULL;
  3123. }
  3124.  
  3125. int32_t Player::__getIndexOfThing(const Thing* thing) const
  3126. {
  3127.     for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i)
  3128.     {
  3129.         if(inventory[i] == thing)
  3130.             return i;
  3131.     }
  3132.  
  3133.     return -1;
  3134. }
  3135.  
  3136. int32_t Player::__getFirstIndex() const
  3137. {
  3138.     return SLOT_FIRST;
  3139. }
  3140.  
  3141. int32_t Player::__getLastIndex() const
  3142. {
  3143.     return SLOT_LAST;
  3144. }
  3145.  
  3146. uint32_t Player::__getItemTypeCount(uint16_t itemId, int32_t subType /*= -1*/) const
  3147. {
  3148.     Item* item = NULL;
  3149.     Container* container = NULL;
  3150.  
  3151.     uint32_t count = 0;
  3152.     for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i)
  3153.     {
  3154.         if(!(item = inventory[i]))
  3155.             continue;
  3156.  
  3157.         if(item->getID() != itemId)
  3158.         {
  3159.             if(!(container = item->getContainer()))
  3160.                 continue;
  3161.  
  3162.             for(ContainerIterator it = container->begin(), end = container->end(); it != end; ++it)
  3163.             {
  3164.                 if((*it)->getID() == itemId)
  3165.                     count += Item::countByType(*it, subType);
  3166.             }
  3167.         }
  3168.         else
  3169.             count += Item::countByType(item, subType);
  3170.     }
  3171.  
  3172.     return count;
  3173.  
  3174. }
  3175.  
  3176. std::map<uint32_t, uint32_t>& Player::__getAllItemTypeCount(std::map<uint32_t, uint32_t>& countMap) const
  3177. {
  3178.     Item* item = NULL;
  3179.     Container* container = NULL;
  3180.     for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i)
  3181.     {
  3182.         if(!(item = inventory[i]))
  3183.             continue;
  3184.  
  3185.         countMap[item->getID()] += Item::countByType(item, -1);
  3186.         if(!(container = item->getContainer()))
  3187.             continue;
  3188.  
  3189.         for(ContainerIterator it = container->begin(), end = container->end(); it != end; ++it)
  3190.             countMap[(*it)->getID()] += Item::countByType(*it, -1);
  3191.     }
  3192.  
  3193.     return countMap;
  3194. }
  3195.  
  3196. void Player::postAddNotification(Creature*, Thing* thing, const Cylinder* oldParent,
  3197.     int32_t index, cylinderlink_t link /*= LINK_OWNER*/)
  3198. {
  3199.     if(link == LINK_OWNER) //calling movement scripts
  3200.         g_moveEvents->onPlayerEquip(this, thing->getItem(), (slots_t)index, false);
  3201.  
  3202.     bool requireListUpdate = true;
  3203.     if(link == LINK_OWNER || link == LINK_TOPPARENT)
  3204.     {
  3205.         if(const Item* item = (oldParent ? oldParent->getItem() : NULL))
  3206.         {
  3207.             assert(item->getContainer() != NULL);
  3208.             requireListUpdate = item->getContainer()->getHoldingPlayer() != this;
  3209.         }
  3210.         else
  3211.             requireListUpdate = oldParent != this;
  3212.  
  3213.         updateInventoryWeight();
  3214.         updateItemsLight();
  3215.         updateWeapon();
  3216.         sendStats();
  3217.     }
  3218.  
  3219.     if(const Item* item = thing->getItem())
  3220.     {
  3221.         if(const Container* container = item->getContainer())
  3222.             onSendContainer(container);
  3223.  
  3224.         if(shopOwner && requireListUpdate)
  3225.             updateInventoryGoods(item->getID());
  3226.     }
  3227.     else if(const Creature* creature = thing->getCreature())
  3228.     {
  3229.         if(creature != this)
  3230.             return;
  3231.  
  3232.         std::vector<Container*> containers;
  3233.         for(ContainerVector::iterator it = containerVec.begin(); it != containerVec.end(); ++it)
  3234.         {
  3235.             if(!Position::areInRange<1,1,0>(it->second->getPosition(), getPosition()))
  3236.                 containers.push_back(it->second);
  3237.         }
  3238.  
  3239.         for(std::vector<Container*>::const_iterator it = containers.begin(); it != containers.end(); ++it)
  3240.             autoCloseContainers(*it);
  3241.     }
  3242. }
  3243.  
  3244. void Player::postRemoveNotification(Creature*, Thing* thing, const Cylinder* newParent,
  3245.     int32_t index, bool isCompleteRemoval, cylinderlink_t link /*= LINK_OWNER*/)
  3246. {
  3247.     if(link == LINK_OWNER) //calling movement scripts
  3248.         g_moveEvents->onPlayerDeEquip(this, thing->getItem(), (slots_t)index, isCompleteRemoval);
  3249.  
  3250.     bool requireListUpdate = true;
  3251.     if(link == LINK_OWNER || link == LINK_TOPPARENT)
  3252.     {
  3253.         if(const Item* item = (newParent ? newParent->getItem() : NULL))
  3254.         {
  3255.             assert(item->getContainer() != NULL);
  3256.             requireListUpdate = item->getContainer()->getHoldingPlayer() != this;
  3257.         }
  3258.         else
  3259.             requireListUpdate = newParent != this;
  3260.  
  3261.         updateInventoryWeight();
  3262.         updateItemsLight();
  3263.         updateWeapon();
  3264.         sendStats();
  3265.     }
  3266.  
  3267.     if(const Item* item = thing->getItem())
  3268.     {
  3269.         if(const Container* container = item->getContainer())
  3270.         {
  3271.             if(container->isRemoved() || !Position::areInRange<1,1,0>(getPosition(), container->getPosition()))
  3272.                 autoCloseContainers(container);
  3273.             else if(container->getTopParent() == this)
  3274.                 onSendContainer(container);
  3275.             else if(const Container* topContainer = dynamic_cast<const Container*>(container->getTopParent()))
  3276.             {
  3277.                 if(const Depot* depot = dynamic_cast<const Depot*>(topContainer))
  3278.                 {
  3279.                     bool isOwner = false;
  3280.                     for(DepotMap::iterator it = depots.begin(); it != depots.end(); ++it)
  3281.                     {
  3282.                         if(it->second.first != depot)
  3283.                             continue;
  3284.  
  3285.                         isOwner = true;
  3286.                         onSendContainer(container);
  3287.                     }
  3288.  
  3289.                     if(!isOwner)
  3290.                         autoCloseContainers(container);
  3291.                 }
  3292.                 else
  3293.                     onSendContainer(container);
  3294.             }
  3295.             else
  3296.                 autoCloseContainers(container);
  3297.         }
  3298.  
  3299.         if(shopOwner && requireListUpdate)
  3300.             updateInventoryGoods(item->getID());
  3301.     }
  3302. }
  3303.  
  3304. void Player::__internalAddThing(Thing* thing)
  3305. {
  3306.     __internalAddThing(0, thing);
  3307. }
  3308.  
  3309. void Player::__internalAddThing(uint32_t index, Thing* thing)
  3310. {
  3311. #ifdef __DEBUG_MOVESYS__
  3312.     std::clog << "[Player::__internalAddThing] index: " << index << std::endl;
  3313.  
  3314. #endif
  3315.     if(!index || index > 11)
  3316.     {
  3317. #ifdef __DEBUG_MOVESYS__
  3318.         std::clog << "Failure: [Player::__internalAddThing] index == 0 || index > 11" << std::endl;
  3319. #endif
  3320.         return;
  3321.     }
  3322.  
  3323.     if(inventory[index])
  3324.     {
  3325. #ifdef __DEBUG_MOVESYS__
  3326.         std::clog << "Warning: [Player::__internalAddThing], player: " << getName() << ", items[index] is not empty." << std::endl;
  3327. #endif
  3328.         return;
  3329.     }
  3330.  
  3331.     Item* item = thing->getItem();
  3332.     if(!item)
  3333.     {
  3334. #ifdef __DEBUG_MOVESYS__
  3335.         std::clog << "Failure: [Player::__internalAddThing] item == NULL" << std::endl;
  3336. #endif
  3337.         return;
  3338.     }
  3339.  
  3340.     inventory[index] = item;
  3341.     item->setParent(this);
  3342. }
  3343.  
  3344. bool Player::setFollowCreature(Creature* creature, bool fullPathSearch /*= false*/)
  3345. {
  3346.     bool deny = false;
  3347.     CreatureEventList followEvents = getCreatureEvents(CREATURE_EVENT_FOLLOW);
  3348.     for(CreatureEventList::iterator it = followEvents.begin(); it != followEvents.end(); ++it)
  3349.     {
  3350.         if(creature && !(*it)->executeFollow(this, creature))
  3351.             deny = true;
  3352.     }
  3353.  
  3354.     if(!deny && Creature::setFollowCreature(creature, fullPathSearch))
  3355.         return true;
  3356.  
  3357.     setFollowCreature(NULL);
  3358.     setAttackedCreature(NULL);
  3359.     if(!deny)
  3360.         sendCancelMessage(RET_THEREISNOWAY);
  3361.  
  3362.     sendCancelTarget();
  3363.     cancelNextWalk = true;
  3364.     return false;
  3365. }
  3366.  
  3367. bool Player::setAttackedCreature(Creature* creature)
  3368. {
  3369.     if(!Creature::setAttackedCreature(creature))
  3370.     {
  3371.         sendCancelTarget();
  3372.         return false;
  3373.     }
  3374.  
  3375.     if(chaseMode == CHASEMODE_FOLLOW && creature)
  3376.     {
  3377.         if(followCreature != creature) //chase opponent
  3378.             setFollowCreature(creature);
  3379.     }
  3380.     else
  3381.         setFollowCreature(NULL);
  3382.  
  3383.     if(creature)
  3384.         Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::checkCreatureAttack, &g_game, getID())));
  3385.  
  3386.     return true;
  3387. }
  3388.  
  3389. void Player::goToFollowCreature()
  3390. {
  3391.     if(!walkTask)
  3392.         Creature::goToFollowCreature();
  3393. }
  3394.  
  3395. void Player::getPathSearchParams(const Creature* creature, FindPathParams& fpp) const
  3396. {
  3397.     Creature::getPathSearchParams(creature, fpp);
  3398.     fpp.fullPathSearch = true;
  3399. }
  3400.  
  3401. void Player::doAttacking(uint32_t)
  3402. {
  3403.     if(!lastAttack)
  3404.         lastAttack = OTSYS_TIME() - getAttackSpeed() - 1;
  3405.     else if((OTSYS_TIME() - lastAttack) < getAttackSpeed())
  3406.         return;
  3407.  
  3408.     if(hasCondition(CONDITION_PACIFIED) && !hasCustomFlag(PlayerCustomFlag_IgnorePacification))
  3409.     {
  3410.         lastAttack = OTSYS_TIME();
  3411.         return;
  3412.     }
  3413.  
  3414.     Item* item = getWeapon(false);
  3415.     if(const Weapon* _weapon = g_weapons->getWeapon(item))
  3416.     {
  3417.         if(_weapon->interruptSwing() && !canDoAction())
  3418.         {
  3419.             SchedulerTask* task = createSchedulerTask(getNextActionTime(),
  3420.                 boost::bind(&Game::checkCreatureAttack, &g_game, getID()));
  3421.             setNextActionTask(task);
  3422.         }
  3423.         else
  3424.         {
  3425.             if((!_weapon->hasExhaustion() || !hasCondition(CONDITION_EXHAUST, EXHAUST_COMBAT)) && _weapon->useWeapon(this, item, attackedCreature))
  3426.                 lastAttack = OTSYS_TIME();
  3427.  
  3428.             updateWeapon();
  3429.         }
  3430.     }
  3431.     else if(Weapon::useFist(this, attackedCreature))
  3432.         lastAttack = OTSYS_TIME();
  3433. }
  3434.  
  3435. double Player::getGainedExperience(Creature* attacker) const
  3436. {
  3437.     if(!skillLoss)
  3438.         return 0;
  3439.  
  3440.     double rate = g_config.getDouble(ConfigManager::RATE_PVP_EXPERIENCE);
  3441.     if(rate <= 0)
  3442.         return 0;
  3443.  
  3444.     Player* attackerPlayer = attacker->getPlayer();
  3445.     if(!attackerPlayer || attackerPlayer == this)
  3446.         return 0;
  3447.  
  3448.     double attackerLevel = (double)attackerPlayer->getLevel(), max = g_config.getDouble(ConfigManager::EFP_MAX_THRESHOLD);
  3449.         if(max > 0 && level > (uint32_t)std::floor(attackerLevel * max))
  3450.            return 0;
  3451.  
  3452.     /*
  3453.         Formula
  3454.         a = attackers level * 0.9
  3455.         b = victims level
  3456.         c = victims experience
  3457.  
  3458.         result = (1 - (a / b)) * 0.05 * c
  3459.         Not affected by special multipliers(!)
  3460.     */
  3461.     uint32_t a = (uint32_t)std::floor(attackerLevel * 0.9), b = level;
  3462.     uint64_t c = getExperience();
  3463.     return (double)std::max((uint64_t)0, (uint64_t)std::floor(getDamageRatio(attacker)
  3464.         * std::max((double)0, ((double)(1 - (((double)a / b))))) * 0.05 * c)) * rate;
  3465. }
  3466.  
  3467. void Player::onFollowCreature(const Creature* creature)
  3468. {
  3469.     if(!creature)
  3470.         cancelNextWalk = true;
  3471. }
  3472.  
  3473. void Player::setChaseMode(chaseMode_t mode)
  3474. {
  3475.     chaseMode_t prevChaseMode = chaseMode;
  3476.     chaseMode = mode;
  3477.  
  3478.     if(prevChaseMode == chaseMode)
  3479.         return;
  3480.  
  3481.     if(chaseMode == CHASEMODE_FOLLOW)
  3482.     {
  3483.         if(!followCreature && attackedCreature) //chase opponent
  3484.             setFollowCreature(attackedCreature);
  3485.     }
  3486.     else if(attackedCreature)
  3487.     {
  3488.         setFollowCreature(NULL);
  3489.         cancelNextWalk = true;
  3490.     }
  3491. }
  3492.  
  3493. void Player::onWalkAborted()
  3494. {
  3495.     setNextWalkActionTask(NULL);
  3496.     sendCancelWalk();
  3497. }
  3498.  
  3499. void Player::onWalkComplete()
  3500. {
  3501.     if(!walkTask)
  3502.         return;
  3503.  
  3504.     walkTaskEvent = Scheduler::getInstance().addEvent(walkTask);
  3505.     walkTask = NULL;
  3506. }
  3507.  
  3508. void Player::getCreatureLight(LightInfo& light) const
  3509. {
  3510.     if(internalLight.level > itemsLight.level)
  3511.         light = internalLight;
  3512.     else
  3513.         light = itemsLight;
  3514. }
  3515.  
  3516. void Player::updateItemsLight(bool internal/* = false*/)
  3517. {
  3518.     LightInfo maxLight, curLight;
  3519.     Item* item = NULL;
  3520.     for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i)
  3521.     {
  3522.         if(!(item = getInventoryItem((slots_t)i)))
  3523.             continue;
  3524.  
  3525.         item->getLight(curLight);
  3526.         if(curLight.level > maxLight.level)
  3527.             maxLight = curLight;
  3528.     }
  3529.  
  3530.     if(maxLight.level > itemsLight.level || (maxLight.level == itemsLight.level && maxLight.color != itemsLight.color))
  3531.     {
  3532.         itemsLight = maxLight;
  3533.         if(!internal)
  3534.             g_game.changeLight(this);
  3535.     }
  3536. }
  3537.  
  3538. void Player::onAddCondition(ConditionType_t type, bool hadCondition)
  3539. {
  3540.     Creature::onAddCondition(type, hadCondition);
  3541.     if(getLastPosition().x && type != CONDITION_GAMEMASTER) // don't send if player have just logged in (its already done in protocolgame), or condition have no icons
  3542.         sendIcons();
  3543. }
  3544.  
  3545. void Player::onAddCombatCondition(ConditionType_t type, bool)
  3546. {
  3547.     std::string tmp;
  3548.     switch(type)
  3549.     {
  3550.         //client hardcoded
  3551.         case CONDITION_FIRE:
  3552.             tmp = "burning";
  3553.             break;
  3554.         case CONDITION_POISON:
  3555.             tmp = "poisoned";
  3556.             break;
  3557.         case CONDITION_ENERGY:
  3558.             tmp = "electrified";
  3559.             break;
  3560.         case CONDITION_FREEZING:
  3561.             tmp = "freezing";
  3562.             break;
  3563.         case CONDITION_DAZZLED:
  3564.             tmp = "dazzled";
  3565.             break;
  3566.         case CONDITION_CURSED:
  3567.             tmp = "cursed";
  3568.             break;
  3569.         case CONDITION_DROWN:
  3570.             tmp = "drowning";
  3571.             break;
  3572.         case CONDITION_DRUNK:
  3573.             tmp = "drunk";
  3574.             break;
  3575.         case CONDITION_PARALYZE:
  3576.             tmp = "paralyzed";
  3577.             break;
  3578.         /*case CONDITION_MANASHIELD:
  3579.             tmp = "protected by a magic shield";
  3580.             break;
  3581.         case CONDITION_HASTE:
  3582.             tmp = "hasted";
  3583.             break;
  3584.         case CONDITION_ATTRIBUTES:
  3585.             tmp = "strengthened";
  3586.             break;*/
  3587.         default:
  3588.             break;
  3589.     }
  3590.  
  3591.     if(!tmp.empty())
  3592.         sendTextMessage(MSG_STATUS_DEFAULT, "You are " + tmp + ".");
  3593. }
  3594.  
  3595. void Player::onEndCondition(ConditionType_t type)
  3596. {
  3597.     Creature::onEndCondition(type);
  3598.     if(type == CONDITION_INFIGHT)
  3599.     {
  3600.         onIdleStatus();
  3601.         clearAttacked();
  3602.  
  3603.         pzLocked = false;
  3604.         if(skull < SKULL_RED)
  3605.             setSkull(SKULL_NONE);
  3606.  
  3607.         g_game.updateCreatureSkull(this);
  3608.     }
  3609.  
  3610.     sendIcons();
  3611. }
  3612.  
  3613. void Player::onCombatRemoveCondition(const Creature*, Condition* condition)
  3614. {
  3615.     //Creature::onCombatRemoveCondition(attacker, condition);
  3616.     bool remove = true;
  3617.     if(condition->getId() > 0)
  3618.     {
  3619.         remove = false;
  3620.         //Means the condition is from an item, id == slot
  3621.         if(g_game.getWorldType() == WORLDTYPE_HARDCORE)
  3622.         {
  3623.             if(Item* item = getInventoryItem((slots_t)condition->getId()))
  3624.             {
  3625.                 //25% chance to destroy the item
  3626.                 if(random_range(1, 100) < 26)
  3627.                     g_game.internalRemoveItem(NULL, item);
  3628.             }
  3629.         }
  3630.     }
  3631.  
  3632.     if(remove)
  3633.     {
  3634.         if(!canDoAction())
  3635.         {
  3636.             int32_t delay = getNextActionTime();
  3637.             delay -= (delay % EVENT_CREATURE_THINK_INTERVAL);
  3638.             if(delay < 0)
  3639.                 removeCondition(condition);
  3640.             else
  3641.                 condition->setTicks(delay);
  3642.         }
  3643.         else
  3644.             removeCondition(condition);
  3645.     }
  3646. }
  3647.  
  3648. void Player::onTickCondition(ConditionType_t type, int32_t interval, bool& _remove)
  3649. {
  3650.     Creature::onTickCondition(type, interval, _remove);
  3651.     if(type == CONDITION_HUNTING)
  3652.         useStamina(-(interval * g_config.getNumber(ConfigManager::RATE_STAMINA_LOSS)));
  3653. }
  3654.  
  3655. void Player::onAttackedCreature(Creature* target)
  3656. {
  3657.     Creature::onAttackedCreature(target);
  3658.     if(hasFlag(PlayerFlag_NotGainInFight))
  3659.         return;
  3660.  
  3661.     addInFightTicks(false);
  3662.     Player* targetPlayer = target->getPlayer();
  3663.     if(!targetPlayer)
  3664.         return;
  3665.  
  3666.     addAttacked(targetPlayer);
  3667.     if(targetPlayer == this && targetPlayer->getZone() != ZONE_HARDCORE)
  3668.     {
  3669.         targetPlayer->sendCreatureSkull(this);
  3670.         return;
  3671.     }
  3672.  
  3673.     if(Combat::isInPvpZone(this, targetPlayer) || isPartner(targetPlayer) ||
  3674. #ifdef __WAR_SYSTEM__
  3675.         isAlly(targetPlayer) ||
  3676. #endif
  3677.         (g_config.getBool(ConfigManager::ALLOW_FIGHTBACK) && targetPlayer->hasAttacked(this)
  3678. #ifdef __WAR_SYSTEM__
  3679.         && !targetPlayer->isEnemy(this, false)
  3680. #endif
  3681.         ))
  3682.         return;
  3683.  
  3684.     if(!pzLocked)
  3685.     {
  3686.         pzLocked = true;
  3687.         sendIcons();
  3688.     }
  3689.  
  3690.     if(getZone() != target->getZone() || skull != SKULL_NONE
  3691. #ifdef __WAR_SYSTEM__
  3692.         || targetPlayer->isEnemy(this, true)
  3693. #endif
  3694.         )
  3695.         return;
  3696.  
  3697.     if(targetPlayer->getSkull() != SKULL_NONE)
  3698.         targetPlayer->sendCreatureSkull(this);
  3699. }
  3700.  
  3701. void Player::onSummonAttackedCreature(Creature* summon, Creature* target)
  3702. {
  3703.     Creature::onSummonAttackedCreature(summon, target);
  3704.     onAttackedCreature(target);
  3705. }
  3706.  
  3707. void Player::onAttacked()
  3708. {
  3709.     Creature::onAttacked();
  3710.     addInFightTicks(false);
  3711. }
  3712.  
  3713. bool Player::checkLoginDelay(uint32_t playerId) const
  3714. {
  3715.     return (!hasCustomFlag(PlayerCustomFlag_IgnoreLoginDelay) && OTSYS_TIME() <= (lastLoad + g_config.getNumber(
  3716.         ConfigManager::LOGIN_PROTECTION)) && !hasBeenAttacked(playerId));
  3717. }
  3718.  
  3719. void Player::onIdleStatus()
  3720. {
  3721.     Creature::onIdleStatus();
  3722.     if(getParty())
  3723.         getParty()->clearPlayerPoints(this);
  3724. }
  3725.  
  3726. void Player::onPlacedCreature()
  3727. {
  3728.     //scripting event - onLogin
  3729.     if(!g_creatureEvents->playerLogin(this))
  3730.         kick(true, true);
  3731. }
  3732.  
  3733. void Player::onAttackedCreatureDrain(Creature* target, int32_t points)
  3734. {
  3735.     Creature::onAttackedCreatureDrain(target, points);
  3736.     if(party && target && (!target->getMaster() || !target->getMaster()->getPlayer())
  3737.         && target->getMonster() && target->getMonster()->isHostile()) //we have fulfilled a requirement for shared experience
  3738.         getParty()->addPlayerDamageMonster(this, points);
  3739.  
  3740.     char buffer[100];
  3741.     sprintf(buffer, "You deal %d damage to %s.", points, target->getNameDescription().c_str());
  3742.     sendTextMessage(MSG_STATUS_DEFAULT, buffer);
  3743. }
  3744.  
  3745. void Player::onSummonAttackedCreatureDrain(Creature* summon, Creature* target, int32_t points)
  3746. {
  3747.     Creature::onSummonAttackedCreatureDrain(summon, target, points);
  3748.  
  3749.     char buffer[100];
  3750.     sprintf(buffer, "Your %s deals %d damage to %s.", summon->getName().c_str(), points, target->getNameDescription().c_str());
  3751.     sendTextMessage(MSG_EVENT_DEFAULT, buffer);
  3752. }
  3753.  
  3754. void Player::onTargetCreatureGainHealth(Creature* target, int32_t points)
  3755. {
  3756.     Creature::onTargetCreatureGainHealth(target, points);
  3757.     if(target && getParty())
  3758.     {
  3759.         Player* tmpPlayer = NULL;
  3760.         if(target->getPlayer())
  3761.             tmpPlayer = target->getPlayer();
  3762.         else if(target->getMaster() && target->getMaster()->getPlayer())
  3763.             tmpPlayer = target->getMaster()->getPlayer();
  3764.  
  3765.         if(isPartner(tmpPlayer))
  3766.             party->addPlayerHealedMember(this, points);
  3767.     }
  3768. }
  3769. #ifdef __WAR_SYSTEM__
  3770.  
  3771. GuildEmblems_t Player::getGuildEmblem(const Creature* creature) const
  3772. {
  3773.     const Player* player = creature->getPlayer();
  3774.     if(!player || !player->hasEnemy())
  3775.         return Creature::getGuildEmblem(creature);
  3776.  
  3777.     if(player->isEnemy(this, false))
  3778.         return EMBLEM_RED;
  3779.  
  3780.     return player->getGuildId() == guildId ? EMBLEM_GREEN : EMBLEM_BLUE;
  3781. }
  3782.  
  3783. bool Player::getEnemy(const Player* player, War_t& data) const
  3784. {
  3785.     if(!guildId || !player || player->isRemoved())
  3786.         return false;
  3787.  
  3788.     uint32_t guild = player->getGuildId();
  3789.     if(!guild)
  3790.         return false;
  3791.  
  3792.     WarMap::const_iterator it = warMap.find(guild);
  3793.     if(it == warMap.end())
  3794.         return false;
  3795.  
  3796.     data = it->second;
  3797.     return true;
  3798. }
  3799.  
  3800. bool Player::isEnemy(const Player* player, bool allies) const
  3801. {
  3802.     if(!guildId || !player || player->isRemoved())
  3803.         return false;
  3804.  
  3805.     uint32_t guild = player->getGuildId();
  3806.     if(!guild)
  3807.         return false;
  3808.  
  3809.     return !warMap.empty() && (((g_game.getWorldType() != WORLDTYPE_OPTIONAL || g_config.getBool(
  3810.         ConfigManager::OPTIONAL_WAR_ATTACK_ALLY)) && allies && guildId == guild) ||
  3811.         warMap.find(guild) != warMap.end());
  3812. }
  3813.  
  3814. bool Player::isAlly(const Player* player) const
  3815. {
  3816.     return !warMap.empty() && player && player->getGuildId() == guildId;
  3817. }
  3818. #endif
  3819.  
  3820. bool Player::onKilledCreature(Creature* target, DeathEntry& entry)
  3821. {
  3822.     if(!Creature::onKilledCreature(target, entry))
  3823.         return false;
  3824.  
  3825.     if(hasFlag(PlayerFlag_NotGenerateLoot))
  3826.         target->setDropLoot(LOOT_DROP_NONE);
  3827.  
  3828.     Condition* condition = NULL;
  3829.     if(target->getMonster() && !target->isPlayerSummon() && !hasFlag(PlayerFlag_HasInfiniteStamina)
  3830.         && (condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_HUNTING,
  3831.         g_config.getNumber(ConfigManager::HUNTING_DURATION))))
  3832.         addCondition(condition);
  3833.  
  3834.     if(hasFlag(PlayerFlag_NotGainInFight) || getZone() != target->getZone())
  3835.         return true;
  3836.  
  3837.     Player* targetPlayer = target->getPlayer();
  3838.     if(!targetPlayer || Combat::isInPvpZone(this, targetPlayer) || isPartner(targetPlayer)
  3839. #ifdef __WAR_SYSTEM__
  3840.         || isAlly(targetPlayer)
  3841. #endif
  3842.         )
  3843.         return true;
  3844. #ifdef __WAR_SYSTEM__
  3845.  
  3846.     War_t enemy;
  3847.     if(targetPlayer->getEnemy(this, enemy) && (!entry.isLast() || IOGuild::getInstance()->updateWar(enemy)))
  3848.         entry.setWar(enemy);
  3849.  
  3850. #endif
  3851.  
  3852.     if(!entry.isJustify() || !hasCondition(CONDITION_INFIGHT))
  3853.         return true;
  3854.  
  3855.     if(!targetPlayer->hasAttacked(this) && target->getSkull() == SKULL_NONE && targetPlayer != this
  3856.         && (addUnjustifiedKill(targetPlayer,
  3857. #ifndef __WAR_SYSTEM__
  3858.         true
  3859. #else
  3860.         !enemy.war
  3861. #endif
  3862.         ) || entry.isLast()))
  3863.         entry.setUnjustified();
  3864.  
  3865.     addInFightTicks(true, g_config.getNumber(ConfigManager::WHITE_SKULL_TIME));
  3866.     return true;
  3867. }
  3868.  
  3869. bool Player::gainExperience(double& gainExp, bool fromMonster)
  3870. {
  3871.     if(!rateExperience(gainExp, fromMonster))
  3872.         return false;
  3873.  
  3874.     //soul regeneration
  3875.     if(gainExp >= level)
  3876.     {
  3877.         if(Condition* condition = Condition::createCondition(
  3878.             CONDITIONID_DEFAULT, CONDITION_SOUL, 4 * 60 * 1000))
  3879.         {
  3880.             condition->setParam(CONDITIONPARAM_SOULGAIN,
  3881.                 vocation->getGainAmount(GAIN_SOUL));
  3882.             condition->setParam(CONDITIONPARAM_SOULTICKS,
  3883.                 (vocation->getGainTicks(GAIN_SOUL) * 1000));
  3884.             addCondition(condition);
  3885.         }
  3886.     }
  3887.  
  3888.     addExperience((uint64_t)gainExp);
  3889.     return true;
  3890. }
  3891.  
  3892. bool Player::rateExperience(double& gainExp, bool fromMonster)
  3893. {
  3894.     if(hasFlag(PlayerFlag_NotGainExperience) || gainExp <= 0)
  3895.         return false;
  3896.  
  3897.     if(!fromMonster)
  3898.         return true;
  3899.  
  3900.     gainExp *= rates[SKILL__LEVEL] * g_game.getExperienceStage(level,
  3901.         vocation->getExperienceMultiplier());
  3902.     if(!hasFlag(PlayerFlag_HasInfiniteStamina))
  3903.     {
  3904.         int32_t minutes = getStaminaMinutes();
  3905.         if(minutes >= g_config.getNumber(ConfigManager::STAMINA_LIMIT_TOP))
  3906.         {
  3907.             if(isPremium() || !g_config.getNumber(ConfigManager::STAMINA_BONUS_PREMIUM))
  3908.                 gainExp *= g_config.getDouble(ConfigManager::RATE_STAMINA_ABOVE);
  3909.         }
  3910.         else if(minutes < (g_config.getNumber(ConfigManager::STAMINA_LIMIT_BOTTOM)) && minutes > 0)
  3911.             gainExp *= g_config.getDouble(ConfigManager::RATE_STAMINA_UNDER);
  3912.         else if(minutes <= 0)
  3913.             gainExp = 0;
  3914.     }
  3915.     else if(isPremium() || !g_config.getNumber(ConfigManager::STAMINA_BONUS_PREMIUM))
  3916.         gainExp *= g_config.getDouble(ConfigManager::RATE_STAMINA_ABOVE);
  3917.  
  3918.     return true;
  3919. }
  3920.  
  3921. void Player::onGainExperience(double& gainExp, bool fromMonster, bool multiplied)
  3922. {
  3923.     if(party && party->isSharedExperienceEnabled() && party->isSharedExperienceActive())
  3924.     {
  3925.         party->shareExperience(gainExp, fromMonster, multiplied);
  3926.         rateExperience(gainExp, fromMonster);
  3927.         return; //we will get a share of the experience through the sharing mechanism
  3928.     }
  3929.  
  3930.     if(gainExperience(gainExp, fromMonster))
  3931.         Creature::onGainExperience(gainExp, fromMonster, true);
  3932. }
  3933.  
  3934. void Player::onGainSharedExperience(double& gainExp, bool fromMonster, bool)
  3935. {
  3936.     if(gainExperience(gainExp, fromMonster))
  3937.         Creature::onGainSharedExperience(gainExp, fromMonster, true);
  3938. }
  3939.  
  3940. bool Player::isImmune(CombatType_t type) const
  3941. {
  3942.     return hasCustomFlag(PlayerCustomFlag_IsImmune) || Creature::isImmune(type);
  3943. }
  3944.  
  3945. bool Player::isImmune(ConditionType_t type) const
  3946. {
  3947.     return hasCustomFlag(PlayerCustomFlag_IsImmune) || Creature::isImmune(type);
  3948. }
  3949.  
  3950. bool Player::isAttackable() const
  3951. {
  3952.     return (!hasFlag(PlayerFlag_CannotBeAttacked) && !isAccountManager());
  3953. }
  3954.  
  3955. void Player::changeHealth(int32_t healthChange)
  3956. {
  3957.     Creature::changeHealth(healthChange);
  3958.     sendStats();
  3959. }
  3960.  
  3961. void Player::changeMana(int32_t manaChange)
  3962. {
  3963.     if(!hasFlag(PlayerFlag_HasInfiniteMana))
  3964.         Creature::changeMana(manaChange);
  3965.  
  3966.     sendStats();
  3967. }
  3968.  
  3969. void Player::changeSoul(int32_t soulChange)
  3970. {
  3971.     if(!hasFlag(PlayerFlag_HasInfiniteSoul))
  3972.         soul = std::min((int32_t)soulMax, (int32_t)soul + soulChange);
  3973.  
  3974.     sendStats();
  3975. }
  3976.  
  3977. bool Player::changeOutfit(Outfit_t outfit, bool checkList)
  3978. {
  3979.     uint32_t outfitId = Outfits::getInstance()->getOutfitId(outfit.lookType);
  3980.     if(checkList && (!canWearOutfit(outfitId, outfit.lookAddons) || !requestedOutfit))
  3981.         return false;
  3982.  
  3983.     requestedOutfit = false;
  3984.     if(outfitAttributes)
  3985.     {
  3986.         uint32_t oldId = Outfits::getInstance()->getOutfitId(defaultOutfit.lookType);
  3987.         outfitAttributes = !Outfits::getInstance()->removeAttributes(getID(), oldId, sex);
  3988.     }
  3989.  
  3990.     defaultOutfit = outfit;
  3991.     outfitAttributes = Outfits::getInstance()->addAttributes(getID(), outfitId, sex, defaultOutfit.lookAddons);
  3992.     return true;
  3993. }
  3994.  
  3995. bool Player::canWearOutfit(uint32_t outfitId, uint32_t addons)
  3996. {
  3997.     OutfitMap::iterator it = outfits.find(outfitId);
  3998.     if(it == outfits.end() || (it->second.isPremium && !isPremium()) || getAccess() < it->second.accessLevel
  3999.         || ((it->second.addons & addons) != addons && !hasCustomFlag(PlayerCustomFlag_CanWearAllAddons)))
  4000.         return false;
  4001.  
  4002.     if(it->second.storageId.empty())
  4003.         return true;
  4004.  
  4005.     std::string value;
  4006.     getStorage(it->second.storageId, value);
  4007.  
  4008.     bool ret = value == it->second.storageValue;
  4009.     if(ret)
  4010.         return ret;
  4011.  
  4012.     int32_t tmp = atoi(value.c_str());
  4013.     if(!tmp && value != "0")
  4014.         return ret;
  4015.  
  4016.     tmp = atoi(it->second.storageValue.c_str());
  4017.     if(!tmp && it->second.storageValue != "0")
  4018.         return ret;
  4019.  
  4020.     return atoi(value.c_str()) >= tmp;
  4021. }
  4022.  
  4023. bool Player::addOutfit(uint32_t outfitId, uint32_t addons)
  4024. {
  4025.     Outfit outfit;
  4026.     if(!Outfits::getInstance()->getOutfit(outfitId, sex, outfit))
  4027.         return false;
  4028.  
  4029.     OutfitMap::iterator it = outfits.find(outfitId);
  4030.     if(it != outfits.end())
  4031.         outfit.addons |= it->second.addons;
  4032.  
  4033.     outfit.addons |= addons;
  4034.     outfits[outfitId] = outfit;
  4035.     return true;
  4036. }
  4037.  
  4038. bool Player::removeOutfit(uint32_t outfitId, uint32_t addons)
  4039. {
  4040.     OutfitMap::iterator it = outfits.find(outfitId);
  4041.     if(it == outfits.end())
  4042.         return false;
  4043.  
  4044.     if(addons == 0xFF) //remove outfit
  4045.         outfits.erase(it);
  4046.     else //remove addons
  4047.         outfits[outfitId].addons = it->second.addons & (~addons);
  4048.  
  4049.     return true;
  4050. }
  4051.  
  4052. void Player::generateReservedStorage()
  4053. {
  4054.     uint32_t key = PSTRG_OUTFITSID_RANGE_START + 1;
  4055.     const OutfitMap& defaultOutfits = Outfits::getInstance()->getOutfits(sex);
  4056.     for(OutfitMap::const_iterator it = outfits.begin(); it != outfits.end(); ++it)
  4057.     {
  4058.         OutfitMap::const_iterator dit = defaultOutfits.find(it->first);
  4059.         if(dit == defaultOutfits.end() || (dit->second.isDefault && (dit->second.addons
  4060.             & it->second.addons) == it->second.addons))
  4061.             continue;
  4062.  
  4063.         std::stringstream k, v;
  4064.         k << key++; // this may not work as intended, revalidate it
  4065.         v << ((it->first << 16) | (it->second.addons & 0xFF));
  4066.  
  4067.         storageMap[k.str()] = v.str();
  4068.         if(key <= PSTRG_OUTFITSID_RANGE_START + PSTRG_OUTFITSID_RANGE_SIZE)
  4069.             continue;
  4070.  
  4071.         std::clog << "[Warning - Player::genReservedStorageRange] Player " << getName() << " with more than 500 outfits!" << std::endl;
  4072.         break;
  4073.     }
  4074. }
  4075.  
  4076. void Player::setSex(uint16_t newSex)
  4077. {
  4078.     sex = newSex;
  4079.     const OutfitMap& defaultOutfits = Outfits::getInstance()->getOutfits(sex);
  4080.     for(OutfitMap::const_iterator it = defaultOutfits.begin(); it != defaultOutfits.end(); ++it)
  4081.     {
  4082.         if(it->second.isDefault)
  4083.             addOutfit(it->first, it->second.addons);
  4084.     }
  4085. }
  4086.  
  4087. Skulls_t Player::getSkull() const
  4088. {
  4089.     if(hasFlag(PlayerFlag_NotGainInFight) || hasCustomFlag(PlayerCustomFlag_NotGainSkull))
  4090.         return SKULL_NONE;
  4091.  
  4092.     return skull;
  4093. }
  4094.  
  4095. Skulls_t Player::getSkullType(const Creature* creature) const
  4096. {
  4097.         const Player* player = creature->getPlayer();
  4098.         if(player && player->getSkull() == SKULL_NONE)
  4099.         {
  4100.         }
  4101.  
  4102.         return Creature::getSkullType(creature);
  4103. }
  4104.  
  4105. bool Player::hasAttacked(const Player* attacked) const
  4106. {
  4107.     return !hasFlag(PlayerFlag_NotGainInFight) && attacked &&
  4108.         attackedSet.find(attacked->getID()) != attackedSet.end();
  4109. }
  4110.  
  4111. void Player::addAttacked(const Player* attacked)
  4112. {
  4113.     if(hasFlag(PlayerFlag_NotGainInFight) || !attacked)
  4114.         return;
  4115.  
  4116.     uint32_t attackedId = attacked->getID();
  4117.     if(attackedSet.find(attackedId) == attackedSet.end())
  4118.         attackedSet.insert(attackedId);
  4119. }
  4120.  
  4121. void Player::setSkullEnd(time_t _time, bool login, Skulls_t _skull)
  4122. {
  4123.     if(g_game.getWorldType() != WORLDTYPE_HARDCORE
  4124.         || hasFlag(PlayerFlag_NotGainInFight) ||
  4125.         hasCustomFlag(PlayerCustomFlag_NotGainSkull))
  4126.         return;
  4127.  
  4128.     bool requireUpdate = false;
  4129.     if(_time > time(NULL))
  4130.     {
  4131.         requireUpdate = true;
  4132.         setSkull(_skull);
  4133.     }
  4134.     else if(skull == _skull)
  4135.     {
  4136.         requireUpdate = true;
  4137.         _time = 0;
  4138.     }
  4139.  
  4140.     if(requireUpdate)
  4141.     {
  4142.         skullEnd = _time;
  4143.         if(!login)
  4144.             g_game.updateCreatureSkull(this);
  4145.     }
  4146. }
  4147.  
  4148. bool Player::addUnjustifiedKill(const Player* attacked, bool countNow)
  4149. {
  4150.     if(!g_config.getBool(ConfigManager::USE_FRAG_HANDLER) || hasFlag(
  4151.         PlayerFlag_NotGainInFight) || g_game.getWorldType() != WORLDTYPE_OPEN
  4152.         || hasCustomFlag(PlayerCustomFlag_NotGainUnjustified) || hasCustomFlag(
  4153.         PlayerCustomFlag_NotGainSkull) || attacked == this)
  4154.         return false;
  4155.  
  4156.     if(client && countNow)
  4157.     {
  4158.         char buffer[90];
  4159.         sprintf(buffer, "Warning! The murder of %s was not justified.",
  4160.             attacked->getName().c_str());
  4161.         client->sendTextMessage(MSG_STATUS_WARNING, buffer);
  4162.     }
  4163.  
  4164.     time_t now = time(NULL), today = (now - 84600), week = (now - (7 * 84600));
  4165.     std::vector<time_t> dateList;
  4166.  
  4167.     IOLoginData::getInstance()->getUnjustifiedDates(guid, dateList, now);
  4168.     if(countNow)
  4169.         dateList.push_back(now);
  4170.  
  4171.     uint32_t tc = 0, wc = 0, mc = dateList.size();
  4172.     for(std::vector<time_t>::iterator it = dateList.begin(); it != dateList.end(); ++it)
  4173.     {
  4174.         if((*it) > week)
  4175.             wc++;
  4176.  
  4177.         if((*it) > today)
  4178.             tc++;
  4179.     }
  4180.  
  4181.     uint32_t d = g_config.getNumber(ConfigManager::RED_DAILY_LIMIT), w = g_config.getNumber(
  4182.         ConfigManager::RED_WEEKLY_LIMIT), m = g_config.getNumber(ConfigManager::RED_MONTHLY_LIMIT);
  4183.     if(skull < SKULL_RED && ((d > 0 && tc >= d) || (w > 0 && wc >= w) || (m > 0 && mc >= m)))
  4184.         setSkullEnd(now + g_config.getNumber(ConfigManager::RED_SKULL_LENGTH), false, SKULL_RED);
  4185.  
  4186.     if(!g_config.getBool(ConfigManager::USE_BLACK_SKULL))
  4187.     {
  4188.         d += g_config.getNumber(ConfigManager::BAN_DAILY_LIMIT);
  4189.         w += g_config.getNumber(ConfigManager::BAN_WEEKLY_LIMIT);
  4190.         m += g_config.getNumber(ConfigManager::BAN_MONTHLY_LIMIT);
  4191.         if((d <= 0 || tc < d) && (w <= 0 || wc < w) && (m <= 0 || mc < m))
  4192.             return true;
  4193.  
  4194.         if(!IOBan::getInstance()->addAccountBanishment(accountId, (now + g_config.getNumber(
  4195.             ConfigManager::KILLS_BAN_LENGTH)), 20, ACTION_BANISHMENT, "Unjustified player killing.", 0, guid))
  4196.             return true;
  4197.  
  4198.         sendTextMessage(MSG_INFO_DESCR, "You have been banished.");
  4199.         g_game.addMagicEffect(getPosition(), MAGIC_EFFECT_WRAPS_GREEN);
  4200.         Scheduler::getInstance().addEvent(createSchedulerTask(1000, boost::bind(
  4201.             &Game::kickPlayer, &g_game, getID(), false)));
  4202.     }
  4203.     else
  4204.     {
  4205.         d += g_config.getNumber(ConfigManager::BLACK_DAILY_LIMIT);
  4206.         w += g_config.getNumber(ConfigManager::BLACK_WEEKLY_LIMIT);
  4207.         m += g_config.getNumber(ConfigManager::BLACK_MONTHLY_LIMIT);
  4208.         if(skull < SKULL_BLACK && ((d > 0 && tc >= d) || (w > 0 && wc >= w) || (m > 0 && mc >= m)))
  4209.         {
  4210.             setSkullEnd(now + g_config.getNumber(ConfigManager::BLACK_SKULL_LENGTH), false, SKULL_BLACK);
  4211.             setAttackedCreature(NULL);
  4212.             destroySummons();
  4213.         }
  4214.     }
  4215.  
  4216.     return true;
  4217. }
  4218.  
  4219. void Player::setPromotionLevel(uint32_t pLevel)
  4220. {
  4221.     if(pLevel > promotionLevel)
  4222.     {
  4223.         uint32_t tmpLevel = 0, currentVoc = vocationId;
  4224.         for(uint32_t i = promotionLevel; i < pLevel; ++i)
  4225.         {
  4226.             currentVoc = Vocations::getInstance()->getPromotedVocation(currentVoc);
  4227.             if(!currentVoc)
  4228.                 break;
  4229.  
  4230.             tmpLevel++;
  4231.             Vocation* voc = Vocations::getInstance()->getVocation(currentVoc);
  4232.             if(voc->isPremiumNeeded() && !isPremium() && g_config.getBool(ConfigManager::PREMIUM_FOR_PROMOTION))
  4233.                 continue;
  4234.  
  4235.             vocationId = currentVoc;
  4236.         }
  4237.  
  4238.         promotionLevel += tmpLevel;
  4239.     }
  4240.     else if(pLevel < promotionLevel)
  4241.     {
  4242.         uint32_t tmpLevel = 0, currentVoc = vocationId;
  4243.         for(uint32_t i = pLevel; i < promotionLevel; ++i)
  4244.         {
  4245.             Vocation* voc = Vocations::getInstance()->getVocation(currentVoc);
  4246.             if(voc->getFromVocation() == currentVoc)
  4247.                 break;
  4248.  
  4249.             tmpLevel++;
  4250.             currentVoc = voc->getFromVocation();
  4251.             if(voc->isPremiumNeeded() && !isPremium() && g_config.getBool(ConfigManager::PREMIUM_FOR_PROMOTION))
  4252.                 continue;
  4253.  
  4254.             vocationId = currentVoc;
  4255.         }
  4256.  
  4257.         promotionLevel -= tmpLevel;
  4258.     }
  4259.  
  4260.     setVocation(vocationId);
  4261. }
  4262.  
  4263. uint16_t Player::getBlessings() const
  4264. {
  4265.     if(!g_config.getBool(ConfigManager::BLESSINGS) || (!isPremium() &&
  4266.         g_config.getBool(ConfigManager::BLESSING_ONLY_PREMIUM)))
  4267.         return 0;
  4268.  
  4269.     uint16_t count = 0;
  4270.     for(int16_t i = 0; i < 16; ++i)
  4271.     {
  4272.         if(hasBlessing(i))
  4273.             count++;
  4274.     }
  4275.  
  4276.     return count;
  4277. }
  4278.  
  4279. uint64_t Player::getLostExperience() const
  4280. {
  4281.     if(!skillLoss)
  4282.         return 0;
  4283.  
  4284.     double percent = (double)(lossPercent[LOSS_EXPERIENCE] - vocation->getLessLoss() - (getBlessings() * g_config.getNumber(
  4285.         ConfigManager::BLESS_REDUCTION))) / 100.;
  4286.     if(level <= 25)
  4287.         return (uint64_t)std::floor((double)(experience * percent) / 10.);
  4288.  
  4289.     int32_t base = level;
  4290.     double levels = (double)(base + 50) / 100.;
  4291.  
  4292.     uint64_t lost = 0;
  4293.     while(levels > 1.0f)
  4294.     {
  4295.         lost += (getExpForLevel(base) - getExpForLevel(base - 1));
  4296.         base--;
  4297.         levels -= 1.;
  4298.     }
  4299.  
  4300.     if(levels > 0.)
  4301.         lost += (uint64_t)std::floor((double)(getExpForLevel(base) - getExpForLevel(base - 1)) * levels);
  4302.  
  4303.     return (uint64_t)std::floor((double)(lost * percent));
  4304. }
  4305.  
  4306. uint32_t Player::getAttackSpeed() const
  4307. {
  4308.     return ((weapon && weapon->getAttackSpeed() != 0) ? weapon->getAttackSpeed() : (vocation->getAttackSpeed() / std::max((size_t)1, getWeapons().size())));
  4309. }
  4310.  
  4311. void Player::learnInstantSpell(const std::string& name)
  4312. {
  4313.     if(!hasLearnedInstantSpell(name))
  4314.         learnedInstantSpellList.push_back(name);
  4315. }
  4316.  
  4317. void Player::unlearnInstantSpell(const std::string& name)
  4318. {
  4319.     if(!hasLearnedInstantSpell(name))
  4320.         return;
  4321.  
  4322.     LearnedInstantSpellList::iterator it = std::find(learnedInstantSpellList.begin(), learnedInstantSpellList.end(), name);
  4323.     if(it != learnedInstantSpellList.end())
  4324.         learnedInstantSpellList.erase(it);
  4325. }
  4326.  
  4327. bool Player::hasLearnedInstantSpell(const std::string& name) const
  4328. {
  4329.     if(hasFlag(PlayerFlag_CannotUseSpells))
  4330.         return false;
  4331.  
  4332.     if(hasFlag(PlayerFlag_IgnoreSpellCheck))
  4333.         return true;
  4334.  
  4335.     for(LearnedInstantSpellList::const_iterator it = learnedInstantSpellList.begin(); it != learnedInstantSpellList.end(); ++it)
  4336.     {
  4337.         if(!strcasecmp((*it).c_str(), name.c_str()))
  4338.             return true;
  4339.     }
  4340.  
  4341.     return false;
  4342. }
  4343.  
  4344. void Player::manageAccount(const std::string &text)
  4345. {
  4346.     std::stringstream msg;
  4347.     msg << "Account Manager: ";
  4348.  
  4349.     bool noSwap = true;
  4350.     switch(accountManager)
  4351.     {
  4352.         case MANAGER_NAMELOCK:
  4353.         {
  4354.             if(!talkState[1])
  4355.             {
  4356.                 managerString = text;
  4357.                 trimString(managerString);
  4358.                 if(managerString.length() < 4)
  4359.                     msg << "Your name you want is too short, please select a longer name.";
  4360.                 else if(managerString.length() > 20)
  4361.                     msg << "The name you want is too long, please select a shorter name.";
  4362.                 else if(!isValidName(managerString))
  4363.                     msg << "That name seems to contain invalid symbols, please choose another name.";
  4364.                 else if(IOLoginData::getInstance()->playerExists(managerString, true))
  4365.                     msg << "A player with that name already exists, please choose another name.";
  4366.                 else
  4367.                 {
  4368.                     std::string tmp = asLowerCaseString(managerString);
  4369.                     if(tmp.substr(0, 4) != "god " && tmp.substr(0, 3) != "cm " && tmp.substr(0, 3) != "gm ")
  4370.                     {
  4371.                         talkState[1] = true;
  4372.                         talkState[2] = true;
  4373.                         msg << managerString << ", are you sure?";
  4374.                     }
  4375.                     else
  4376.                         msg << "Your character is not a staff member, please tell me another name!";
  4377.                 }
  4378.             }
  4379.             else if(checkText(text, "no") && talkState[2])
  4380.             {
  4381.                 talkState[1] = talkState[2] = false;
  4382.                 msg << "What else would you like to name your character?";
  4383.             }
  4384.             else if(checkText(text, "yes") && talkState[2])
  4385.             {
  4386.                 if(!IOLoginData::getInstance()->playerExists(managerString, true))
  4387.                 {
  4388.                     uint32_t tmp;
  4389.                     if(IOLoginData::getInstance()->getGuidByName(tmp, managerString2) &&
  4390.                         IOLoginData::getInstance()->changeName(tmp, managerString, managerString2) &&
  4391.                         IOBan::getInstance()->removePlayerBanishment(tmp, PLAYERBAN_LOCK))
  4392.                     {
  4393.                         if(House* house = Houses::getInstance()->getHouseByPlayerId(tmp))
  4394.                             house->updateDoorDescription(managerString);
  4395.  
  4396.                         talkState[1] = true;
  4397.                         talkState[2] = false;
  4398.                         msg << "Your character has been successfully renamed, you should now be able to login at it without any problems.";
  4399.                     }
  4400.                     else
  4401.                     {
  4402.                         talkState[1] = talkState[2] = false;
  4403.                         msg << "Failed to change your name, please try again.";
  4404.                     }
  4405.                 }
  4406.                 else
  4407.                 {
  4408.                     talkState[1] = talkState[2] = false;
  4409.                     msg << "A player with that name already exists, please choose another name.";
  4410.                 }
  4411.             }
  4412.             else
  4413.                 msg << "Sorry, but I can't understand you, please try to repeat that!";
  4414.  
  4415.             break;
  4416.         }
  4417.         case MANAGER_ACCOUNT:
  4418.         {
  4419.             Account account = IOLoginData::getInstance()->loadAccount(managerNumber);
  4420.             if(checkText(text, "cancel") || (checkText(text, "account") && !talkState[1]))
  4421.             {
  4422.                 talkState[1] = true;
  4423.                 for(int8_t i = 2; i <= 12; i++)
  4424.                     talkState[i] = false;
  4425.  
  4426.                 msg << "Do you want to change your 'password', request a 'recovery key', add a 'character', or 'delete' a character?";
  4427.             }
  4428.             else if(checkText(text, "delete") && talkState[1])
  4429.             {
  4430.                 talkState[1] = false;
  4431.                 talkState[2] = true;
  4432.                 msg << "Which character would you like to delete?";
  4433.             }
  4434.             else if(talkState[2])
  4435.             {
  4436.                 std::string tmp = text;
  4437.                 trimString(tmp);
  4438.                 if(!isValidName(tmp, false))
  4439.                     msg << "That name contains invalid characters, try to say your name again, you might have typed it wrong.";
  4440.                 else
  4441.                 {
  4442.                     talkState[2] = false;
  4443.                     talkState[3] = true;
  4444.                     managerString = tmp;
  4445.                     msg << "Do you really want to delete the character named " << managerString << "?";
  4446.                 }
  4447.             }
  4448.             else if(checkText(text, "yes") && talkState[3])
  4449.             {
  4450.                 switch(IOLoginData::getInstance()->deleteCharacter(managerNumber, managerString))
  4451.                 {
  4452.                     case DELETE_INTERNAL:
  4453.                         msg << "An error occured while deleting your character. Either the character does not belong to you or it doesn't exist.";
  4454.                         break;
  4455.  
  4456.                     case DELETE_SUCCESS:
  4457.                         msg << "Your character has been deleted.";
  4458.                         break;
  4459.  
  4460.                     case DELETE_HOUSE:
  4461.                         msg << "Your character owns a house. To make sure you really want to lose your house by deleting your character, you have to login and leave the house or pass it to someone else first.";
  4462.                         break;
  4463.  
  4464.                     case DELETE_LEADER:
  4465.                         msg << "Your character is the leader of a guild. You need to disband or pass the leadership someone else to delete your character.";
  4466.                         break;
  4467.  
  4468.                     case DELETE_ONLINE:
  4469.                         msg << "A character with that name is currently online, to delete a character it has to be offline.";
  4470.                         break;
  4471.                 }
  4472.  
  4473.                 talkState[1] = true;
  4474.                 for(int8_t i = 2; i <= 12; i++)
  4475.                     talkState[i] = false;
  4476.             }
  4477.             else if(checkText(text, "no") && talkState[3])
  4478.             {
  4479.                 talkState[1] = true;
  4480.                 talkState[3] = false;
  4481.                 msg << "Tell me what character you want to delete.";
  4482.             }
  4483.             else if(checkText(text, "password") && talkState[1])
  4484.             {
  4485.                 talkState[1] = false;
  4486.                 talkState[4] = true;
  4487.                 msg << "Tell me your new password please.";
  4488.             }
  4489.             else if(talkState[4])
  4490.             {
  4491.                 std::string tmp = text;
  4492.                 trimString(tmp);
  4493.                 if(tmp.length() < 6)
  4494.                     msg << "That password is too short, at least 6 digits are required. Please select a longer password.";
  4495.                 else if(!isValidPassword(tmp))
  4496.                     msg << "Your password contains invalid characters... please tell me another one.";
  4497.                 else
  4498.                 {
  4499.                     talkState[4] = false;
  4500.                     talkState[5] = true;
  4501.                     managerString = tmp;
  4502.                     msg << "Should '" << managerString << "' be your new password?";
  4503.                 }
  4504.             }
  4505.             else if(checkText(text, "yes") && talkState[5])
  4506.             {
  4507.                 talkState[1] = true;
  4508.                 for(int8_t i = 2; i <= 12; i++)
  4509.                     talkState[i] = false;
  4510.  
  4511.                 IOLoginData::getInstance()->setPassword(managerNumber, managerString);
  4512.                 msg << "Your password has been changed.";
  4513.             }
  4514.             else if(checkText(text, "no") && talkState[5])
  4515.             {
  4516.                 talkState[1] = true;
  4517.                 for(int8_t i = 2; i <= 12; i++)
  4518.                     talkState[i] = false;
  4519.  
  4520.                 msg << "Then not.";
  4521.             }
  4522.             else if(checkText(text, "character") && talkState[1])
  4523.             {
  4524.                 if(account.charList.size() <= 15)
  4525.                 {
  4526.                     talkState[1] = false;
  4527.                     talkState[6] = true;
  4528.                     msg << "What would you like as your character name?";
  4529.                 }
  4530.                 else
  4531.                 {
  4532.                     talkState[1] = true;
  4533.                     for(int8_t i = 2; i <= 12; i++)
  4534.                         talkState[i] = false;
  4535.  
  4536.                     msg << "Your account reach the limit of 15 players, you can 'delete' a character if you want to create a new one.";
  4537.                 }
  4538.             }
  4539.             else if(talkState[6])
  4540.             {
  4541.                 managerString = text;
  4542.                 trimString(managerString);
  4543.                 if(managerString.length() < 4)
  4544.                     msg << "Your name you want is too short, please select a longer name.";
  4545.                 else if(managerString.length() > 20)
  4546.                     msg << "The name you want is too long, please select a shorter name.";
  4547.                 else if(!isValidName(managerString))
  4548.                     msg << "That name seems to contain invalid symbols, please choose another name.";
  4549.                 else if(IOLoginData::getInstance()->playerExists(managerString, true))
  4550.                     msg << "A player with that name already exists, please choose another name.";
  4551.                 else
  4552.                 {
  4553.                     std::string tmp = asLowerCaseString(managerString);
  4554.                     if(tmp.substr(0, 4) != "god " && tmp.substr(0, 3) != "cm " && tmp.substr(0, 3) != "gm ")
  4555.                     {
  4556.                         talkState[6] = false;
  4557.                         talkState[7] = true;
  4558.                         msg << managerString << ", are you sure?";
  4559.                     }
  4560.                     else
  4561.                         msg << "Your character is not a staff member, please tell me another name!";
  4562.                 }
  4563.             }
  4564.             else if(checkText(text, "no") && talkState[7])
  4565.             {
  4566.                 talkState[6] = true;
  4567.                 talkState[7] = false;
  4568.                 msg << "What else would you like to name your character?";
  4569.             }
  4570.             else if(checkText(text, "yes") && talkState[7])
  4571.             {
  4572.                 talkState[7] = false;
  4573.                 talkState[8] = true;
  4574.                 msg << "Should your character be a 'male' or a 'female'.";
  4575.             }
  4576.             else if(talkState[8] && (checkText(text, "female") || checkText(text, "male")))
  4577.             {
  4578.                 talkState[8] = false;
  4579.                 talkState[9] = true;
  4580.                 if(checkText(text, "female"))
  4581.                 {
  4582.                     msg << "A female, are you sure?";
  4583.                     managerSex = PLAYERSEX_FEMALE;
  4584.                 }
  4585.                 else
  4586.                 {
  4587.                     msg << "A male, are you sure?";
  4588.                     managerSex = PLAYERSEX_MALE;
  4589.                 }
  4590.             }
  4591.             else if(checkText(text, "no") && talkState[9])
  4592.             {
  4593.                 talkState[8] = true;
  4594.                 talkState[9] = false;
  4595.                 msg << "Tell me... would you like to be a 'male' or a 'female'?";
  4596.             }
  4597.             else if(checkText(text, "yes") && talkState[9])
  4598.             {
  4599.                 if(g_config.getBool(ConfigManager::START_CHOOSEVOC))
  4600.                 {
  4601.                     talkState[9] = false;
  4602.                     talkState[11] = true;
  4603.  
  4604.                     bool firstPart = true;
  4605.                     for(VocationsMap::iterator it = Vocations::getInstance()->getFirstVocation(); it != Vocations::getInstance()->getLastVocation(); ++it)
  4606.                     {
  4607.                         if(it->first == it->second->getFromVocation() && it->first != 0)
  4608.                         {
  4609.                             if(firstPart)
  4610.                             {
  4611.                                 msg << "What do you want to be... " << it->second->getDescription();
  4612.                                 firstPart = false;
  4613.                             }
  4614.                             else if(it->first - 1 != 0)
  4615.                                 msg << ", " << it->second->getDescription();
  4616.                             else
  4617.                                 msg << " or " << it->second->getDescription() << ".";
  4618.                         }
  4619.                     }
  4620.                 }
  4621.                 else if(!IOLoginData::getInstance()->playerExists(managerString, true))
  4622.                 {
  4623.                     talkState[1] = true;
  4624.                     for(int8_t i = 2; i <= 12; i++)
  4625.                         talkState[i] = false;
  4626.  
  4627.                     if(IOLoginData::getInstance()->createCharacter(managerNumber, managerString, managerNumber2, (uint16_t)managerSex))
  4628.                         msg << "Your character has been created.";
  4629.                     else
  4630.                         msg << "Your character couldn't be created, please try again.";
  4631.                 }
  4632.                 else
  4633.                 {
  4634.                     talkState[6] = true;
  4635.                     talkState[9] = false;
  4636.                     msg << "A player with that name already exists, please choose another name.";
  4637.                 }
  4638.             }
  4639.             else if(talkState[11])
  4640.             {
  4641.                 for(VocationsMap::iterator it = Vocations::getInstance()->getFirstVocation(); it != Vocations::getInstance()->getLastVocation(); ++it)
  4642.                 {
  4643.                     std::string tmp = asLowerCaseString(it->second->getName());
  4644.                     if(checkText(text, tmp) && it != Vocations::getInstance()->getLastVocation() && it->first == it->second->getFromVocation() && it->first != 0)
  4645.                     {
  4646.                         msg << "So you would like to be " << it->second->getDescription() << "... are you sure?";
  4647.                         managerNumber2 = it->first;
  4648.                         talkState[11] = false;
  4649.                         talkState[12] = true;
  4650.                     }
  4651.                 }
  4652.  
  4653.                 if(msg.str().length() == 17)
  4654.                     msg << "I don't understand what vocation you would like to be... could you please repeat it?";
  4655.             }
  4656.             else if(checkText(text, "yes") && talkState[12])
  4657.             {
  4658.                 if(!IOLoginData::getInstance()->playerExists(managerString, true))
  4659.                 {
  4660.                     talkState[1] = true;
  4661.                     for(int8_t i = 2; i <= 12; i++)
  4662.                         talkState[i] = false;
  4663.  
  4664.                     if(IOLoginData::getInstance()->createCharacter(managerNumber, managerString, managerNumber2, (uint16_t)managerSex))
  4665.                         msg << "Your character has been created.";
  4666.                     else
  4667.                         msg << "Your character couldn't be created, please try again.";
  4668.                 }
  4669.                 else
  4670.                 {
  4671.                     talkState[6] = true;
  4672.                     talkState[9] = false;
  4673.                     msg << "A player with that name already exists, please choose another name.";
  4674.                 }
  4675.             }
  4676.             else if(checkText(text, "no") && talkState[12])
  4677.             {
  4678.                 talkState[11] = true;
  4679.                 talkState[12] = false;
  4680.                 msg << "No? Then what would you like to be?";
  4681.             }
  4682.             else if(checkText(text, "recovery key") && talkState[1])
  4683.             {
  4684.                 talkState[1] = false;
  4685.                 talkState[10] = true;
  4686.                 msg << "Would you like a recovery key?";
  4687.             }
  4688.             else if(checkText(text, "yes") && talkState[10])
  4689.             {
  4690.                 if(account.recoveryKey != "0")
  4691.                     msg << "Sorry, you already have a recovery key, for security reasons I may not give you a new one.";
  4692.                 else
  4693.                 {
  4694.                     managerString = generateRecoveryKey(4, 4);
  4695.                     IOLoginData::getInstance()->setRecoveryKey(managerNumber, managerString);
  4696.                     msg << "Your recovery key is: " << managerString << ".";
  4697.                 }
  4698.  
  4699.                 talkState[1] = true;
  4700.                 for(int8_t i = 2; i <= 12; i++)
  4701.                     talkState[i] = false;
  4702.             }
  4703.             else if(checkText(text, "no") && talkState[10])
  4704.             {
  4705.                 msg << "Then not.";
  4706.                 talkState[1] = true;
  4707.                 for(int8_t i = 2; i <= 12; i++)
  4708.                     talkState[i] = false;
  4709.             }
  4710.             else
  4711.                 msg << "Please read the latest message that I have specified, I don't understand the current requested action.";
  4712.  
  4713.             break;
  4714.         }
  4715.         case MANAGER_NEW:
  4716.         {
  4717.             if(checkText(text, "account") && !talkState[1])
  4718.             {
  4719.                 msg << "What would you like your password to be?";
  4720.                 talkState[1] = true;
  4721.                 talkState[2] = true;
  4722.             }
  4723.             else if(talkState[2])
  4724.             {
  4725.                 std::string tmp = text;
  4726.                 trimString(tmp);
  4727.                 if(tmp.length() < 6)
  4728.                     msg << "That password is too short, at least 6 digits are required. Please select a longer password.";
  4729.                 else if(!isValidPassword(tmp))
  4730.                     msg << "Your password contains invalid characters... please tell me another one.";
  4731.                 else
  4732.                 {
  4733.                     talkState[3] = true;
  4734.                     talkState[2] = false;
  4735.                     managerString = tmp;
  4736.                     msg << managerString << " is it? 'yes' or 'no'?";
  4737.                 }
  4738.             }
  4739.             else if(checkText(text, "yes") && talkState[3])
  4740.             {
  4741.                 if(g_config.getBool(ConfigManager::GENERATE_ACCOUNT_NUMBER))
  4742.                 {
  4743.                     do
  4744.                         sprintf(managerChar, "%d%d%d%d%d%d%d", random_range(2, 9), random_range(2, 9), random_range(2, 9), random_range(2, 9), random_range(2, 9), random_range(2, 9), random_range(2, 9));
  4745.                     while(IOLoginData::getInstance()->accountNameExists(managerChar));
  4746.  
  4747.                     uint32_t id = (uint32_t)IOLoginData::getInstance()->createAccount(managerChar, managerString);
  4748.                     if(id)
  4749.                     {
  4750.                         accountManager = MANAGER_ACCOUNT;
  4751.                         managerNumber = id;
  4752.  
  4753.                         noSwap = talkState[1] = false;
  4754.                         msg << "Your account has been created, you may manage it now, but remember your account name: '"
  4755.                             << managerChar << "' and password: '" << managerString
  4756.                             << "'! If the account name is too hard to remember, please note it somewhere.";
  4757.                     }
  4758.                     else
  4759.                         msg << "Your account could not be created, please try again.";
  4760.  
  4761.                     for(int8_t i = 2; i <= 5; i++)
  4762.                         talkState[i] = false;
  4763.                 }
  4764.                 else
  4765.                 {
  4766.                     msg << "What would you like your account name to be?";
  4767.                     talkState[3] = false;
  4768.                     talkState[4] = true;
  4769.                 }
  4770.             }
  4771.             else if(checkText(text, "no") && talkState[3])
  4772.             {
  4773.                 talkState[2] = true;
  4774.                 talkState[3] = false;
  4775.                 msg << "What would you like your password to be then?";
  4776.             }
  4777.             else if(talkState[4])
  4778.             {
  4779.                 std::string tmp = text;
  4780.                 trimString(tmp);
  4781.                 if(tmp.length() < 3)
  4782.                     msg << "That account name is too short, at least 3 digits are required. Please select a longer account name.";
  4783.                 else if(tmp.length() > 25)
  4784.                     msg << "That account name is too long, not more than 25 digits are required. Please select a shorter account name.";
  4785.                 else if(!isValidAccountName(tmp))
  4786.                     msg << "Your account name contains invalid characters, please choose another one.";
  4787.                 else if(asLowerCaseString(tmp) == asLowerCaseString(managerString))
  4788.                     msg << "Your account name cannot be same as password, please choose another one.";
  4789.                 else
  4790.                 {
  4791.                     sprintf(managerChar, "%s", tmp.c_str());
  4792.                     msg << managerChar << ", are you sure?";
  4793.                     talkState[4] = false;
  4794.                     talkState[5] = true;
  4795.                 }
  4796.             }
  4797.             else if(checkText(text, "yes") && talkState[5])
  4798.             {
  4799.                 if(!IOLoginData::getInstance()->accountNameExists(managerChar))
  4800.                 {
  4801.                     uint32_t id = (uint32_t)IOLoginData::getInstance()->createAccount(managerChar, managerString);
  4802.                     if(id)
  4803.                     {
  4804.                         accountManager = MANAGER_ACCOUNT;
  4805.                         managerNumber = id;
  4806.  
  4807.                         noSwap = talkState[1] = false;
  4808.                         msg << "Your account has been created, you may manage it now, but remember your account name: '"
  4809.                             << managerChar << "' and password: '" << managerString << "'!";
  4810.                     }
  4811.                     else
  4812.                         msg << "Your account could not be created, please try again.";
  4813.  
  4814.                     for(int8_t i = 2; i <= 5; i++)
  4815.                         talkState[i] = false;
  4816.                 }
  4817.                 else
  4818.                 {
  4819.                     msg << "An account with that name already exists, please try another account name.";
  4820.                     talkState[4] = true;
  4821.                     talkState[5] = false;
  4822.                 }
  4823.             }
  4824.             else if(checkText(text, "no") && talkState[5])
  4825.             {
  4826.                 talkState[5] = false;
  4827.                 talkState[4] = true;
  4828.                 msg << "What else would you like as your account name?";
  4829.             }
  4830.             else if(checkText(text, "recover") && !talkState[6])
  4831.             {
  4832.                 talkState[6] = true;
  4833.                 talkState[7] = true;
  4834.                 msg << "What was your account name?";
  4835.             }
  4836.             else if(talkState[7])
  4837.             {
  4838.                 managerString = text;
  4839.                 if(IOLoginData::getInstance()->getAccountId(managerString, (uint32_t&)managerNumber))
  4840.                 {
  4841.                     talkState[7] = false;
  4842.                     talkState[8] = true;
  4843.                     msg << "What was your recovery key?";
  4844.                 }
  4845.                 else
  4846.                 {
  4847.                     msg << "Sorry, but account with such name doesn't exists.";
  4848.                     talkState[6] = talkState[7] = false;
  4849.                 }
  4850.             }
  4851.             else if(talkState[8])
  4852.             {
  4853.                 managerString2 = text;
  4854.                 if(IOLoginData::getInstance()->validRecoveryKey(managerNumber, managerString2) && managerString2 != "0")
  4855.                 {
  4856.                     sprintf(managerChar, "%s%d", g_config.getString(ConfigManager::SERVER_NAME).c_str(), random_range(100, 999));
  4857.                     IOLoginData::getInstance()->setPassword(managerNumber, managerChar);
  4858.                     msg << "Correct! Your new password is: " << managerChar << ".";
  4859.                 }
  4860.                 else
  4861.                     msg << "Sorry, but this key doesn't match to account you gave me.";
  4862.  
  4863.                 talkState[7] = talkState[8] = false;
  4864.             }
  4865.             else
  4866.                 msg << "Sorry, but I can't understand you, please try to repeat that.";
  4867.  
  4868.             break;
  4869.         }
  4870.         default:
  4871.             return;
  4872.             break;
  4873.     }
  4874.  
  4875.     sendTextMessage(MSG_STATUS_CONSOLE_BLUE, msg.str().c_str());
  4876.     if(!noSwap)
  4877.         sendTextMessage(MSG_STATUS_CONSOLE_ORANGE, "Hint: Type 'account' to manage your account and if you want to start over then type 'cancel'.");
  4878. }
  4879.  
  4880. bool Player::isGuildInvited(uint32_t guildId) const
  4881. {
  4882.     for(InvitedToGuildsList::const_iterator it = invitedToGuildsList.begin(); it != invitedToGuildsList.end(); ++it)
  4883.     {
  4884.         if((*it) == guildId)
  4885.             return true;
  4886.     }
  4887.  
  4888.     return false;
  4889. }
  4890.  
  4891. void Player::leaveGuild()
  4892. {
  4893.     sendClosePrivate(CHANNEL_GUILD);
  4894. #ifdef __WAR_SYSTEM__
  4895.     warMap.clear();
  4896.     g_game.updateCreatureEmblem(this);
  4897.  
  4898. #endif
  4899.     guildLevel = GUILDLEVEL_NONE;
  4900.     guildId = rankId = 0;
  4901.     guildName = rankName = guildNick = std::string();
  4902. }
  4903.  
  4904. bool Player::isPremium() const
  4905. {
  4906.     if(g_config.getBool(ConfigManager::FREE_PREMIUM) || hasFlag(PlayerFlag_IsAlwaysPremium))
  4907.         return true;
  4908.  
  4909.     return premiumDays;
  4910. }
  4911.  
  4912. bool Player::setGuildLevel(GuildLevel_t newLevel, uint32_t rank/* = 0*/)
  4913. {
  4914.     std::string name;
  4915.     if(!IOGuild::getInstance()->getRankEx(rank, name, guildId, newLevel))
  4916.         return false;
  4917.  
  4918.     guildLevel = newLevel;
  4919.     rankName = name;
  4920.     rankId = rank;
  4921.     return true;
  4922. }
  4923.  
  4924. void Player::setGroupId(int32_t newId)
  4925. {
  4926.     if(Group* tmp = Groups::getInstance()->getGroup(newId))
  4927.     {
  4928.         groupId = newId;
  4929.         group = tmp;
  4930.     }
  4931. }
  4932.  
  4933. void Player::setGroup(Group* newGroup)
  4934. {
  4935.     if(!newGroup)
  4936.         return;
  4937.  
  4938.     group = newGroup;
  4939.     groupId = group->getId();
  4940. }
  4941.  
  4942. PartyShields_t Player::getPartyShield(const Creature* creature) const
  4943. {
  4944.     const Player* player = creature->getPlayer();
  4945.     if(!player)
  4946.         return Creature::getPartyShield(creature);
  4947.  
  4948.     if(Party* party = getParty())
  4949.     {
  4950.         if(party->getLeader() == player)
  4951.         {
  4952.             if(!party->isSharedExperienceActive())
  4953.                 return SHIELD_YELLOW;
  4954.  
  4955.             if(party->isSharedExperienceEnabled())
  4956.                 return SHIELD_YELLOW_SHAREDEXP;
  4957.  
  4958.             if(party->canUseSharedExperience(player))
  4959.                 return SHIELD_YELLOW_NOSHAREDEXP;
  4960.  
  4961.             return SHIELD_YELLOW_NOSHAREDEXP_BLINK;
  4962.         }
  4963.  
  4964.         if(party->isPlayerMember(player))
  4965.         {
  4966.             if(!party->isSharedExperienceActive())
  4967.                 return SHIELD_BLUE;
  4968.  
  4969.             if(party->isSharedExperienceEnabled())
  4970.                 return SHIELD_BLUE_SHAREDEXP;
  4971.  
  4972.             if(party->canUseSharedExperience(player))
  4973.                 return SHIELD_BLUE_NOSHAREDEXP;
  4974.  
  4975.             return SHIELD_BLUE_NOSHAREDEXP_BLINK;
  4976.         }
  4977.  
  4978.         if(isInviting(player))
  4979.             return SHIELD_WHITEBLUE;
  4980.     }
  4981.  
  4982.     if(player->isInviting(this))
  4983.         return SHIELD_WHITEYELLOW;
  4984.  
  4985.     return SHIELD_NONE;
  4986. }
  4987.  
  4988. bool Player::isInviting(const Player* player) const
  4989. {
  4990.     if(!player || player->isRemoved() || !party || party->getLeader() != this)
  4991.         return false;
  4992.  
  4993.     return party->isPlayerInvited(player);
  4994. }
  4995.  
  4996. bool Player::isPartner(const Player* player) const
  4997. {
  4998.     return player && player->getParty() && player->getParty() == party;
  4999. }
  5000.  
  5001. bool Player::getHideHealth() const
  5002. {
  5003.     if(hasFlag(PlayerFlag_HideHealth))
  5004.         return true;
  5005.  
  5006.     return hideHealth;
  5007. }
  5008.  
  5009. void Player::sendPlayerIcons(Player* player)
  5010. {
  5011.     sendCreatureShield(player);
  5012.     sendCreatureSkull(player);
  5013. }
  5014.  
  5015. bool Player::addPartyInvitation(Party* party)
  5016. {
  5017.     if(!party)
  5018.         return false;
  5019.  
  5020.     PartyList::iterator it = std::find(invitePartyList.begin(), invitePartyList.end(), party);
  5021.     if(it != invitePartyList.end())
  5022.         return false;
  5023.  
  5024.     invitePartyList.push_back(party);
  5025.     return true;
  5026. }
  5027.  
  5028. bool Player::removePartyInvitation(Party* party)
  5029. {
  5030.     if(!party)
  5031.         return false;
  5032.  
  5033.     PartyList::iterator it = std::find(invitePartyList.begin(), invitePartyList.end(), party);
  5034.     if(it != invitePartyList.end())
  5035.     {
  5036.         invitePartyList.erase(it);
  5037.         return true;
  5038.     }
  5039.     return false;
  5040. }
  5041.  
  5042. void Player::clearPartyInvitations()
  5043. {
  5044.     if(invitePartyList.empty())
  5045.         return;
  5046.  
  5047.     PartyList list;
  5048.     for(PartyList::iterator it = invitePartyList.begin(); it != invitePartyList.end(); ++it)
  5049.         list.push_back(*it);
  5050.  
  5051.     invitePartyList.clear();
  5052.     for(PartyList::iterator it = list.begin(); it != list.end(); ++it)
  5053.         (*it)->removeInvite(this);
  5054. }
  5055.  
  5056. void Player::increaseCombatValues(int32_t& min, int32_t& max, bool useCharges, bool countWeapon)
  5057. {
  5058.     if(min > 0)
  5059.         min = (int32_t)(min * vocation->getMultiplier(MULTIPLIER_HEALING));
  5060.     else
  5061.         min = (int32_t)(min * vocation->getMultiplier(MULTIPLIER_MAGIC));
  5062.  
  5063.     if(max > 0)
  5064.         max = (int32_t)(max * vocation->getMultiplier(MULTIPLIER_HEALING));
  5065.     else
  5066.         max = (int32_t)(max * vocation->getMultiplier(MULTIPLIER_MAGIC));
  5067.  
  5068.     Item* item = NULL;
  5069.     int32_t minValue = 0, maxValue = 0, i = SLOT_FIRST;
  5070.     for(; i < SLOT_LAST; ++i)
  5071.     {
  5072.         if(!(item = getInventoryItem((slots_t)i)) || item->isRemoved() ||
  5073.             (g_moveEvents->hasEquipEvent(item) && !isItemAbilityEnabled((slots_t)i)))
  5074.             continue;
  5075.  
  5076.         const ItemType& it = Item::items[item->getID()];
  5077.         if(min > 0)
  5078.         {
  5079.             minValue += it.abilities.increment[HEALING_VALUE];
  5080.             if(it.abilities.increment[HEALING_PERCENT])
  5081.                 min = (int32_t)std::ceil((double)(min * it.abilities.increment[HEALING_PERCENT]) / 100.);
  5082.         }
  5083.         else
  5084.         {
  5085.             minValue -= it.abilities.increment[MAGIC_VALUE];
  5086.             if(it.abilities.increment[MAGIC_PERCENT])
  5087.                 min = (int32_t)std::ceil((double)(min * it.abilities.increment[MAGIC_PERCENT]) / 100.);
  5088.         }
  5089.  
  5090.         if(max > 0)
  5091.         {
  5092.             maxValue += it.abilities.increment[HEALING_VALUE];
  5093.             if(it.abilities.increment[HEALING_PERCENT])
  5094.                 max = (int32_t)std::ceil((double)(max * it.abilities.increment[HEALING_PERCENT]) / 100.);
  5095.         }
  5096.         else
  5097.         {
  5098.             maxValue -= it.abilities.increment[MAGIC_VALUE];
  5099.             if(it.abilities.increment[MAGIC_PERCENT])
  5100.                 max = (int32_t)std::ceil((double)(max * it.abilities.increment[MAGIC_PERCENT]) / 100.);
  5101.         }
  5102.  
  5103.         bool removeCharges = false;
  5104.         for(int32_t j = INCREMENT_FIRST; j <= INCREMENT_LAST; ++j)
  5105.         {
  5106.             if(!it.abilities.increment[(Increment_t)j])
  5107.                 continue;
  5108.  
  5109.             removeCharges = true;
  5110.             break;
  5111.         }
  5112.  
  5113.         if(useCharges && removeCharges && (countWeapon || item != weapon) && item->hasCharges())
  5114.             g_game.transformItem(item, item->getID(), std::max((int32_t)0, (int32_t)item->getCharges() - 1));
  5115.     }
  5116.  
  5117.     min += minValue;
  5118.     max += maxValue;
  5119. }
  5120.  
  5121. bool Player::transferMoneyTo(const std::string& name, uint64_t amount)
  5122. {
  5123.     if(!g_config.getBool(ConfigManager::BANK_SYSTEM) || amount > balance)
  5124.         return false;
  5125.  
  5126.     Player* target = g_game.getPlayerByNameEx(name);
  5127.     if(!target)
  5128.         return false;
  5129.  
  5130.     balance -= amount;
  5131.     target->balance += amount;
  5132.     if(target->isVirtual())
  5133.     {
  5134.         IOLoginData::getInstance()->savePlayer(target);
  5135.         delete target;
  5136.     }
  5137.  
  5138.     return true;
  5139. }
  5140.  
  5141. void Player::sendCritical() const
  5142. {
  5143.     if(g_config.getBool(ConfigManager::DISPLAY_CRITICAL_HIT))
  5144.         g_game.addAnimatedText(getPosition(), COLOR_DARKRED, "CRITICAL!");
  5145. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement