Guest User

Player.cpp

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