Guest User

Untitled

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