Advertisement
Guest User

Untitled

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