Oskar1121

Untitled

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