Advertisement
Guest User

Untitled

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