Advertisement
Guest User

player.cpp

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