Guest User

Untitled

a guest
Jan 19th, 2013
659
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 467.84 KB | None | 0 0
  1. /*
  2. * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
  3. * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License as published by the
  7. * Free Software Foundation; either version 2 of the License, or (at your
  8. * option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful, but WITHOUT
  11. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13. * more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18.  
  19. #include "Common.h"
  20. #include "Language.h"
  21. #include "DatabaseEnv.h"
  22. #include "Log.h"
  23. #include "Opcodes.h"
  24. #include "SpellMgr.h"
  25. #include "World.h"
  26. #include "WorldPacket.h"
  27. #include "WorldSession.h"
  28. #include "UpdateMask.h"
  29. #include "Player.h"
  30. #include "Vehicle.h"
  31. #include "SkillDiscovery.h"
  32. #include "QuestDef.h"
  33. #include "GossipDef.h"
  34. #include "UpdateData.h"
  35. #include "Channel.h"
  36. #include "ChannelMgr.h"
  37. #include "MapManager.h"
  38. #include "MapInstanced.h"
  39. #include "InstanceSaveMgr.h"
  40. #include "GridNotifiers.h"
  41. #include "GridNotifiersImpl.h"
  42. #include "CellImpl.h"
  43. #include "ObjectMgr.h"
  44. #include "ArenaTeamMgr.h"
  45. #include "GuildMgr.h"
  46. #include "GroupMgr.h"
  47. #include "ObjectAccessor.h"
  48. #include "CreatureAI.h"
  49. #include "Formulas.h"
  50. #include "Group.h"
  51. #include "Guild.h"
  52. #include "Pet.h"
  53. #include "Util.h"
  54. #include "Transport.h"
  55. #include "Weather.h"
  56. #include "Battleground.h"
  57. #include "BattlegroundAV.h"
  58. #include "BattlegroundMgr.h"
  59. #include "OutdoorPvP.h"
  60. #include "OutdoorPvPMgr.h"
  61. #include "ArenaTeam.h"
  62. #include "Chat.h"
  63. #include "Spell.h"
  64. #include "SocialMgr.h"
  65. #include "GameEventMgr.h"
  66. #include "AchievementMgr.h"
  67. #include "SpellAuras.h"
  68. #include "SpellAuraEffects.h"
  69. #include "ConditionMgr.h"
  70. #include "DisableMgr.h"
  71. #include "WeatherMgr.h"
  72. #include "LFGMgr.h"
  73. #include "CharacterDatabaseCleaner.h"
  74. #include "InstanceScript.h"
  75. #include <cmath>
  76. #include "AccountMgr.h"
  77. #include "TransmogEngine.h"
  78.  
  79. #define ZONE_UPDATE_INTERVAL (1*IN_MILLISECONDS)
  80.  
  81. #define PLAYER_SKILL_INDEX(x) (PLAYER_SKILL_INFO_1_1 + ((x)*3))
  82. #define PLAYER_SKILL_VALUE_INDEX(x) (PLAYER_SKILL_INDEX(x)+1)
  83. #define PLAYER_SKILL_BONUS_INDEX(x) (PLAYER_SKILL_INDEX(x)+2)
  84.  
  85. #define SKILL_VALUE(x) PAIR32_LOPART(x)
  86. #define SKILL_MAX(x) PAIR32_HIPART(x)
  87. #define MAKE_SKILL_VALUE(v, m) MAKE_PAIR32(v, m)
  88.  
  89. #define SKILL_TEMP_BONUS(x) int16(PAIR32_LOPART(x))
  90. #define SKILL_PERM_BONUS(x) int16(PAIR32_HIPART(x))
  91. #define MAKE_SKILL_BONUS(t, p) MAKE_PAIR32(t, p)
  92.  
  93. enum CharacterFlags
  94. {
  95. CHARACTER_FLAG_NONE = 0x00000000,
  96. CHARACTER_FLAG_UNK1 = 0x00000001,
  97. CHARACTER_FLAG_UNK2 = 0x00000002,
  98. CHARACTER_LOCKED_FOR_TRANSFER = 0x00000004,
  99. CHARACTER_FLAG_UNK4 = 0x00000008,
  100. CHARACTER_FLAG_UNK5 = 0x00000010,
  101. CHARACTER_FLAG_UNK6 = 0x00000020,
  102. CHARACTER_FLAG_UNK7 = 0x00000040,
  103. CHARACTER_FLAG_UNK8 = 0x00000080,
  104. CHARACTER_FLAG_UNK9 = 0x00000100,
  105. CHARACTER_FLAG_UNK10 = 0x00000200,
  106. CHARACTER_FLAG_HIDE_HELM = 0x00000400,
  107. CHARACTER_FLAG_HIDE_CLOAK = 0x00000800,
  108. CHARACTER_FLAG_UNK13 = 0x00001000,
  109. CHARACTER_FLAG_GHOST = 0x00002000,
  110. CHARACTER_FLAG_RENAME = 0x00004000,
  111. CHARACTER_FLAG_UNK16 = 0x00008000,
  112. CHARACTER_FLAG_UNK17 = 0x00010000,
  113. CHARACTER_FLAG_UNK18 = 0x00020000,
  114. CHARACTER_FLAG_UNK19 = 0x00040000,
  115. CHARACTER_FLAG_UNK20 = 0x00080000,
  116. CHARACTER_FLAG_UNK21 = 0x00100000,
  117. CHARACTER_FLAG_UNK22 = 0x00200000,
  118. CHARACTER_FLAG_UNK23 = 0x00400000,
  119. CHARACTER_FLAG_UNK24 = 0x00800000,
  120. CHARACTER_FLAG_LOCKED_BY_BILLING = 0x01000000,
  121. CHARACTER_FLAG_DECLINED = 0x02000000,
  122. CHARACTER_FLAG_UNK27 = 0x04000000,
  123. CHARACTER_FLAG_UNK28 = 0x08000000,
  124. CHARACTER_FLAG_UNK29 = 0x10000000,
  125. CHARACTER_FLAG_UNK30 = 0x20000000,
  126. CHARACTER_FLAG_UNK31 = 0x40000000,
  127. CHARACTER_FLAG_UNK32 = 0x80000000
  128. };
  129.  
  130. enum CharacterCustomizeFlags
  131. {
  132. CHAR_CUSTOMIZE_FLAG_NONE = 0x00000000,
  133. CHAR_CUSTOMIZE_FLAG_CUSTOMIZE = 0x00000001, // name, gender, etc...
  134. CHAR_CUSTOMIZE_FLAG_FACTION = 0x00010000, // name, gender, faction, etc...
  135. CHAR_CUSTOMIZE_FLAG_RACE = 0x00100000 // name, gender, race, etc...
  136. };
  137.  
  138. // corpse reclaim times
  139. #define DEATH_EXPIRE_STEP (5*MINUTE)
  140. #define MAX_DEATH_COUNT 3
  141.  
  142. static uint32 copseReclaimDelay[MAX_DEATH_COUNT] = { 30, 60, 120 };
  143.  
  144. // == PlayerTaxi ================================================
  145.  
  146. PlayerTaxi::PlayerTaxi()
  147. {
  148. memset(m_taximask, 0, sizeof(m_taximask));
  149. }
  150.  
  151. void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level)
  152. {
  153. // class specific initial known nodes
  154. switch (chrClass)
  155. {
  156. case CLASS_DEATH_KNIGHT:
  157. {
  158. for (uint8 i = 0; i < TaxiMaskSize; ++i)
  159. m_taximask[i] |= sOldContinentsNodesMask[i];
  160. break;
  161. }
  162. }
  163.  
  164. // race specific initial known nodes: capital and taxi hub masks
  165. switch (race)
  166. {
  167. case RACE_HUMAN: SetTaximaskNode(2); break; // Human
  168. case RACE_ORC: SetTaximaskNode(23); break; // Orc
  169. case RACE_DWARF: SetTaximaskNode(6); break; // Dwarf
  170. case RACE_NIGHTELF: SetTaximaskNode(26);
  171. SetTaximaskNode(27); break; // Night Elf
  172. case RACE_UNDEAD_PLAYER: SetTaximaskNode(11); break;// Undead
  173. case RACE_TAUREN: SetTaximaskNode(22); break; // Tauren
  174. case RACE_GNOME: SetTaximaskNode(6); break; // Gnome
  175. case RACE_TROLL: SetTaximaskNode(23); break; // Troll
  176. case RACE_BLOODELF: SetTaximaskNode(82); break; // Blood Elf
  177. case RACE_DRAENEI: SetTaximaskNode(94); break; // Draenei
  178. }
  179.  
  180. // new continent starting masks (It will be accessible only at new map)
  181. switch (Player::TeamForRace(race))
  182. {
  183. case ALLIANCE: SetTaximaskNode(100); break;
  184. case HORDE: SetTaximaskNode(99); break;
  185. }
  186. // level dependent taxi hubs
  187. if (level >= 68)
  188. SetTaximaskNode(213); //Shattered Sun Staging Area
  189. }
  190.  
  191. void PlayerTaxi::LoadTaxiMask(const char* data)
  192. {
  193. Tokens tokens(data, ' ');
  194.  
  195. uint8 index;
  196. Tokens::iterator iter;
  197. for (iter = tokens.begin(), index = 0;
  198. (index < TaxiMaskSize) && (iter != tokens.end()); ++iter, ++index)
  199. {
  200. // load and set bits only for existed taxi nodes
  201. m_taximask[index] = sTaxiNodesMask[index] & uint32(atol(*iter));
  202. }
  203. }
  204.  
  205. void PlayerTaxi::AppendTaximaskTo(ByteBuffer& data, bool all)
  206. {
  207. if (all)
  208. {
  209. for (uint8 i=0; i<TaxiMaskSize; i++)
  210. data << uint32(sTaxiNodesMask[i]); // all existed nodes
  211. }
  212. else
  213. {
  214. for (uint8 i=0; i<TaxiMaskSize; i++)
  215. data << uint32(m_taximask[i]); // known nodes
  216. }
  217. }
  218.  
  219. bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, uint32 team)
  220. {
  221. ClearTaxiDestinations();
  222.  
  223. Tokens tokens(values, ' ');
  224.  
  225. for (Tokens::iterator iter = tokens.begin(); iter != tokens.end(); ++iter)
  226. {
  227. uint32 node = uint32(atol(*iter));
  228. AddTaxiDestination(node);
  229. }
  230.  
  231. if (m_TaxiDestinations.empty())
  232. return true;
  233.  
  234. // Check integrity
  235. if (m_TaxiDestinations.size() < 2)
  236. return false;
  237.  
  238. for (size_t i = 1; i < m_TaxiDestinations.size(); ++i)
  239. {
  240. uint32 cost;
  241. uint32 path;
  242. sObjectMgr->GetTaxiPath(m_TaxiDestinations[i-1], m_TaxiDestinations[i], path, cost);
  243. if (!path)
  244. return false;
  245. }
  246.  
  247. // can't load taxi path without mount set (quest taxi path?)
  248. if (!sObjectMgr->GetTaxiMountDisplayId(GetTaxiSource(), team, true))
  249. return false;
  250.  
  251. return true;
  252. }
  253.  
  254. std::string PlayerTaxi::SaveTaxiDestinationsToString()
  255. {
  256. if (m_TaxiDestinations.empty())
  257. return "";
  258.  
  259. std::ostringstream ss;
  260.  
  261. for (size_t i=0; i < m_TaxiDestinations.size(); ++i)
  262. ss << m_TaxiDestinations[i] << ' ';
  263.  
  264. return ss.str();
  265. }
  266.  
  267. uint32 PlayerTaxi::GetCurrentTaxiPath() const
  268. {
  269. if (m_TaxiDestinations.size() < 2)
  270. return 0;
  271.  
  272. uint32 path;
  273. uint32 cost;
  274.  
  275. sObjectMgr->GetTaxiPath(m_TaxiDestinations[0], m_TaxiDestinations[1], path, cost);
  276.  
  277. return path;
  278. }
  279.  
  280. std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi)
  281. {
  282. for (uint8 i = 0; i < TaxiMaskSize; ++i)
  283. ss << taxi.m_taximask[i] << ' ';
  284. return ss;
  285. }
  286.  
  287. //== TradeData =================================================
  288.  
  289. TradeData* TradeData::GetTraderData() const
  290. {
  291. return m_trader->GetTradeData();
  292. }
  293.  
  294. Item* TradeData::GetItem(TradeSlots slot) const
  295. {
  296. return m_items[slot] ? m_player->GetItemByGuid(m_items[slot]) : NULL;
  297. }
  298.  
  299. bool TradeData::HasItem(uint64 itemGuid) const
  300. {
  301. for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i)
  302. if (m_items[i] == itemGuid)
  303. return true;
  304.  
  305. return false;
  306. }
  307.  
  308. TradeSlots TradeData::GetTradeSlotForItem(uint64 itemGuid) const
  309. {
  310. for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i)
  311. if (m_items[i] == itemGuid)
  312. return TradeSlots(i);
  313.  
  314. return TRADE_SLOT_INVALID;
  315. }
  316.  
  317. Item* TradeData::GetSpellCastItem() const
  318. {
  319. return m_spellCastItem ? m_player->GetItemByGuid(m_spellCastItem) : NULL;
  320. }
  321.  
  322. void TradeData::SetItem(TradeSlots slot, Item* item)
  323. {
  324. uint64 itemGuid = item ? item->GetGUID() : 0;
  325.  
  326. if (m_items[slot] == itemGuid)
  327. return;
  328.  
  329. m_items[slot] = itemGuid;
  330.  
  331. SetAccepted(false);
  332. GetTraderData()->SetAccepted(false);
  333.  
  334. Update();
  335.  
  336. // need remove possible trader spell applied to changed item
  337. if (slot == TRADE_SLOT_NONTRADED)
  338. GetTraderData()->SetSpell(0);
  339.  
  340. // need remove possible player spell applied (possible move reagent)
  341. SetSpell(0);
  342. }
  343.  
  344. void TradeData::SetSpell(uint32 spell_id, Item* castItem /*= NULL*/)
  345. {
  346. uint64 itemGuid = castItem ? castItem->GetGUID() : 0;
  347.  
  348. if (m_spell == spell_id && m_spellCastItem == itemGuid)
  349. return;
  350.  
  351. m_spell = spell_id;
  352. m_spellCastItem = itemGuid;
  353.  
  354. SetAccepted(false);
  355. GetTraderData()->SetAccepted(false);
  356.  
  357. Update(true); // send spell info to item owner
  358. Update(false); // send spell info to caster self
  359. }
  360.  
  361. void TradeData::SetMoney(uint32 money)
  362. {
  363. if (m_money == money)
  364. return;
  365.  
  366. m_money = money;
  367.  
  368. SetAccepted(false);
  369. GetTraderData()->SetAccepted(false);
  370.  
  371. Update(true);
  372. }
  373.  
  374. void TradeData::Update(bool forTarget /*= true*/)
  375. {
  376. if (forTarget)
  377. m_trader->GetSession()->SendUpdateTrade(true); // player state for trader
  378. else
  379. m_player->GetSession()->SendUpdateTrade(false); // player state for player
  380. }
  381.  
  382. void TradeData::SetAccepted(bool state, bool crosssend /*= false*/)
  383. {
  384. m_accepted = state;
  385.  
  386. if (!state)
  387. {
  388. if (crosssend)
  389. m_trader->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
  390. else
  391. m_player->GetSession()->SendTradeStatus(TRADE_STATUS_BACK_TO_TRADE);
  392. }
  393. }
  394.  
  395. // == KillRewarder ====================================================
  396. // KillRewarder incapsulates logic of rewarding player upon kill with:
  397. // * XP;
  398. // * honor;
  399. // * reputation;
  400. // * kill credit (for quest objectives).
  401. // Rewarding is initiated in two cases: when player kills unit in Unit::Kill()
  402. // and on battlegrounds in Battleground::RewardXPAtKill().
  403. //
  404. // Rewarding algorithm is:
  405. // 1. Initialize internal variables to default values.
  406. // 2. In case when player is in group, initialize variables necessary for group calculations:
  407. // 2.1. _count - number of alive group members within reward distance;
  408. // 2.2. _sumLevel - sum of levels of alive group members within reward distance;
  409. // 2.3. _maxLevel - maximum level of alive group member within reward distance;
  410. // 2.4. _maxNotGrayMember - maximum level of alive group member within reward distance,
  411. // for whom victim is not gray;
  412. // 2.5. _isFullXP - flag identifying that for all group members victim is not gray,
  413. // so 100% XP will be rewarded (50% otherwise).
  414. // 3. Reward killer (and group, if necessary).
  415. // 3.1. If killer is in group, reward group.
  416. // 3.1.1. Initialize initial XP amount based on maximum level of group member,
  417. // for whom victim is not gray.
  418. // 3.1.2. Alter group rate if group is in raid (not for battlegrounds).
  419. // 3.1.3. Reward each group member (even dead) within reward distance (see 4. for more details).
  420. // 3.2. Reward single killer (not group case).
  421. // 3.2.1. Initialize initial XP amount based on killer's level.
  422. // 3.2.2. Reward killer (see 4. for more details).
  423. // 4. Reward player.
  424. // 4.1. Give honor (player must be alive and not on BG).
  425. // 4.2. Give XP.
  426. // 4.2.1. If player is in group, adjust XP:
  427. // * set to 0 if player's level is more than maximum level of not gray member;
  428. // * cut XP in half if _isFullXP is false.
  429. // 4.2.2. Apply auras modifying rewarded XP.
  430. // 4.2.3. Give XP to player.
  431. // 4.2.4. If player has pet, reward pet with XP (100% for single player, 50% for group case).
  432. // 4.3. Give reputation (player must not be on BG).
  433. // 4.4. Give kill credit (player must not be in group, or he must be alive or without corpse).
  434. // 5. Credit instance encounter.
  435. KillRewarder::KillRewarder(Player* killer, Unit* victim, bool isBattleGround) :
  436. // 1. Initialize internal variables to default values.
  437. _killer(killer), _victim(victim), _group(killer->GetGroup()),
  438. _groupRate(1.0f), _maxNotGrayMember(NULL), _count(0), _sumLevel(0), _xp(0),
  439. _isFullXP(false), _maxLevel(0), _isBattleGround(isBattleGround), _isPvP(false)
  440. {
  441. // mark the credit as pvp if victim is player
  442. if (victim->GetTypeId() == TYPEID_PLAYER)
  443. _isPvP = true;
  444. // or if its owned by player and its not a vehicle
  445. else if (IS_PLAYER_GUID(victim->GetCharmerOrOwnerGUID()))
  446. _isPvP = !victim->IsVehicle();
  447.  
  448. _InitGroupData();
  449. }
  450.  
  451. inline void KillRewarder::_InitGroupData()
  452. {
  453. if (_group)
  454. {
  455. // 2. In case when player is in group, initialize variables necessary for group calculations:
  456. for (GroupReference* itr = _group->GetFirstMember(); itr != NULL; itr = itr->next())
  457. if (Player* member = itr->getSource())
  458. if (member->isAlive() && member->IsAtGroupRewardDistance(_victim))
  459. {
  460. const uint8 lvl = member->getLevel();
  461. // 2.1. _count - number of alive group members within reward distance;
  462. ++_count;
  463. // 2.2. _sumLevel - sum of levels of alive group members within reward distance;
  464. _sumLevel += lvl;
  465. // 2.3. _maxLevel - maximum level of alive group member within reward distance;
  466. if (_maxLevel < lvl)
  467. _maxLevel = lvl;
  468. // 2.4. _maxNotGrayMember - maximum level of alive group member within reward distance,
  469. // for whom victim is not gray;
  470. uint32 grayLevel = Trinity::XP::GetGrayLevel(lvl);
  471. if (_victim->getLevel() > grayLevel && (!_maxNotGrayMember || _maxNotGrayMember->getLevel() < lvl))
  472. _maxNotGrayMember = member;
  473. }
  474. // 2.5. _isFullXP - flag identifying that for all group members victim is not gray,
  475. // so 100% XP will be rewarded (50% otherwise).
  476. _isFullXP = _maxNotGrayMember && (_maxLevel == _maxNotGrayMember->getLevel());
  477. }
  478. else
  479. _count = 1;
  480. }
  481.  
  482. inline void KillRewarder::_InitXP(Player* player)
  483. {
  484. // Get initial value of XP for kill.
  485. // XP is given:
  486. // * on battlegrounds;
  487. // * otherwise, not in PvP;
  488. // * not if killer is on vehicle.
  489. if (_isBattleGround || (!_isPvP && !_killer->GetVehicle()))
  490. _xp = Trinity::XP::Gain(player, _victim);
  491. }
  492.  
  493. inline void KillRewarder::_RewardHonor(Player* player)
  494. {
  495. // Rewarded player must be alive.
  496. if (player->isAlive())
  497. player->RewardHonor(_victim, _count, -1, true);
  498. }
  499.  
  500. inline void KillRewarder::_RewardXP(Player* player, float rate)
  501. {
  502. uint32 xp(_xp);
  503. if (_group)
  504. {
  505. // 4.2.1. If player is in group, adjust XP:
  506. // * set to 0 if player's level is more than maximum level of not gray member;
  507. // * cut XP in half if _isFullXP is false.
  508. if (_maxNotGrayMember && player->isAlive() &&
  509. _maxNotGrayMember->getLevel() >= player->getLevel())
  510. xp = _isFullXP ?
  511. uint32(xp * rate) : // Reward FULL XP if all group members are not gray.
  512. uint32(xp * rate / 2) + 1; // Reward only HALF of XP if some of group members are gray.
  513. else
  514. xp = 0;
  515. }
  516. if (xp)
  517. {
  518. // 4.2.2. Apply auras modifying rewarded XP (SPELL_AURA_MOD_XP_PCT).
  519. Unit::AuraEffectList const& auras = player->GetAuraEffectsByType(SPELL_AURA_MOD_XP_PCT);
  520. for (Unit::AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
  521. AddPctN(xp, (*i)->GetAmount());
  522.  
  523. // 4.2.3. Give XP to player.
  524. player->GiveXP(xp, _victim, _groupRate);
  525. if (Pet* pet = player->GetPet())
  526. // 4.2.4. If player has pet, reward pet with XP (100% for single player, 50% for group case).
  527. pet->GivePetXP(_group ? xp / 2 : xp);
  528. }
  529. }
  530.  
  531. inline void KillRewarder::_RewardReputation(Player* player, float rate)
  532. {
  533. // 4.3. Give reputation (player must not be on BG).
  534. // Even dead players and corpses are rewarded.
  535. player->RewardReputation(_victim, rate);
  536. }
  537.  
  538. inline void KillRewarder::_RewardKillCredit(Player* player)
  539. {
  540. // 4.4. Give kill credit (player must not be in group, or he must be alive or without corpse).
  541. if (!_group || player->isAlive() || !player->GetCorpse())
  542. if (_victim->GetTypeId() == TYPEID_UNIT)
  543. player->KilledMonster(_victim->ToCreature()->GetCreatureTemplate(), _victim->GetGUID());
  544. }
  545.  
  546. void KillRewarder::_RewardPlayer(Player* player, bool isDungeon)
  547. {
  548. // 4. Reward player.
  549. if (!_isBattleGround)
  550. {
  551. // 4.1. Give honor (player must be alive and not on BG).
  552. _RewardHonor(player);
  553. // 4.1.1 Send player killcredit for quests with PlayerSlain
  554. if (_victim->GetTypeId() == TYPEID_PLAYER)
  555. player->KilledPlayerCredit();
  556. }
  557. // Give XP only in PvE or in battlegrounds.
  558. // Give reputation and kill credit only in PvE.
  559. if (!_isPvP || _isBattleGround)
  560. {
  561. const float rate = _group ?
  562. _groupRate * float(player->getLevel()) / _sumLevel : // Group rate depends on summary level.
  563. 1.0f; // Personal rate is 100%.
  564. if (_xp)
  565. // 4.2. Give XP.
  566. _RewardXP(player, rate);
  567. if (!_isBattleGround)
  568. {
  569. // If killer is in dungeon then all members receive full reputation at kill.
  570. _RewardReputation(player, isDungeon ? 1.0f : rate);
  571. _RewardKillCredit(player);
  572. }
  573. }
  574. }
  575.  
  576. void KillRewarder::_RewardGroup()
  577. {
  578. if (_maxLevel)
  579. {
  580. if (_maxNotGrayMember)
  581. // 3.1.1. Initialize initial XP amount based on maximum level of group member,
  582. // for whom victim is not gray.
  583. _InitXP(_maxNotGrayMember);
  584. // To avoid unnecessary calculations and calls,
  585. // proceed only if XP is not ZERO or player is not on battleground
  586. // (battleground rewards only XP, that's why).
  587. if (!_isBattleGround || _xp)
  588. {
  589. const bool isDungeon = !_isPvP && sMapStore.LookupEntry(_killer->GetMapId())->IsDungeon();
  590. if (!_isBattleGround)
  591. {
  592. // 3.1.2. Alter group rate if group is in raid (not for battlegrounds).
  593. const bool isRaid = !_isPvP && sMapStore.LookupEntry(_killer->GetMapId())->IsRaid() && _group->isRaidGroup();
  594. _groupRate = Trinity::XP::xp_in_group_rate(_count, isRaid);
  595. }
  596.  
  597. // 3.1.3. Reward each group member (even dead or corpse) within reward distance.
  598. for (GroupReference* itr = _group->GetFirstMember(); itr != NULL; itr = itr->next())
  599. if (Player* member = itr->getSource())
  600. if (member->IsAtGroupRewardDistance(_victim))
  601. _RewardPlayer(member, isDungeon);
  602. }
  603. }
  604. }
  605.  
  606. void KillRewarder::Reward()
  607. {
  608. // 3. Reward killer (and group, if necessary).
  609. if (_group)
  610. // 3.1. If killer is in group, reward group.
  611. _RewardGroup();
  612. else
  613. {
  614. // 3.2. Reward single killer (not group case).
  615. // 3.2.1. Initialize initial XP amount based on killer's level.
  616. _InitXP(_killer);
  617. // To avoid unnecessary calculations and calls,
  618. // proceed only if XP is not ZERO or player is not on battleground
  619. // (battleground rewards only XP, that's why).
  620. if (!_isBattleGround || _xp)
  621. // 3.2.2. Reward killer.
  622. _RewardPlayer(_killer, false);
  623. }
  624.  
  625. // 5. Credit instance encounter.
  626. if (Creature* victim = _victim->ToCreature())
  627. if (victim->IsDungeonBoss())
  628. if (InstanceScript* instance = _victim->GetInstanceScript())
  629. instance->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, _victim->GetEntry(), _victim);
  630. }
  631.  
  632. // == Player ====================================================
  633.  
  634. // we can disable this warning for this since it only
  635. // causes undefined behavior when passed to the base class constructor
  636. #ifdef _MSC_VER
  637. #pragma warning(disable:4355)
  638. #endif
  639. Player::Player(WorldSession* session): Unit(true), m_achievementMgr(this), m_reputationMgr(this)
  640. {
  641. #ifdef _MSC_VER
  642. #pragma warning(default:4355)
  643. #endif
  644.  
  645. m_speakTime = 0;
  646. m_speakCount = 0;
  647.  
  648. m_objectType |= TYPEMASK_PLAYER;
  649. m_objectTypeId = TYPEID_PLAYER;
  650.  
  651. m_valuesCount = PLAYER_END;
  652.  
  653. m_session = session;
  654.  
  655. m_divider = 0;
  656.  
  657. m_ExtraFlags = 0;
  658.  
  659. m_spellModTakingSpell = NULL;
  660. //m_pad = 0;
  661.  
  662. // players always accept
  663. if (AccountMgr::IsPlayerAccount(GetSession()->GetSecurity()))
  664. SetAcceptWhispers(true);
  665.  
  666. m_curSelection = 0;
  667. m_lootGuid = 0;
  668.  
  669. m_comboTarget = 0;
  670. m_comboPoints = 0;
  671.  
  672. m_usedTalentCount = 0;
  673. m_questRewardTalentCount = 0;
  674.  
  675. m_regenTimer = 0;
  676. m_regenTimerCount = 0;
  677. m_weaponChangeTimer = 0;
  678.  
  679. m_zoneUpdateId = 0;
  680. m_zoneUpdateTimer = 0;
  681.  
  682. m_areaUpdateId = 0;
  683.  
  684. m_nextSave = sWorld->getIntConfig(CONFIG_INTERVAL_SAVE);
  685.  
  686. clearResurrectRequestData();
  687.  
  688. memset(m_items, 0, sizeof(Item*)*PLAYER_SLOTS_COUNT);
  689.  
  690. m_social = NULL;
  691.  
  692. // group is initialized in the reference constructor
  693. SetGroupInvite(NULL);
  694. m_groupUpdateMask = 0;
  695. m_auraRaidUpdateMask = 0;
  696. m_bPassOnGroupLoot = false;
  697.  
  698. duel = NULL;
  699.  
  700. m_GuildIdInvited = 0;
  701. m_ArenaTeamIdInvited = 0;
  702.  
  703. m_atLoginFlags = AT_LOGIN_NONE;
  704.  
  705. mSemaphoreTeleport_Near = false;
  706. mSemaphoreTeleport_Far = false;
  707.  
  708. m_DelayedOperations = 0;
  709. m_bCanDelayTeleport = false;
  710. m_bHasDelayedTeleport = false;
  711. m_teleport_options = 0;
  712.  
  713. m_trade = NULL;
  714.  
  715. m_cinematic = 0;
  716.  
  717. PlayerTalkClass = new PlayerMenu(GetSession());
  718. m_currentBuybackSlot = BUYBACK_SLOT_START;
  719.  
  720. m_DailyQuestChanged = false;
  721. m_lastDailyQuestTime = 0;
  722.  
  723. for (uint8 i=0; i<MAX_TIMERS; i++)
  724. m_MirrorTimer[i] = DISABLED_MIRROR_TIMER;
  725.  
  726. m_MirrorTimerFlags = UNDERWATER_NONE;
  727. m_MirrorTimerFlagsLast = UNDERWATER_NONE;
  728. m_isInWater = false;
  729. m_drunkTimer = 0;
  730. m_restTime = 0;
  731. m_deathTimer = 0;
  732. m_deathExpireTime = 0;
  733.  
  734. m_swingErrorMsg = 0;
  735.  
  736. for (uint8 j = 0; j < PLAYER_MAX_BATTLEGROUND_QUEUES; ++j)
  737. {
  738. m_bgBattlegroundQueueID[j].bgQueueTypeId = BATTLEGROUND_QUEUE_NONE;
  739. m_bgBattlegroundQueueID[j].invitedToInstance = 0;
  740. }
  741.  
  742. m_logintime = time(NULL);
  743. m_Last_tick = m_logintime;
  744. m_WeaponProficiency = 0;
  745. m_ArmorProficiency = 0;
  746. m_canParry = false;
  747. m_canBlock = false;
  748. m_canDualWield = false;
  749. m_canTitanGrip = false;
  750. m_ammoDPS = 0.0f;
  751.  
  752. m_temporaryUnsummonedPetNumber = 0;
  753. //cache for UNIT_CREATED_BY_SPELL to allow
  754. //returning reagents for temporarily removed pets
  755. //when dying/logging out
  756. m_oldpetspell = 0;
  757. m_lastpetnumber = 0;
  758.  
  759. ////////////////////Rest System/////////////////////
  760. time_inn_enter=0;
  761. inn_pos_mapid=0;
  762. inn_pos_x=0;
  763. inn_pos_y=0;
  764. inn_pos_z=0;
  765. m_rest_bonus=0;
  766. rest_type=REST_TYPE_NO;
  767. ////////////////////Rest System/////////////////////
  768.  
  769. m_mailsLoaded = false;
  770. m_mailsUpdated = false;
  771. unReadMails = 0;
  772. m_nextMailDelivereTime = 0;
  773.  
  774. m_resetTalentsCost = 0;
  775. m_resetTalentsTime = 0;
  776. m_itemUpdateQueueBlocked = false;
  777.  
  778. for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
  779. m_forced_speed_changes[i] = 0;
  780.  
  781. m_stableSlots = 0;
  782.  
  783. /////////////////// Instance System /////////////////////
  784.  
  785. m_HomebindTimer = 0;
  786. m_InstanceValid = true;
  787. m_dungeonDifficulty = DUNGEON_DIFFICULTY_NORMAL;
  788. m_raidDifficulty = RAID_DIFFICULTY_10MAN_NORMAL;
  789.  
  790. m_lastPotionId = 0;
  791.  
  792. m_activeSpec = 0;
  793. m_specsCount = 1;
  794.  
  795. for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i)
  796. {
  797. for (uint8 g = 0; g < MAX_GLYPH_SLOT_INDEX; ++g)
  798. m_Glyphs[i][g] = 0;
  799.  
  800. m_talents[i] = new PlayerTalentMap();
  801. }
  802.  
  803. for (uint8 i = 0; i < BASEMOD_END; ++i)
  804. {
  805. m_auraBaseMod[i][FLAT_MOD] = 0.0f;
  806. m_auraBaseMod[i][PCT_MOD] = 1.0f;
  807. }
  808.  
  809. for (uint8 i = 0; i < MAX_COMBAT_RATING; i++)
  810. m_baseRatingValue[i] = 0;
  811.  
  812. m_baseSpellPower = 0;
  813. m_baseFeralAP = 0;
  814. m_baseManaRegen = 0;
  815. m_baseHealthRegen = 0;
  816. m_spellPenetrationItemMod = 0;
  817.  
  818. // Honor System
  819. m_lastHonorUpdateTime = time(NULL);
  820.  
  821. m_IsBGRandomWinner = false;
  822.  
  823. // Player summoning
  824. m_summon_expire = 0;
  825. m_summon_mapid = 0;
  826. m_summon_x = 0.0f;
  827. m_summon_y = 0.0f;
  828. m_summon_z = 0.0f;
  829.  
  830. m_mover = this;
  831. m_movedPlayer = this;
  832. m_seer = this;
  833.  
  834. m_contestedPvPTimer = 0;
  835.  
  836. m_declinedname = NULL;
  837.  
  838. m_isActive = true;
  839.  
  840. m_runes = NULL;
  841.  
  842. m_lastFallTime = 0;
  843. m_lastFallZ = 0;
  844.  
  845. m_grantableLevels = 0;
  846.  
  847. m_ControlledByPlayer = true;
  848.  
  849. sWorld->IncreasePlayerCount();
  850.  
  851. m_ChampioningFaction = 0;
  852.  
  853. for (uint8 i = 0; i < MAX_POWERS; ++i)
  854. m_powerFraction[i] = 0;
  855.  
  856. isDebugAreaTriggers = false;
  857.  
  858. m_WeeklyQuestChanged = false;
  859.  
  860. m_SeasonalQuestChanged = false;
  861.  
  862. SetPendingBind(0, 0);
  863. }
  864.  
  865. Player::~Player()
  866. {
  867. // it must be unloaded already in PlayerLogout and accessed only for loggined player
  868. //m_social = NULL;
  869.  
  870. // Note: buy back item already deleted from DB when player was saved
  871. for (uint8 i = 0; i < PLAYER_SLOTS_COUNT; ++i)
  872. delete m_items[i];
  873.  
  874. for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
  875. delete itr->second;
  876.  
  877. for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i)
  878. {
  879. for (PlayerTalentMap::const_iterator itr = m_talents[i]->begin(); itr != m_talents[i]->end(); ++itr)
  880. delete itr->second;
  881. delete m_talents[i];
  882. }
  883.  
  884. //all mailed items should be deleted, also all mail should be deallocated
  885. for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr)
  886. delete *itr;
  887.  
  888. for (ItemMap::iterator iter = mMitems.begin(); iter != mMitems.end(); ++iter)
  889. delete iter->second; //if item is duplicated... then server may crash ... but that item should be deallocated
  890.  
  891. delete PlayerTalkClass;
  892.  
  893. for (size_t x = 0; x < ItemSetEff.size(); x++)
  894. delete ItemSetEff[x];
  895.  
  896. delete m_declinedname;
  897. delete m_runes;
  898.  
  899. sWorld->DecreasePlayerCount();
  900. }
  901.  
  902. void Player::CleanupsBeforeDelete(bool finalCleanup)
  903. {
  904. TradeCancel(false);
  905. DuelComplete(DUEL_INTERRUPTED);
  906.  
  907. Unit::CleanupsBeforeDelete(finalCleanup);
  908.  
  909. if (m_transport)
  910. m_transport->RemovePassenger(this);
  911.  
  912. // clean up player-instance binds, may unload some instance saves
  913. for (uint8 i = 0; i < MAX_DIFFICULTY; ++i)
  914. for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
  915. itr->second.save->RemovePlayer(this);
  916. }
  917.  
  918. bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo)
  919. {
  920. //FIXME: outfitId not used in player creating
  921. // TODO: need more checks against packet modifications
  922. // should check that skin, face, hair* are valid via DBC per race/class
  923. // also do it in Player::BuildEnumData, Player::LoadFromDB
  924.  
  925. Object::_Create(guidlow, 0, HIGHGUID_PLAYER);
  926.  
  927. m_name = createInfo->Name;
  928.  
  929. PlayerInfo const* info = sObjectMgr->GetPlayerInfo(createInfo->Race, createInfo->Class);
  930. if (!info)
  931. {
  932. sLog->outError(LOG_FILTER_PLAYER, "Player::Create: Possible hacking-attempt: Account %u tried creating a character named '%s' with an invalid race/class pair (%u/%u) - refusing to do so.",
  933. GetSession()->GetAccountId(), m_name.c_str(), createInfo->Race, createInfo->Class);
  934. return false;
  935. }
  936.  
  937. for (uint8 i = 0; i < PLAYER_SLOTS_COUNT; i++)
  938. m_items[i] = NULL;
  939.  
  940. Relocate(info->positionX, info->positionY, info->positionZ, info->orientation);
  941.  
  942. ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(createInfo->Class);
  943. if (!cEntry)
  944. {
  945. sLog->outError(LOG_FILTER_PLAYER, "Player::Create: Possible hacking-attempt: Account %u tried creating a character named '%s' with an invalid character class (%u) - refusing to do so (wrong DBC-files?)",
  946. GetSession()->GetAccountId(), m_name.c_str(), createInfo->Class);
  947. return false;
  948. }
  949.  
  950. SetMap(sMapMgr->CreateMap(info->mapId, this));
  951.  
  952. uint8 powertype = cEntry->powerType;
  953.  
  954. SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, DEFAULT_WORLD_OBJECT_SIZE);
  955. SetFloatValue(UNIT_FIELD_COMBATREACH, 1.5f);
  956.  
  957. setFactionForRace(createInfo->Race);
  958.  
  959. if (!IsValidGender(createInfo->Gender))
  960. {
  961. sLog->outError(LOG_FILTER_PLAYER, "Player::Create: Possible hacking-attempt: Account %u tried creating a character named '%s' with an invalid gender (%hu) - refusing to do so",
  962. GetSession()->GetAccountId(), m_name.c_str(), createInfo->Gender);
  963. return false;
  964. }
  965.  
  966. uint32 RaceClassGender = (createInfo->Race) | (createInfo->Class << 8) | (createInfo->Gender << 16);
  967.  
  968. SetUInt32Value(UNIT_FIELD_BYTES_0, (RaceClassGender | (powertype << 24)));
  969. InitDisplayIds();
  970. if (sWorld->getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_PVP || sWorld->getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_RPPVP)
  971. {
  972. SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP);
  973. SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
  974. }
  975. SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER);
  976. SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f); // fix cast time showed in spell tooltip on client
  977. SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 1.0f); // default for players in 3.0.3
  978.  
  979. // -1 is default value
  980. SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, uint32(-1));
  981.  
  982. SetUInt32Value(PLAYER_BYTES, (createInfo->Skin | (createInfo->Face << 8) | (createInfo->HairStyle << 16) | (createInfo->HairColor << 24)));
  983. SetUInt32Value(PLAYER_BYTES_2, (createInfo->FacialHair |
  984. (0x00 << 8) |
  985. (0x00 << 16) |
  986. (((GetSession()->IsARecruiter() || GetSession()->GetRecruiterId() != 0) ? REST_STATE_RAF_LINKED : REST_STATE_NOT_RAF_LINKED) << 24)));
  987. SetByteValue(PLAYER_BYTES_3, 0, createInfo->Gender);
  988. SetByteValue(PLAYER_BYTES_3, 3, 0); // BattlefieldArenaFaction (0 or 1)
  989.  
  990. SetUInt32Value(PLAYER_GUILDID, 0);
  991. SetUInt32Value(PLAYER_GUILDRANK, 0);
  992. SetUInt32Value(PLAYER_GUILD_TIMESTAMP, 0);
  993.  
  994. for (int i = 0; i < KNOWN_TITLES_SIZE; ++i)
  995. SetUInt64Value(PLAYER__FIELD_KNOWN_TITLES + i, 0); // 0=disabled
  996. SetUInt32Value(PLAYER_CHOSEN_TITLE, 0);
  997.  
  998. SetUInt32Value(PLAYER_FIELD_KILLS, 0);
  999. SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, 0);
  1000. SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, 0);
  1001. SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0);
  1002.  
  1003. // set starting level
  1004. uint32 start_level = getClass() != CLASS_DEATH_KNIGHT
  1005. ? sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL)
  1006. : sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL);
  1007.  
  1008. if (!AccountMgr::IsPlayerAccount(GetSession()->GetSecurity()))
  1009. {
  1010. uint32 gm_level = sWorld->getIntConfig(CONFIG_START_GM_LEVEL);
  1011. if (gm_level > start_level)
  1012. start_level = gm_level;
  1013. }
  1014.  
  1015. SetUInt32Value(UNIT_FIELD_LEVEL, start_level);
  1016.  
  1017. InitRunes();
  1018.  
  1019. SetUInt32Value(PLAYER_FIELD_COINAGE, sWorld->getIntConfig(CONFIG_START_PLAYER_MONEY));
  1020. SetHonorPoints(sWorld->getIntConfig(CONFIG_START_HONOR_POINTS));
  1021. SetArenaPoints(sWorld->getIntConfig(CONFIG_START_ARENA_POINTS));
  1022.  
  1023. // start with every map explored
  1024. if (sWorld->getBoolConfig(CONFIG_START_ALL_EXPLORED))
  1025. {
  1026. for (uint8 i=0; i<PLAYER_EXPLORED_ZONES_SIZE; i++)
  1027. SetFlag(PLAYER_EXPLORED_ZONES_1+i, 0xFFFFFFFF);
  1028. }
  1029.  
  1030. //Reputations if "StartAllReputation" is enabled, -- TODO: Fix this in a better way
  1031. if (sWorld->getBoolConfig(CONFIG_START_ALL_REP))
  1032. {
  1033. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(942), 42999);
  1034. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(935), 42999);
  1035. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(936), 42999);
  1036. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(1011), 42999);
  1037. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(970), 42999);
  1038. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(967), 42999);
  1039. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(989), 42999);
  1040. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(932), 42999);
  1041. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(934), 42999);
  1042. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(1038), 42999);
  1043. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(1077), 42999);
  1044.  
  1045. // Factions depending on team, like cities and some more stuff
  1046. switch (GetTeam())
  1047. {
  1048. case ALLIANCE:
  1049. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(72), 42999);
  1050. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(47), 42999);
  1051. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(69), 42999);
  1052. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(930), 42999);
  1053. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(730), 42999);
  1054. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(978), 42999);
  1055. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(54), 42999);
  1056. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(946), 42999);
  1057. break;
  1058. case HORDE:
  1059. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(76), 42999);
  1060. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(68), 42999);
  1061. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(81), 42999);
  1062. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(911), 42999);
  1063. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(729), 42999);
  1064. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(941), 42999);
  1065. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(530), 42999);
  1066. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(947), 42999);
  1067. break;
  1068. default:
  1069. break;
  1070. }
  1071. }
  1072.  
  1073. // Played time
  1074. m_Last_tick = time(NULL);
  1075. m_Played_time[PLAYED_TIME_TOTAL] = 0;
  1076. m_Played_time[PLAYED_TIME_LEVEL] = 0;
  1077.  
  1078. // base stats and related field values
  1079. InitStatsForLevel();
  1080. InitTaxiNodesForLevel();
  1081. InitGlyphsForLevel();
  1082. InitTalentForLevel();
  1083. InitPrimaryProfessions(); // to max set before any spell added
  1084.  
  1085. // apply original stats mods before spell loading or item equipment that call before equip _RemoveStatsMods()
  1086. UpdateMaxHealth(); // Update max Health (for add bonus from stamina)
  1087. SetFullHealth();
  1088. if (getPowerType() == POWER_MANA)
  1089. {
  1090. UpdateMaxPower(POWER_MANA); // Update max Mana (for add bonus from intellect)
  1091. SetPower(POWER_MANA, GetMaxPower(POWER_MANA));
  1092. }
  1093.  
  1094. if (getPowerType() == POWER_RUNIC_POWER)
  1095. {
  1096. SetPower(POWER_RUNE, 8);
  1097. SetMaxPower(POWER_RUNE, 8);
  1098. SetPower(POWER_RUNIC_POWER, 0);
  1099. SetMaxPower(POWER_RUNIC_POWER, 1000);
  1100. }
  1101.  
  1102. // original spells
  1103. learnDefaultSpells();
  1104.  
  1105. // original action bar
  1106. for (PlayerCreateInfoActions::const_iterator action_itr = info->action.begin(); action_itr != info->action.end(); ++action_itr)
  1107. addActionButton(action_itr->button, action_itr->action, action_itr->type);
  1108.  
  1109. // original items
  1110. CharStartOutfitEntry const* oEntry = NULL;
  1111. for (uint32 i = 1; i < sCharStartOutfitStore.GetNumRows(); ++i)
  1112. {
  1113. if (CharStartOutfitEntry const* entry = sCharStartOutfitStore.LookupEntry(i))
  1114. {
  1115. if (entry->RaceClassGender == RaceClassGender)
  1116. {
  1117. oEntry = entry;
  1118. break;
  1119. }
  1120. }
  1121. }
  1122.  
  1123. if (oEntry)
  1124. {
  1125. for (int j = 0; j < MAX_OUTFIT_ITEMS; ++j)
  1126. {
  1127. if (oEntry->ItemId[j] <= 0)
  1128. continue;
  1129.  
  1130. uint32 itemId = oEntry->ItemId[j];
  1131.  
  1132. // just skip, reported in ObjectMgr::LoadItemTemplates
  1133. ItemTemplate const* iProto = sObjectMgr->GetItemTemplate(itemId);
  1134. if (!iProto)
  1135. continue;
  1136.  
  1137. // BuyCount by default
  1138. uint32 count = iProto->BuyCount;
  1139.  
  1140. // special amount for food/drink
  1141. if (iProto->Class == ITEM_CLASS_CONSUMABLE && iProto->SubClass == ITEM_SUBCLASS_FOOD)
  1142. {
  1143. switch (iProto->Spells[0].SpellCategory)
  1144. {
  1145. case SPELL_CATEGORY_FOOD: // food
  1146. count = getClass() == CLASS_DEATH_KNIGHT ? 10 : 4;
  1147. break;
  1148. case SPELL_CATEGORY_DRINK: // drink
  1149. count = 2;
  1150. break;
  1151. }
  1152. if (iProto->GetMaxStackSize() < count)
  1153. count = iProto->GetMaxStackSize();
  1154. }
  1155. StoreNewItemInBestSlots(itemId, count);
  1156. }
  1157. }
  1158.  
  1159. for (PlayerCreateInfoItems::const_iterator item_id_itr = info->item.begin(); item_id_itr != info->item.end(); ++item_id_itr)
  1160. StoreNewItemInBestSlots(item_id_itr->item_id, item_id_itr->item_amount);
  1161.  
  1162. // bags and main-hand weapon must equipped at this moment
  1163. // now second pass for not equipped (offhand weapon/shield if it attempt equipped before main-hand weapon)
  1164. // or ammo not equipped in special bag
  1165. for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
  1166. {
  1167. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  1168. {
  1169. uint16 eDest;
  1170. // equip offhand weapon/shield if it attempt equipped before main-hand weapon
  1171. InventoryResult msg = CanEquipItem(NULL_SLOT, eDest, pItem, false);
  1172. if (msg == EQUIP_ERR_OK)
  1173. {
  1174. RemoveItem(INVENTORY_SLOT_BAG_0, i, true);
  1175. EquipItem(eDest, pItem, true);
  1176. }
  1177. // move other items to more appropriate slots (ammo not equipped in special bag)
  1178. else
  1179. {
  1180. ItemPosCountVec sDest;
  1181. msg = CanStoreItem(NULL_BAG, NULL_SLOT, sDest, pItem, false);
  1182. if (msg == EQUIP_ERR_OK)
  1183. {
  1184. RemoveItem(INVENTORY_SLOT_BAG_0, i, true);
  1185. pItem = StoreItem(sDest, pItem, true);
  1186. }
  1187.  
  1188. // if this is ammo then use it
  1189. msg = CanUseAmmo(pItem->GetEntry());
  1190. if (msg == EQUIP_ERR_OK)
  1191. SetAmmo(pItem->GetEntry());
  1192. }
  1193. }
  1194. }
  1195. // all item positions resolved
  1196.  
  1197. return true;
  1198. }
  1199.  
  1200. bool Player::StoreNewItemInBestSlots(uint32 titem_id, uint32 titem_amount)
  1201. {
  1202. sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "STORAGE: Creating initial item, itemId = %u, count = %u", titem_id, titem_amount);
  1203.  
  1204. // attempt equip by one
  1205. while (titem_amount > 0)
  1206. {
  1207. uint16 eDest;
  1208. InventoryResult msg = CanEquipNewItem(NULL_SLOT, eDest, titem_id, false);
  1209. if (msg != EQUIP_ERR_OK)
  1210. break;
  1211.  
  1212. EquipNewItem(eDest, titem_id, true);
  1213. AutoUnequipOffhandIfNeed();
  1214. --titem_amount;
  1215. }
  1216.  
  1217. if (titem_amount == 0)
  1218. return true; // equipped
  1219.  
  1220. // attempt store
  1221. ItemPosCountVec sDest;
  1222. // store in main bag to simplify second pass (special bags can be not equipped yet at this moment)
  1223. InventoryResult msg = CanStoreNewItem(INVENTORY_SLOT_BAG_0, NULL_SLOT, sDest, titem_id, titem_amount);
  1224. if (msg == EQUIP_ERR_OK)
  1225. {
  1226. StoreNewItem(sDest, titem_id, true, Item::GenerateItemRandomPropertyId(titem_id));
  1227. return true; // stored
  1228. }
  1229.  
  1230. // item can't be added
  1231. sLog->outError(LOG_FILTER_PLAYER_ITEMS, "STORAGE: Can't equip or store initial item %u for race %u class %u, error msg = %u", titem_id, getRace(), getClass(), msg);
  1232. return false;
  1233. }
  1234.  
  1235. void Player::SendMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, int32 Regen)
  1236. {
  1237. if (int(MaxValue) == DISABLED_MIRROR_TIMER)
  1238. {
  1239. if (int(CurrentValue) != DISABLED_MIRROR_TIMER)
  1240. StopMirrorTimer(Type);
  1241. return;
  1242. }
  1243. WorldPacket data(SMSG_START_MIRROR_TIMER, (21));
  1244. data << (uint32)Type;
  1245. data << CurrentValue;
  1246. data << MaxValue;
  1247. data << Regen;
  1248. data << (uint8)0;
  1249. data << (uint32)0; // spell id
  1250. GetSession()->SendPacket(&data);
  1251. }
  1252.  
  1253. void Player::StopMirrorTimer(MirrorTimerType Type)
  1254. {
  1255. m_MirrorTimer[Type] = DISABLED_MIRROR_TIMER;
  1256. WorldPacket data(SMSG_STOP_MIRROR_TIMER, 4);
  1257. data << (uint32)Type;
  1258. GetSession()->SendPacket(&data);
  1259. }
  1260.  
  1261. bool Player::IsImmuneToEnvironmentalDamage()
  1262. {
  1263. // check for GM and death state included in isAttackableByAOE
  1264. return (!isTargetableForAttack(false));
  1265. }
  1266.  
  1267. uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage)
  1268. {
  1269. if (IsImmuneToEnvironmentalDamage())
  1270. return 0;
  1271.  
  1272. // Absorb, resist some environmental damage type
  1273. uint32 absorb = 0;
  1274. uint32 resist = 0;
  1275. if (type == DAMAGE_LAVA)
  1276. CalcAbsorbResist(this, SPELL_SCHOOL_MASK_FIRE, DIRECT_DAMAGE, damage, &absorb, &resist);
  1277. else if (type == DAMAGE_SLIME)
  1278. CalcAbsorbResist(this, SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE, damage, &absorb, &resist);
  1279.  
  1280. damage -= absorb + resist;
  1281.  
  1282. DealDamageMods(this, damage, &absorb);
  1283.  
  1284. WorldPacket data(SMSG_ENVIRONMENTALDAMAGELOG, (21));
  1285. data << uint64(GetGUID());
  1286. data << uint8(type != DAMAGE_FALL_TO_VOID ? type : DAMAGE_FALL);
  1287. data << uint32(damage);
  1288. data << uint32(absorb);
  1289. data << uint32(resist);
  1290. SendMessageToSet(&data, true);
  1291.  
  1292. uint32 final_damage = DealDamage(this, damage, NULL, SELF_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
  1293.  
  1294. if (!isAlive())
  1295. {
  1296. if (type == DAMAGE_FALL) // DealDamage not apply item durability loss at self damage
  1297. {
  1298. sLog->outDebug(LOG_FILTER_PLAYER, "We are fall to death, loosing 10 percents durability");
  1299. DurabilityLossAll(0.10f, false);
  1300. // durability lost message
  1301. WorldPacket data2(SMSG_DURABILITY_DAMAGE_DEATH, 0);
  1302. GetSession()->SendPacket(&data2);
  1303. }
  1304.  
  1305. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM, 1, type);
  1306. }
  1307.  
  1308. return final_damage;
  1309. }
  1310.  
  1311. int32 Player::getMaxTimer(MirrorTimerType timer)
  1312. {
  1313. switch (timer)
  1314. {
  1315. case FATIGUE_TIMER:
  1316. return MINUTE * IN_MILLISECONDS;
  1317. case BREATH_TIMER:
  1318. {
  1319. if (!isAlive() || HasAuraType(SPELL_AURA_WATER_BREATHING) || GetSession()->GetSecurity() >= AccountTypes(sWorld->getIntConfig(CONFIG_DISABLE_BREATHING)))
  1320. return DISABLED_MIRROR_TIMER;
  1321. int32 UnderWaterTime = 3 * MINUTE * IN_MILLISECONDS;
  1322. AuraEffectList const& mModWaterBreathing = GetAuraEffectsByType(SPELL_AURA_MOD_WATER_BREATHING);
  1323. for (AuraEffectList::const_iterator i = mModWaterBreathing.begin(); i != mModWaterBreathing.end(); ++i)
  1324. AddPctN(UnderWaterTime, (*i)->GetAmount());
  1325. return UnderWaterTime;
  1326. }
  1327. case FIRE_TIMER:
  1328. {
  1329. if (!isAlive())
  1330. return DISABLED_MIRROR_TIMER;
  1331. return 1 * IN_MILLISECONDS;
  1332. }
  1333. default:
  1334. return 0;
  1335. }
  1336. }
  1337.  
  1338. void Player::UpdateMirrorTimers()
  1339. {
  1340. // Desync flags for update on next HandleDrowning
  1341. if (m_MirrorTimerFlags)
  1342. m_MirrorTimerFlagsLast = ~m_MirrorTimerFlags;
  1343. }
  1344.  
  1345. void Player::HandleDrowning(uint32 time_diff)
  1346. {
  1347. if (!m_MirrorTimerFlags)
  1348. return;
  1349.  
  1350. // In water
  1351. if (m_MirrorTimerFlags & UNDERWATER_INWATER)
  1352. {
  1353. // Breath timer not activated - activate it
  1354. if (m_MirrorTimer[BREATH_TIMER] == DISABLED_MIRROR_TIMER)
  1355. {
  1356. m_MirrorTimer[BREATH_TIMER] = getMaxTimer(BREATH_TIMER);
  1357. SendMirrorTimer(BREATH_TIMER, m_MirrorTimer[BREATH_TIMER], m_MirrorTimer[BREATH_TIMER], -1);
  1358. }
  1359. else // If activated - do tick
  1360. {
  1361. m_MirrorTimer[BREATH_TIMER]-=time_diff;
  1362. // Timer limit - need deal damage
  1363. if (m_MirrorTimer[BREATH_TIMER] < 0)
  1364. {
  1365. m_MirrorTimer[BREATH_TIMER]+= 1*IN_MILLISECONDS;
  1366. // Calculate and deal damage
  1367. // TODO: Check this formula
  1368. uint32 damage = GetMaxHealth() / 5 + urand(0, getLevel()-1);
  1369. EnvironmentalDamage(DAMAGE_DROWNING, damage);
  1370. }
  1371. else if (!(m_MirrorTimerFlagsLast & UNDERWATER_INWATER)) // Update time in client if need
  1372. SendMirrorTimer(BREATH_TIMER, getMaxTimer(BREATH_TIMER), m_MirrorTimer[BREATH_TIMER], -1);
  1373. }
  1374. }
  1375. else if (m_MirrorTimer[BREATH_TIMER] != DISABLED_MIRROR_TIMER) // Regen timer
  1376. {
  1377. int32 UnderWaterTime = getMaxTimer(BREATH_TIMER);
  1378. // Need breath regen
  1379. m_MirrorTimer[BREATH_TIMER]+=10*time_diff;
  1380. if (m_MirrorTimer[BREATH_TIMER] >= UnderWaterTime || !isAlive())
  1381. StopMirrorTimer(BREATH_TIMER);
  1382. else if (m_MirrorTimerFlagsLast & UNDERWATER_INWATER)
  1383. SendMirrorTimer(BREATH_TIMER, UnderWaterTime, m_MirrorTimer[BREATH_TIMER], 10);
  1384. }
  1385.  
  1386. // In dark water
  1387. if (m_MirrorTimerFlags & UNDERWARER_INDARKWATER)
  1388. {
  1389. // Fatigue timer not activated - activate it
  1390. if (m_MirrorTimer[FATIGUE_TIMER] == DISABLED_MIRROR_TIMER)
  1391. {
  1392. m_MirrorTimer[FATIGUE_TIMER] = getMaxTimer(FATIGUE_TIMER);
  1393. SendMirrorTimer(FATIGUE_TIMER, m_MirrorTimer[FATIGUE_TIMER], m_MirrorTimer[FATIGUE_TIMER], -1);
  1394. }
  1395. else
  1396. {
  1397. m_MirrorTimer[FATIGUE_TIMER]-=time_diff;
  1398. // Timer limit - need deal damage or teleport ghost to graveyard
  1399. if (m_MirrorTimer[FATIGUE_TIMER] < 0)
  1400. {
  1401. m_MirrorTimer[FATIGUE_TIMER]+= 1*IN_MILLISECONDS;
  1402. if (isAlive()) // Calculate and deal damage
  1403. {
  1404. uint32 damage = GetMaxHealth() / 5 + urand(0, getLevel()-1);
  1405. EnvironmentalDamage(DAMAGE_EXHAUSTED, damage);
  1406. }
  1407. else if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) // Teleport ghost to graveyard
  1408. RepopAtGraveyard();
  1409. }
  1410. else if (!(m_MirrorTimerFlagsLast & UNDERWARER_INDARKWATER))
  1411. SendMirrorTimer(FATIGUE_TIMER, getMaxTimer(FATIGUE_TIMER), m_MirrorTimer[FATIGUE_TIMER], -1);
  1412. }
  1413. }
  1414. else if (m_MirrorTimer[FATIGUE_TIMER] != DISABLED_MIRROR_TIMER) // Regen timer
  1415. {
  1416. int32 DarkWaterTime = getMaxTimer(FATIGUE_TIMER);
  1417. m_MirrorTimer[FATIGUE_TIMER]+=10*time_diff;
  1418. if (m_MirrorTimer[FATIGUE_TIMER] >= DarkWaterTime || !isAlive())
  1419. StopMirrorTimer(FATIGUE_TIMER);
  1420. else if (m_MirrorTimerFlagsLast & UNDERWARER_INDARKWATER)
  1421. SendMirrorTimer(FATIGUE_TIMER, DarkWaterTime, m_MirrorTimer[FATIGUE_TIMER], 10);
  1422. }
  1423.  
  1424. if (m_MirrorTimerFlags & (UNDERWATER_INLAVA /*| UNDERWATER_INSLIME*/) && !(_lastLiquid && _lastLiquid->SpellId))
  1425. {
  1426. // Breath timer not activated - activate it
  1427. if (m_MirrorTimer[FIRE_TIMER] == DISABLED_MIRROR_TIMER)
  1428. m_MirrorTimer[FIRE_TIMER] = getMaxTimer(FIRE_TIMER);
  1429. else
  1430. {
  1431. m_MirrorTimer[FIRE_TIMER] -= time_diff;
  1432. if (m_MirrorTimer[FIRE_TIMER] < 0)
  1433. {
  1434. m_MirrorTimer[FIRE_TIMER]+= 1*IN_MILLISECONDS;
  1435. // Calculate and deal damage
  1436. // TODO: Check this formula
  1437. uint32 damage = urand(600, 700);
  1438. if (m_MirrorTimerFlags & UNDERWATER_INLAVA)
  1439. EnvironmentalDamage(DAMAGE_LAVA, damage);
  1440. // need to skip Slime damage in Undercity,
  1441. // maybe someone can find better way to handle environmental damage
  1442. //else if (m_zoneUpdateId != 1497)
  1443. // EnvironmentalDamage(DAMAGE_SLIME, damage);
  1444. }
  1445. }
  1446. }
  1447. else
  1448. m_MirrorTimer[FIRE_TIMER] = DISABLED_MIRROR_TIMER;
  1449.  
  1450. // Recheck timers flag
  1451. m_MirrorTimerFlags&=~UNDERWATER_EXIST_TIMERS;
  1452. for (uint8 i = 0; i< MAX_TIMERS; ++i)
  1453. if (m_MirrorTimer[i] != DISABLED_MIRROR_TIMER)
  1454. {
  1455. m_MirrorTimerFlags|=UNDERWATER_EXIST_TIMERS;
  1456. break;
  1457. }
  1458. m_MirrorTimerFlagsLast = m_MirrorTimerFlags;
  1459. }
  1460.  
  1461. ///The player sobers by 1% every 9 seconds
  1462. void Player::HandleSobering()
  1463. {
  1464. m_drunkTimer = 0;
  1465.  
  1466. uint8 currentDrunkValue = GetDrunkValue();
  1467. uint8 drunk = currentDrunkValue ? --currentDrunkValue : 0;
  1468. SetDrunkValue(drunk);
  1469. }
  1470.  
  1471. DrunkenState Player::GetDrunkenstateByValue(uint8 value)
  1472. {
  1473. if (value >= 90)
  1474. return DRUNKEN_SMASHED;
  1475. if (value >= 50)
  1476. return DRUNKEN_DRUNK;
  1477. if (value)
  1478. return DRUNKEN_TIPSY;
  1479. return DRUNKEN_SOBER;
  1480. }
  1481.  
  1482. void Player::SetDrunkValue(uint8 newDrunkValue, uint32 itemId /*= 0*/)
  1483. {
  1484. bool isSobering = newDrunkValue < GetDrunkValue();
  1485. uint32 oldDrunkenState = Player::GetDrunkenstateByValue(GetDrunkValue());
  1486. if (newDrunkValue > 100)
  1487. newDrunkValue = 100;
  1488.  
  1489. // select drunk percent or total SPELL_AURA_MOD_FAKE_INEBRIATE amount, whichever is higher for visibility updates
  1490. int32 drunkPercent = std::max<int32>(newDrunkValue, GetTotalAuraModifier(SPELL_AURA_MOD_FAKE_INEBRIATE));
  1491. if (drunkPercent)
  1492. {
  1493. m_invisibilityDetect.AddFlag(INVISIBILITY_DRUNK);
  1494. m_invisibilityDetect.SetValue(INVISIBILITY_DRUNK, drunkPercent);
  1495. }
  1496. else if (!HasAuraType(SPELL_AURA_MOD_FAKE_INEBRIATE) && !newDrunkValue)
  1497. m_invisibilityDetect.DelFlag(INVISIBILITY_DRUNK);
  1498.  
  1499. uint32 newDrunkenState = Player::GetDrunkenstateByValue(newDrunkValue);
  1500. SetByteValue(PLAYER_BYTES_3, 1, newDrunkValue);
  1501. UpdateObjectVisibility();
  1502.  
  1503. if (!isSobering)
  1504. m_drunkTimer = 0; // reset sobering timer
  1505.  
  1506. if (newDrunkenState == oldDrunkenState)
  1507. return;
  1508.  
  1509. WorldPacket data(SMSG_CROSSED_INEBRIATION_THRESHOLD, (8+4+4));
  1510. data << uint64(GetGUID());
  1511. data << uint32(newDrunkenState);
  1512. data << uint32(itemId);
  1513. SendMessageToSet(&data, true);
  1514. }
  1515.  
  1516. void Player::Update(uint32 p_time)
  1517. {
  1518. if (!IsInWorld())
  1519. return;
  1520.  
  1521. // undelivered mail
  1522. if (m_nextMailDelivereTime && m_nextMailDelivereTime <= time(NULL))
  1523. {
  1524. SendNewMail();
  1525. ++unReadMails;
  1526.  
  1527. // It will be recalculate at mailbox open (for unReadMails important non-0 until mailbox open, it also will be recalculated)
  1528. m_nextMailDelivereTime = 0;
  1529. }
  1530.  
  1531. // If this is set during update SetSpellModTakingSpell call is missing somewhere in the code
  1532. // Having this would prevent more aura charges to be dropped, so let's crash
  1533. //ASSERT (!m_spellModTakingSpell);
  1534. if (m_spellModTakingSpell)
  1535. {
  1536. //sLog->outFatal(LOG_FILTER_PLAYER, "Player has m_pad %u during update!", m_pad);
  1537. //if (m_spellModTakingSpell)
  1538. sLog->outFatal(LOG_FILTER_SPELLS_AURAS, "Player has m_spellModTakingSpell %u during update!", m_spellModTakingSpell->m_spellInfo->Id);
  1539. m_spellModTakingSpell = NULL;
  1540. }
  1541.  
  1542. //used to implement delayed far teleports
  1543. SetCanDelayTeleport(true);
  1544. Unit::Update(p_time);
  1545. SetCanDelayTeleport(false);
  1546.  
  1547. time_t now = time(NULL);
  1548.  
  1549. UpdatePvPFlag(now);
  1550.  
  1551. UpdateContestedPvP(p_time);
  1552.  
  1553. UpdateDuelFlag(now);
  1554.  
  1555. CheckDuelDistance(now);
  1556.  
  1557. UpdateAfkReport(now);
  1558.  
  1559. if (isCharmed())
  1560. if (Unit* charmer = GetCharmer())
  1561. if (charmer->GetTypeId() == TYPEID_UNIT && charmer->isAlive())
  1562. UpdateCharmedAI();
  1563.  
  1564. // Update items that have just a limited lifetime
  1565. if (now > m_Last_tick)
  1566. UpdateItemDuration(uint32(now - m_Last_tick));
  1567.  
  1568. // check every second
  1569. if (now > m_Last_tick + 1)
  1570. UpdateSoulboundTradeItems();
  1571.  
  1572. if (!m_timedquests.empty())
  1573. {
  1574. QuestSet::iterator iter = m_timedquests.begin();
  1575. while (iter != m_timedquests.end())
  1576. {
  1577. QuestStatusData& q_status = m_QuestStatus[*iter];
  1578. if (q_status.Timer <= p_time)
  1579. {
  1580. uint32 quest_id = *iter;
  1581. ++iter; // current iter will be removed in FailQuest
  1582. FailQuest(quest_id);
  1583. }
  1584. else
  1585. {
  1586. q_status.Timer -= p_time;
  1587. m_QuestStatusSave[*iter] = true;
  1588. ++iter;
  1589. }
  1590. }
  1591. }
  1592.  
  1593. GetAchievementMgr().UpdateTimedAchievements(p_time);
  1594.  
  1595. if (HasUnitState(UNIT_STATE_MELEE_ATTACKING) && !HasUnitState(UNIT_STATE_CASTING))
  1596. {
  1597. if (Unit* victim = getVictim())
  1598. {
  1599. // default combat reach 10
  1600. // TODO add weapon, skill check
  1601.  
  1602. if (isAttackReady(BASE_ATTACK))
  1603. {
  1604. if (!IsWithinMeleeRange(victim))
  1605. {
  1606. setAttackTimer(BASE_ATTACK, 100);
  1607. if (m_swingErrorMsg != 1) // send single time (client auto repeat)
  1608. {
  1609. SendAttackSwingNotInRange();
  1610. m_swingErrorMsg = 1;
  1611. }
  1612. }
  1613. //120 degrees of radiant range
  1614. else if (!HasInArc(2*M_PI/3, victim))
  1615. {
  1616. setAttackTimer(BASE_ATTACK, 100);
  1617. if (m_swingErrorMsg != 2) // send single time (client auto repeat)
  1618. {
  1619. SendAttackSwingBadFacingAttack();
  1620. m_swingErrorMsg = 2;
  1621. }
  1622. }
  1623. else
  1624. {
  1625. m_swingErrorMsg = 0; // reset swing error state
  1626.  
  1627. // prevent base and off attack in same time, delay attack at 0.2 sec
  1628. if (haveOffhandWeapon())
  1629. if (getAttackTimer(OFF_ATTACK) < ATTACK_DISPLAY_DELAY)
  1630. setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY);
  1631.  
  1632. // do attack
  1633. AttackerStateUpdate(victim, BASE_ATTACK);
  1634. resetAttackTimer(BASE_ATTACK);
  1635. }
  1636. }
  1637.  
  1638. if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK))
  1639. {
  1640. if (!IsWithinMeleeRange(victim))
  1641. setAttackTimer(OFF_ATTACK, 100);
  1642. else if (!HasInArc(2*M_PI/3, victim))
  1643. setAttackTimer(OFF_ATTACK, 100);
  1644. else
  1645. {
  1646. // prevent base and off attack in same time, delay attack at 0.2 sec
  1647. if (getAttackTimer(BASE_ATTACK) < ATTACK_DISPLAY_DELAY)
  1648. setAttackTimer(BASE_ATTACK, ATTACK_DISPLAY_DELAY);
  1649.  
  1650. // do attack
  1651. AttackerStateUpdate(victim, OFF_ATTACK);
  1652. resetAttackTimer(OFF_ATTACK);
  1653. }
  1654. }
  1655.  
  1656. /*Unit* owner = victim->GetOwner();
  1657. Unit* u = owner ? owner : victim;
  1658. if (u->IsPvP() && (!duel || duel->opponent != u))
  1659. {
  1660. UpdatePvP(true);
  1661. RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
  1662. }*/
  1663. }
  1664. }
  1665.  
  1666. if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING))
  1667. {
  1668. if (roll_chance_i(3) && GetTimeInnEnter() > 0) // freeze update
  1669. {
  1670. time_t time_inn = time(NULL)-GetTimeInnEnter();
  1671. if (time_inn >= 10) // freeze update
  1672. {
  1673. float bubble = 0.125f*sWorld->getRate(RATE_REST_INGAME);
  1674. // speed collect rest bonus (section/in hour)
  1675. SetRestBonus(GetRestBonus()+ time_inn*((float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP)/72000)*bubble);
  1676. UpdateInnerTime(time(NULL));
  1677. }
  1678. }
  1679. }
  1680.  
  1681. if (m_weaponChangeTimer > 0)
  1682. {
  1683. if (p_time >= m_weaponChangeTimer)
  1684. m_weaponChangeTimer = 0;
  1685. else
  1686. m_weaponChangeTimer -= p_time;
  1687. }
  1688.  
  1689. if (m_zoneUpdateTimer > 0)
  1690. {
  1691. if (p_time >= m_zoneUpdateTimer)
  1692. {
  1693. uint32 newzone, newarea;
  1694. GetZoneAndAreaId(newzone, newarea);
  1695.  
  1696. if (m_zoneUpdateId != newzone)
  1697. UpdateZone(newzone, newarea); // also update area
  1698. else
  1699. {
  1700. // use area updates as well
  1701. // needed for free far all arenas for example
  1702. if (m_areaUpdateId != newarea)
  1703. UpdateArea(newarea);
  1704.  
  1705. m_zoneUpdateTimer = ZONE_UPDATE_INTERVAL;
  1706. }
  1707. }
  1708. else
  1709. m_zoneUpdateTimer -= p_time;
  1710. }
  1711.  
  1712. if (m_timeSyncTimer > 0)
  1713. {
  1714. if (p_time >= m_timeSyncTimer)
  1715. SendTimeSync();
  1716. else
  1717. m_timeSyncTimer -= p_time;
  1718. }
  1719.  
  1720. if (isAlive())
  1721. {
  1722. m_regenTimer += p_time;
  1723. RegenerateAll();
  1724. }
  1725.  
  1726. if (m_deathState == JUST_DIED)
  1727. KillPlayer();
  1728.  
  1729. if (m_nextSave > 0)
  1730. {
  1731. if (p_time >= m_nextSave)
  1732. {
  1733. // m_nextSave reseted in SaveToDB call
  1734. SaveToDB();
  1735. sLog->outDebug(LOG_FILTER_PLAYER, "Player '%s' (GUID: %u) saved", GetName(), GetGUIDLow());
  1736. }
  1737. else
  1738. m_nextSave -= p_time;
  1739. }
  1740.  
  1741. //Handle Water/drowning
  1742. HandleDrowning(p_time);
  1743.  
  1744. // Played time
  1745. if (now > m_Last_tick)
  1746. {
  1747. uint32 elapsed = uint32(now - m_Last_tick);
  1748. m_Played_time[PLAYED_TIME_TOTAL] += elapsed; // Total played time
  1749. m_Played_time[PLAYED_TIME_LEVEL] += elapsed; // Level played time
  1750. m_Last_tick = now;
  1751. }
  1752.  
  1753. if (GetDrunkValue())
  1754. {
  1755. m_drunkTimer += p_time;
  1756. if (m_drunkTimer > 9 * IN_MILLISECONDS)
  1757. HandleSobering();
  1758. }
  1759.  
  1760. if (HasPendingBind())
  1761. {
  1762. if (_pendingBindTimer <= p_time)
  1763. {
  1764. // Player left the instance
  1765. if (_pendingBindId == GetInstanceId())
  1766. BindToInstance();
  1767. SetPendingBind(0, 0);
  1768. }
  1769. else
  1770. _pendingBindTimer -= p_time;
  1771. }
  1772.  
  1773. // not auto-free ghost from body in instances
  1774. if (m_deathTimer > 0 && !GetBaseMap()->Instanceable() && !HasAuraType(SPELL_AURA_PREVENT_RESURRECTION))
  1775. {
  1776. if (p_time >= m_deathTimer)
  1777. {
  1778. m_deathTimer = 0;
  1779. BuildPlayerRepop();
  1780. RepopAtGraveyard();
  1781. }
  1782. else
  1783. m_deathTimer -= p_time;
  1784. }
  1785.  
  1786. UpdateEnchantTime(p_time);
  1787. UpdateHomebindTime(p_time);
  1788.  
  1789. if (!_instanceResetTimes.empty())
  1790. {
  1791. for (InstanceTimeMap::iterator itr = _instanceResetTimes.begin(); itr != _instanceResetTimes.end();)
  1792. {
  1793. if (itr->second < now)
  1794. _instanceResetTimes.erase(itr++);
  1795. else
  1796. ++itr;
  1797. }
  1798. }
  1799.  
  1800. // group update
  1801. SendUpdateToOutOfRangeGroupMembers();
  1802.  
  1803. Pet* pet = GetPet();
  1804. if (pet && !pet->IsWithinDistInMap(this, GetMap()->GetVisibilityRange()) && !pet->isPossessed())
  1805. //if (pet && !pet->IsWithinDistInMap(this, GetMap()->GetVisibilityDistance()) && (GetCharmGUID() && (pet->GetGUID() != GetCharmGUID())))
  1806. RemovePet(pet, PET_SAVE_NOT_IN_SLOT, true);
  1807.  
  1808. //we should execute delayed teleports only for alive(!) players
  1809. //because we don't want player's ghost teleported from graveyard
  1810. if (IsHasDelayedTeleport() && isAlive())
  1811. TeleportTo(m_teleport_dest, m_teleport_options);
  1812. }
  1813.  
  1814. void Player::setDeathState(DeathState s)
  1815. {
  1816. uint32 ressSpellId = 0;
  1817.  
  1818. bool cur = isAlive();
  1819.  
  1820. if (s == JUST_DIED)
  1821. {
  1822. if (!cur)
  1823. {
  1824. sLog->outError(LOG_FILTER_PLAYER, "setDeathState: attempt to kill a dead player %s(%d)", GetName(), GetGUIDLow());
  1825. return;
  1826. }
  1827.  
  1828. // drunken state is cleared on death
  1829. SetDrunkValue(0);
  1830. // lost combo points at any target (targeted combo points clear in Unit::setDeathState)
  1831. ClearComboPoints();
  1832.  
  1833. clearResurrectRequestData();
  1834.  
  1835. //FIXME: is pet dismissed at dying or releasing spirit? if second, add setDeathState(DEAD) to HandleRepopRequestOpcode and define pet unsummon here with (s == DEAD)
  1836. RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true);
  1837.  
  1838. // save value before aura remove in Unit::setDeathState
  1839. ressSpellId = GetUInt32Value(PLAYER_SELF_RES_SPELL);
  1840.  
  1841. // passive spell
  1842. if (!ressSpellId)
  1843. ressSpellId = GetResurrectionSpellId();
  1844. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP, 1);
  1845. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH, 1);
  1846. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON, 1);
  1847. GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, ACHIEVEMENT_CRITERIA_CONDITION_NO_DEATH);
  1848. GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL, ACHIEVEMENT_CRITERIA_CONDITION_NO_DEATH);
  1849. GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, ACHIEVEMENT_CRITERIA_CONDITION_NO_DEATH);
  1850. }
  1851.  
  1852. Unit::setDeathState(s);
  1853.  
  1854. // restore resurrection spell id for player after aura remove
  1855. if (s == JUST_DIED && cur && ressSpellId)
  1856. SetUInt32Value(PLAYER_SELF_RES_SPELL, ressSpellId);
  1857.  
  1858. if (isAlive() && !cur)
  1859. //clear aura case after resurrection by another way (spells will be applied before next death)
  1860. SetUInt32Value(PLAYER_SELF_RES_SPELL, 0);
  1861. }
  1862.  
  1863. bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data)
  1864. {
  1865. // 0 1 2 3 4 5 6 7
  1866. // "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, "
  1867. // 8 9 10 11 12 13 14
  1868. // "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, "
  1869. // 15 16 17 18 19 20 21
  1870. // "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.data, character_banned.guid, character_declinedname.genitive "
  1871.  
  1872. Field* fields = result->Fetch();
  1873.  
  1874. uint32 guid = fields[0].GetUInt32();
  1875. uint8 plrRace = fields[2].GetUInt8();
  1876. uint8 plrClass = fields[3].GetUInt8();
  1877. uint8 gender = fields[4].GetUInt8();
  1878.  
  1879. PlayerInfo const* info = sObjectMgr->GetPlayerInfo(plrRace, plrClass);
  1880. if (!info)
  1881. {
  1882. sLog->outError(LOG_FILTER_PLAYER_LOADING, "Player %u has incorrect race/class pair. Don't build enum.", guid);
  1883. return false;
  1884. }
  1885. else if (!IsValidGender(gender))
  1886. {
  1887. sLog->outError(LOG_FILTER_PLAYER_LOADING, "Player (%u) has incorrect gender (%hu), don't build enum.", guid, gender);
  1888. return false;
  1889. }
  1890.  
  1891. *data << uint64(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER));
  1892. *data << fields[1].GetString(); // name
  1893. *data << uint8(plrRace); // race
  1894. *data << uint8(plrClass); // class
  1895. *data << uint8(gender); // gender
  1896.  
  1897. uint32 playerBytes = fields[5].GetUInt32();
  1898. *data << uint8(playerBytes); // skin
  1899. *data << uint8(playerBytes >> 8); // face
  1900. *data << uint8(playerBytes >> 16); // hair style
  1901. *data << uint8(playerBytes >> 24); // hair color
  1902.  
  1903. uint32 playerBytes2 = fields[6].GetUInt32();
  1904. *data << uint8(playerBytes2 & 0xFF); // facial hair
  1905.  
  1906. *data << uint8(fields[7].GetUInt8()); // level
  1907. *data << uint32(fields[8].GetUInt16()); // zone
  1908. *data << uint32(fields[9].GetUInt16()); // map
  1909.  
  1910. *data << fields[10].GetFloat(); // x
  1911. *data << fields[11].GetFloat(); // y
  1912. *data << fields[12].GetFloat(); // z
  1913.  
  1914. *data << uint32(fields[13].GetUInt32()); // guild id
  1915.  
  1916. uint32 charFlags = 0;
  1917. uint32 playerFlags = fields[14].GetUInt32();
  1918. uint16 atLoginFlags = fields[15].GetUInt16();
  1919. if (playerFlags & PLAYER_FLAGS_HIDE_HELM)
  1920. charFlags |= CHARACTER_FLAG_HIDE_HELM;
  1921. if (playerFlags & PLAYER_FLAGS_HIDE_CLOAK)
  1922. charFlags |= CHARACTER_FLAG_HIDE_CLOAK;
  1923. if (playerFlags & PLAYER_FLAGS_GHOST)
  1924. charFlags |= CHARACTER_FLAG_GHOST;
  1925. if (atLoginFlags & AT_LOGIN_RENAME)
  1926. charFlags |= CHARACTER_FLAG_RENAME;
  1927. if (fields[20].GetUInt32())
  1928. charFlags |= CHARACTER_FLAG_LOCKED_BY_BILLING;
  1929. if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED))
  1930. {
  1931. if (!fields[21].GetString().empty())
  1932. charFlags |= CHARACTER_FLAG_DECLINED;
  1933. }
  1934. else
  1935. charFlags |= CHARACTER_FLAG_DECLINED;
  1936.  
  1937. *data << uint32(charFlags); // character flags
  1938.  
  1939. // character customize flags
  1940. if (atLoginFlags & AT_LOGIN_CUSTOMIZE)
  1941. *data << uint32(CHAR_CUSTOMIZE_FLAG_CUSTOMIZE);
  1942. else if (atLoginFlags & AT_LOGIN_CHANGE_FACTION)
  1943. *data << uint32(CHAR_CUSTOMIZE_FLAG_FACTION);
  1944. else if (atLoginFlags & AT_LOGIN_CHANGE_RACE)
  1945. *data << uint32(CHAR_CUSTOMIZE_FLAG_RACE);
  1946. else
  1947. *data << uint32(CHAR_CUSTOMIZE_FLAG_NONE);
  1948.  
  1949. // First login
  1950. *data << uint8(atLoginFlags & AT_LOGIN_FIRST ? 1 : 0);
  1951.  
  1952. // Pets info
  1953. uint32 petDisplayId = 0;
  1954. uint32 petLevel = 0;
  1955. uint32 petFamily = 0;
  1956.  
  1957. // show pet at selection character in character list only for non-ghost character
  1958. if (result && !(playerFlags & PLAYER_FLAGS_GHOST) && (plrClass == CLASS_WARLOCK || plrClass == CLASS_HUNTER || plrClass == CLASS_DEATH_KNIGHT))
  1959. {
  1960. uint32 entry = fields[16].GetUInt32();
  1961. CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(entry);
  1962. if (creatureInfo)
  1963. {
  1964. petDisplayId = fields[17].GetUInt32();
  1965. petLevel = fields[18].GetUInt16();
  1966. petFamily = creatureInfo->family;
  1967. }
  1968. }
  1969.  
  1970. *data << uint32(petDisplayId);
  1971. *data << uint32(petLevel);
  1972. *data << uint32(petFamily);
  1973.  
  1974. Tokens equipment(fields[19].GetString(), ' ');
  1975. for (uint8 slot = 0; slot < INVENTORY_SLOT_BAG_END; ++slot)
  1976. {
  1977. uint32 visualBase = slot * 2;
  1978. uint32 itemId = GetUInt32ValueFromArray(equipment, visualBase);
  1979. ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
  1980. if (!proto)
  1981. {
  1982. *data << uint32(0);
  1983. *data << uint8(0);
  1984. *data << uint32(0);
  1985. continue;
  1986. }
  1987.  
  1988. SpellItemEnchantmentEntry const* enchant = NULL;
  1989.  
  1990. uint32 enchants = GetUInt32ValueFromArray(equipment, visualBase + 1);
  1991. for (uint8 enchantSlot = PERM_ENCHANTMENT_SLOT; enchantSlot <= TEMP_ENCHANTMENT_SLOT; ++enchantSlot)
  1992. {
  1993. // values stored in 2 uint16
  1994. uint32 enchantId = 0x0000FFFF & (enchants >> enchantSlot*16);
  1995. if (!enchantId)
  1996. continue;
  1997.  
  1998. enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId);
  1999. if (enchant)
  2000. break;
  2001. }
  2002.  
  2003. *data << uint32(proto->DisplayInfoID);
  2004. *data << uint8(proto->InventoryType);
  2005. *data << uint32(enchant ? enchant->aura_id : 0);
  2006. }
  2007.  
  2008. return true;
  2009. }
  2010.  
  2011. bool Player::ToggleAFK()
  2012. {
  2013. ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK);
  2014.  
  2015. bool state = HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK);
  2016.  
  2017. // afk player not allowed in battleground
  2018. if (state && InBattleground() && !InArena())
  2019. LeaveBattleground();
  2020.  
  2021. return state;
  2022. }
  2023.  
  2024. bool Player::ToggleDND()
  2025. {
  2026. ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND);
  2027.  
  2028. return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND);
  2029. }
  2030.  
  2031. uint8 Player::GetChatTag() const
  2032. {
  2033. uint8 tag = CHAT_TAG_NONE;
  2034.  
  2035. if (isGMChat())
  2036. tag |= CHAT_TAG_GM;
  2037. if (isDND())
  2038. tag |= CHAT_TAG_DND;
  2039. if (isAFK())
  2040. tag |= CHAT_TAG_AFK;
  2041. if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_DEVELOPER))
  2042. tag |= CHAT_TAG_DEV;
  2043.  
  2044. return tag;
  2045. }
  2046.  
  2047. void Player::SendTeleportPacket(Position &oldPos)
  2048. {
  2049. WorldPacket data2(MSG_MOVE_TELEPORT, 38);
  2050. data2.append(GetPackGUID());
  2051. BuildMovementPacket(&data2);
  2052. Relocate(&oldPos);
  2053. SendMessageToSet(&data2, false);
  2054. }
  2055.  
  2056. void Player::SendTeleportAckPacket()
  2057. {
  2058. WorldPacket data(MSG_MOVE_TELEPORT_ACK, 41);
  2059. data.append(GetPackGUID());
  2060. data << uint32(0); // this value increments every time
  2061. BuildMovementPacket(&data);
  2062. GetSession()->SendPacket(&data);
  2063. }
  2064.  
  2065. bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options)
  2066. {
  2067. if (!MapManager::IsValidMapCoord(mapid, x, y, z, orientation))
  2068. {
  2069. sLog->outError(LOG_FILTER_MAPS, "TeleportTo: invalid map (%d) or invalid coordinates (X: %f, Y: %f, Z: %f, O: %f) given when teleporting player (GUID: %u, name: %s, map: %d, X: %f, Y: %f, Z: %f, O: %f).",
  2070. mapid, x, y, z, orientation, GetGUIDLow(), GetName(), GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
  2071. return false;
  2072. }
  2073.  
  2074. if (AccountMgr::IsPlayerAccount(GetSession()->GetSecurity()) && DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, mapid, this))
  2075. {
  2076. sLog->outError(LOG_FILTER_MAPS, "Player (GUID: %u, name: %s) tried to enter a forbidden map %u", GetGUIDLow(), GetName(), mapid);
  2077. SendTransferAborted(mapid, TRANSFER_ABORT_MAP_NOT_ALLOWED);
  2078. return false;
  2079. }
  2080.  
  2081. // preparing unsummon pet if lost (we must get pet before teleportation or will not find it later)
  2082. Pet* pet = GetPet();
  2083.  
  2084. MapEntry const* mEntry = sMapStore.LookupEntry(mapid);
  2085.  
  2086. // don't let enter battlegrounds without assigned battleground id (for example through areatrigger)...
  2087. // don't let gm level > 1 either
  2088. if (!InBattleground() && mEntry->IsBattlegroundOrArena())
  2089. return false;
  2090.  
  2091. // client without expansion support
  2092. if (GetSession()->Expansion() < mEntry->Expansion())
  2093. {
  2094. sLog->outDebug(LOG_FILTER_MAPS, "Player %s using client without required expansion tried teleport to non accessible map %u", GetName(), mapid);
  2095.  
  2096. if (GetTransport())
  2097. {
  2098. m_transport->RemovePassenger(this);
  2099. m_transport = NULL;
  2100. m_movementInfo.t_pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f);
  2101. m_movementInfo.t_time = 0;
  2102. m_movementInfo.t_seat = -1;
  2103. RepopAtGraveyard(); // teleport to near graveyard if on transport, looks blizz like :)
  2104. }
  2105.  
  2106. SendTransferAborted(mapid, TRANSFER_ABORT_INSUF_EXPAN_LVL, mEntry->Expansion());
  2107.  
  2108. return false; // normal client can't teleport to this map...
  2109. }
  2110. else
  2111. sLog->outDebug(LOG_FILTER_MAPS, "Player %s is being teleported to map %u", GetName(), mapid);
  2112.  
  2113. // reset movement flags at teleport, because player will continue move with these flags after teleport
  2114. SetUnitMovementFlags(0);
  2115. DisableSpline();
  2116.  
  2117. if (m_transport)
  2118. {
  2119. if (options & TELE_TO_NOT_LEAVE_TRANSPORT)
  2120. AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
  2121. else
  2122. {
  2123. m_transport->RemovePassenger(this);
  2124. m_transport = NULL;
  2125. m_movementInfo.t_pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f);
  2126. m_movementInfo.t_time = 0;
  2127. m_movementInfo.t_seat = -1;
  2128. }
  2129. }
  2130.  
  2131. // The player was ported to another map and loses the duel immediately.
  2132. // We have to perform this check before the teleport, otherwise the
  2133. // ObjectAccessor won't find the flag.
  2134. if (duel && GetMapId() != mapid && GetMap()->GetGameObject(GetUInt64Value(PLAYER_DUEL_ARBITER)))
  2135. DuelComplete(DUEL_FLED);
  2136.  
  2137. if (GetMapId() == mapid)
  2138. {
  2139. //lets reset far teleport flag if it wasn't reset during chained teleports
  2140. SetSemaphoreTeleportFar(false);
  2141. //setup delayed teleport flag
  2142. SetDelayedTeleportFlag(IsCanDelayTeleport());
  2143. //if teleport spell is casted in Unit::Update() func
  2144. //then we need to delay it until update process will be finished
  2145. if (IsHasDelayedTeleport())
  2146. {
  2147. SetSemaphoreTeleportNear(true);
  2148. //lets save teleport destination for player
  2149. m_teleport_dest = WorldLocation(mapid, x, y, z, orientation);
  2150. m_teleport_options = options;
  2151. return true;
  2152. }
  2153.  
  2154. if (!(options & TELE_TO_NOT_UNSUMMON_PET))
  2155. {
  2156. //same map, only remove pet if out of range for new position
  2157. if (pet && !pet->IsWithinDist3d(x, y, z, GetMap()->GetVisibilityRange()))
  2158. UnsummonPetTemporaryIfAny();
  2159. }
  2160.  
  2161. if (!(options & TELE_TO_NOT_LEAVE_COMBAT))
  2162. CombatStop();
  2163.  
  2164. // this will be used instead of the current location in SaveToDB
  2165. m_teleport_dest = WorldLocation(mapid, x, y, z, orientation);
  2166. SetFallInformation(0, z);
  2167.  
  2168. // code for finish transfer called in WorldSession::HandleMovementOpcodes()
  2169. // at client packet MSG_MOVE_TELEPORT_ACK
  2170. SetSemaphoreTeleportNear(true);
  2171. // near teleport, triggering send MSG_MOVE_TELEPORT_ACK from client at landing
  2172. if (!GetSession()->PlayerLogout())
  2173. {
  2174. Position oldPos;
  2175. GetPosition(&oldPos);
  2176. Relocate(x, y, z, orientation);
  2177. SendTeleportAckPacket();
  2178. SendTeleportPacket(oldPos); // this automatically relocates to oldPos in order to broadcast the packet in the right place
  2179. }
  2180. }
  2181. else
  2182. {
  2183. if (getClass() == CLASS_DEATH_KNIGHT && GetMapId() == 609 && !isGameMaster() && !HasSpell(50977))
  2184. return false;
  2185.  
  2186. // far teleport to another map
  2187. Map* oldmap = IsInWorld() ? GetMap() : NULL;
  2188. // check if we can enter before stopping combat / removing pet / totems / interrupting spells
  2189.  
  2190. // Check enter rights before map getting to avoid creating instance copy for player
  2191. // this check not dependent from map instance copy and same for all instance copies of selected map
  2192. if (!sMapMgr->CanPlayerEnter(mapid, this, false))
  2193. return false;
  2194.  
  2195. //I think this always returns true. Correct me if I am wrong.
  2196. // If the map is not created, assume it is possible to enter it.
  2197. // It will be created in the WorldPortAck.
  2198. //Map* map = sMapMgr->FindBaseNonInstanceMap(mapid);
  2199. //if (!map || map->CanEnter(this))
  2200. {
  2201. //lets reset near teleport flag if it wasn't reset during chained teleports
  2202. SetSemaphoreTeleportNear(false);
  2203. //setup delayed teleport flag
  2204. SetDelayedTeleportFlag(IsCanDelayTeleport());
  2205. //if teleport spell is casted in Unit::Update() func
  2206. //then we need to delay it until update process will be finished
  2207. if (IsHasDelayedTeleport())
  2208. {
  2209. SetSemaphoreTeleportFar(true);
  2210. //lets save teleport destination for player
  2211. m_teleport_dest = WorldLocation(mapid, x, y, z, orientation);
  2212. m_teleport_options = options;
  2213. return true;
  2214. }
  2215.  
  2216. SetSelection(0);
  2217.  
  2218. CombatStop();
  2219.  
  2220. ResetContestedPvP();
  2221.  
  2222. // remove player from battleground on far teleport (when changing maps)
  2223. if (Battleground const* bg = GetBattleground())
  2224. {
  2225. // Note: at battleground join battleground id set before teleport
  2226. // and we already will found "current" battleground
  2227. // just need check that this is targeted map or leave
  2228. if (bg->GetMapId() != mapid)
  2229. LeaveBattleground(false); // don't teleport to entry point
  2230. }
  2231.  
  2232. // remove arena spell coldowns/buffs now to also remove pet's cooldowns before it's temporarily unsummoned
  2233. if (mEntry->IsBattleArena())
  2234. {
  2235. RemoveArenaSpellCooldowns(true);
  2236. RemoveArenaAuras();
  2237. if (pet)
  2238. pet->RemoveArenaAuras();
  2239. }
  2240.  
  2241. // remove pet on map change
  2242. if (pet)
  2243. UnsummonPetTemporaryIfAny();
  2244.  
  2245. // remove all dyn objects
  2246. RemoveAllDynObjects();
  2247.  
  2248. // stop spellcasting
  2249. // not attempt interrupt teleportation spell at caster teleport
  2250. if (!(options & TELE_TO_SPELL))
  2251. if (IsNonMeleeSpellCasted(true))
  2252. InterruptNonMeleeSpells(true);
  2253.  
  2254. //remove auras before removing from map...
  2255. RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP | AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING);
  2256.  
  2257. if (!GetSession()->PlayerLogout())
  2258. {
  2259. // send transfer packets
  2260. WorldPacket data(SMSG_TRANSFER_PENDING, 4 + 4 + 4);
  2261. data << uint32(mapid);
  2262. if (m_transport)
  2263. data << m_transport->GetEntry() << GetMapId();
  2264.  
  2265. GetSession()->SendPacket(&data);
  2266. }
  2267.  
  2268. // remove from old map now
  2269. if (oldmap)
  2270. oldmap->RemovePlayerFromMap(this, false);
  2271.  
  2272. // new final coordinates
  2273. float final_x = x;
  2274. float final_y = y;
  2275. float final_z = z;
  2276. float final_o = orientation;
  2277.  
  2278. if (m_transport)
  2279. {
  2280. final_x += m_movementInfo.t_pos.GetPositionX();
  2281. final_y += m_movementInfo.t_pos.GetPositionY();
  2282. final_z += m_movementInfo.t_pos.GetPositionZ();
  2283. final_o += m_movementInfo.t_pos.GetOrientation();
  2284. }
  2285.  
  2286. m_teleport_dest = WorldLocation(mapid, final_x, final_y, final_z, final_o);
  2287. SetFallInformation(0, final_z);
  2288. // if the player is saved before worldportack (at logout for example)
  2289. // this will be used instead of the current location in SaveToDB
  2290.  
  2291. if (!GetSession()->PlayerLogout())
  2292. {
  2293. WorldPacket data(SMSG_NEW_WORLD, 4 + 4 + 4 + 4 + 4);
  2294. data << uint32(mapid);
  2295. if (m_transport)
  2296. data << m_movementInfo.t_pos.PositionXYZOStream();
  2297. else
  2298. data << m_teleport_dest.PositionXYZOStream();
  2299.  
  2300. GetSession()->SendPacket(&data);
  2301. SendSavedInstances();
  2302. }
  2303.  
  2304. // move packet sent by client always after far teleport
  2305. // code for finish transfer to new map called in WorldSession::HandleMoveWorldportAckOpcode at client packet
  2306. SetSemaphoreTeleportFar(true);
  2307. }
  2308. //else
  2309. // return false;
  2310. }
  2311. return true;
  2312. }
  2313.  
  2314. bool Player::TeleportToBGEntryPoint()
  2315. {
  2316. if (m_bgData.joinPos.m_mapId == MAPID_INVALID)
  2317. return false;
  2318.  
  2319. ScheduleDelayedOperation(DELAYED_BG_MOUNT_RESTORE);
  2320. ScheduleDelayedOperation(DELAYED_BG_TAXI_RESTORE);
  2321. ScheduleDelayedOperation(DELAYED_BG_GROUP_RESTORE);
  2322. return TeleportTo(m_bgData.joinPos);
  2323. }
  2324.  
  2325. void Player::ProcessDelayedOperations()
  2326. {
  2327. if (m_DelayedOperations == 0)
  2328. return;
  2329.  
  2330. if (m_DelayedOperations & DELAYED_RESURRECT_PLAYER)
  2331. {
  2332. ResurrectPlayer(0.0f, false);
  2333.  
  2334. if (GetMaxHealth() > m_resurrectHealth)
  2335. SetHealth(m_resurrectHealth);
  2336. else
  2337. SetFullHealth();
  2338.  
  2339. if (GetMaxPower(POWER_MANA) > m_resurrectMana)
  2340. SetPower(POWER_MANA, m_resurrectMana);
  2341. else
  2342. SetPower(POWER_MANA, GetMaxPower(POWER_MANA));
  2343.  
  2344. SetPower(POWER_RAGE, 0);
  2345. SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY));
  2346.  
  2347. SpawnCorpseBones();
  2348. }
  2349.  
  2350. if (m_DelayedOperations & DELAYED_SAVE_PLAYER)
  2351. SaveToDB();
  2352.  
  2353. if (m_DelayedOperations & DELAYED_SPELL_CAST_DESERTER)
  2354. CastSpell(this, 26013, true); // Deserter
  2355.  
  2356. if (m_DelayedOperations & DELAYED_BG_MOUNT_RESTORE)
  2357. {
  2358. if (m_bgData.mountSpell)
  2359. {
  2360. CastSpell(this, m_bgData.mountSpell, true);
  2361. m_bgData.mountSpell = 0;
  2362. }
  2363. }
  2364.  
  2365. if (m_DelayedOperations & DELAYED_BG_TAXI_RESTORE)
  2366. {
  2367. if (m_bgData.HasTaxiPath())
  2368. {
  2369. m_taxi.AddTaxiDestination(m_bgData.taxiPath[0]);
  2370. m_taxi.AddTaxiDestination(m_bgData.taxiPath[1]);
  2371. m_bgData.ClearTaxiPath();
  2372.  
  2373. ContinueTaxiFlight();
  2374. }
  2375. }
  2376.  
  2377. if (m_DelayedOperations & DELAYED_BG_GROUP_RESTORE)
  2378. {
  2379. if (Group *g = GetGroup())
  2380. g->SendUpdateToPlayer(GetGUID());
  2381. }
  2382.  
  2383. //we have executed ALL delayed ops, so clear the flag
  2384. m_DelayedOperations = 0;
  2385. }
  2386.  
  2387. void Player::AddToWorld()
  2388. {
  2389. ///- Do not add/remove the player from the object storage
  2390. ///- It will crash when updating the ObjectAccessor
  2391. ///- The player should only be added when logging in
  2392. Unit::AddToWorld();
  2393.  
  2394. for (uint8 i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i)
  2395. if (m_items[i])
  2396. m_items[i]->AddToWorld();
  2397. }
  2398.  
  2399. void Player::RemoveFromWorld()
  2400. {
  2401. // cleanup
  2402. if (IsInWorld())
  2403. {
  2404. ///- Release charmed creatures, unsummon totems and remove pets/guardians
  2405. StopCastingCharm();
  2406. StopCastingBindSight();
  2407. UnsummonPetTemporaryIfAny();
  2408. sOutdoorPvPMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
  2409. }
  2410.  
  2411. ///- Do not add/remove the player from the object storage
  2412. ///- It will crash when updating the ObjectAccessor
  2413. ///- The player should only be removed when logging out
  2414. Unit::RemoveFromWorld();
  2415.  
  2416. for (uint8 i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i)
  2417. {
  2418. if (m_items[i])
  2419. m_items[i]->RemoveFromWorld();
  2420. }
  2421.  
  2422. for (ItemMap::iterator iter = mMitems.begin(); iter != mMitems.end(); ++iter)
  2423. iter->second->RemoveFromWorld();
  2424.  
  2425. if (m_uint32Values)
  2426. {
  2427. if (WorldObject* viewpoint = GetViewpoint())
  2428. {
  2429. sLog->outError(LOG_FILTER_PLAYER, "Player %s has viewpoint %u %u when removed from world", GetName(), viewpoint->GetEntry(), viewpoint->GetTypeId());
  2430. SetViewpoint(viewpoint, false);
  2431. }
  2432. }
  2433. }
  2434.  
  2435. void Player::RegenerateAll()
  2436. {
  2437. //if (m_regenTimer <= 500)
  2438. // return;
  2439.  
  2440. m_regenTimerCount += m_regenTimer;
  2441.  
  2442. Regenerate(POWER_ENERGY);
  2443.  
  2444. Regenerate(POWER_MANA);
  2445.  
  2446. // Runes act as cooldowns, and they don't need to send any data
  2447. if (getClass() == CLASS_DEATH_KNIGHT)
  2448. for (uint8 i = 0; i < MAX_RUNES; ++i)
  2449. if (uint32 cd = GetRuneCooldown(i))
  2450. SetRuneCooldown(i, (cd > m_regenTimer) ? cd - m_regenTimer : 0);
  2451.  
  2452. if (m_regenTimerCount >= 2000)
  2453. {
  2454. // Not in combat or they have regeneration
  2455. if (!isInCombat() || IsPolymorphed() || m_baseHealthRegen ||
  2456. HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT) ||
  2457. HasAuraType(SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT))
  2458. {
  2459. RegenerateHealth();
  2460. }
  2461.  
  2462. Regenerate(POWER_RAGE);
  2463. if (getClass() == CLASS_DEATH_KNIGHT)
  2464. Regenerate(POWER_RUNIC_POWER);
  2465.  
  2466. m_regenTimerCount -= 2000;
  2467. }
  2468.  
  2469. m_regenTimer = 0;
  2470. }
  2471.  
  2472. void Player::Regenerate(Powers power)
  2473. {
  2474. uint32 maxValue = GetMaxPower(power);
  2475. if (!maxValue)
  2476. return;
  2477.  
  2478. uint32 curValue = GetPower(power);
  2479.  
  2480. // TODO: possible use of miscvalueb instead of amount
  2481. if (HasAuraTypeWithValue(SPELL_AURA_PREVENT_REGENERATE_POWER, power))
  2482. return;
  2483.  
  2484. float addvalue = 0.0f;
  2485.  
  2486. switch (power)
  2487. {
  2488. case POWER_MANA:
  2489. {
  2490. bool recentCast = IsUnderLastManaUseEffect();
  2491. float ManaIncreaseRate = sWorld->getRate(RATE_POWER_MANA);
  2492.  
  2493. if (getLevel() < 15)
  2494. ManaIncreaseRate = sWorld->getRate(RATE_POWER_MANA) * (2.066f - (getLevel() * 0.066f));
  2495.  
  2496. if (recentCast) // Trinity Updates Mana in intervals of 2s, which is correct
  2497. addvalue += GetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER) * ManaIncreaseRate * 0.001f * m_regenTimer;
  2498. else
  2499. addvalue += GetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER) * ManaIncreaseRate * 0.001f * m_regenTimer;
  2500. } break;
  2501. case POWER_RAGE: // Regenerate rage
  2502. {
  2503. if (!isInCombat() && !HasAuraType(SPELL_AURA_INTERRUPT_REGEN))
  2504. {
  2505. float RageDecreaseRate = sWorld->getRate(RATE_POWER_RAGE_LOSS);
  2506. addvalue += -20 * RageDecreaseRate; // 2 rage by tick (= 2 seconds => 1 rage/sec)
  2507. }
  2508. } break;
  2509. case POWER_ENERGY: // Regenerate energy (rogue)
  2510. addvalue += 0.01f * m_regenTimer * sWorld->getRate(RATE_POWER_ENERGY);
  2511. break;
  2512. case POWER_RUNIC_POWER:
  2513. {
  2514. if (!isInCombat() && !HasAuraType(SPELL_AURA_INTERRUPT_REGEN))
  2515. {
  2516. float RunicPowerDecreaseRate = sWorld->getRate(RATE_POWER_RUNICPOWER_LOSS);
  2517. addvalue += -30 * RunicPowerDecreaseRate; // 3 RunicPower by tick
  2518. }
  2519. } break;
  2520. case POWER_RUNE:
  2521. case POWER_FOCUS:
  2522. case POWER_HAPPINESS:
  2523. case POWER_HEALTH:
  2524. break;
  2525. default:
  2526. break;
  2527. }
  2528.  
  2529. // Mana regen calculated in Player::UpdateManaRegen()
  2530. if (power != POWER_MANA)
  2531. {
  2532. AuraEffectList const& ModPowerRegenPCTAuras = GetAuraEffectsByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT);
  2533. for (AuraEffectList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
  2534. if (Powers((*i)->GetMiscValue()) == power)
  2535. AddPctN(addvalue, (*i)->GetAmount());
  2536.  
  2537. // Butchery requires combat for this effect
  2538. if (power != POWER_RUNIC_POWER || isInCombat())
  2539. addvalue += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, power) * ((power != POWER_ENERGY) ? m_regenTimerCount : m_regenTimer) / (5 * IN_MILLISECONDS);
  2540. }
  2541.  
  2542. if (addvalue < 0.0f)
  2543. {
  2544. if (curValue == 0)
  2545. return;
  2546. }
  2547. else if (addvalue > 0.0f)
  2548. {
  2549. if (curValue == maxValue)
  2550. return;
  2551. }
  2552. else
  2553. return;
  2554.  
  2555. addvalue += m_powerFraction[power];
  2556. uint32 integerValue = uint32(fabs(addvalue));
  2557.  
  2558. if (addvalue < 0.0f)
  2559. {
  2560. if (curValue > integerValue)
  2561. {
  2562. curValue -= integerValue;
  2563. m_powerFraction[power] = addvalue + integerValue;
  2564. }
  2565. else
  2566. {
  2567. curValue = 0;
  2568. m_powerFraction[power] = 0;
  2569. }
  2570. }
  2571. else
  2572. {
  2573. curValue += integerValue;
  2574.  
  2575. if (curValue > maxValue)
  2576. {
  2577. curValue = maxValue;
  2578. m_powerFraction[power] = 0;
  2579. }
  2580. else
  2581. m_powerFraction[power] = addvalue - integerValue;
  2582. }
  2583. if (m_regenTimerCount >= 2000)
  2584. SetPower(power, curValue);
  2585. else
  2586. UpdateUInt32Value(UNIT_FIELD_POWER1 + power, curValue);
  2587. }
  2588.  
  2589. void Player::RegenerateHealth()
  2590. {
  2591. uint32 curValue = GetHealth();
  2592. uint32 maxValue = GetMaxHealth();
  2593.  
  2594. if (curValue >= maxValue)
  2595. return;
  2596.  
  2597. float HealthIncreaseRate = sWorld->getRate(RATE_HEALTH);
  2598.  
  2599. if (getLevel() < 15)
  2600. HealthIncreaseRate = sWorld->getRate(RATE_HEALTH) * (2.066f - (getLevel() * 0.066f));
  2601.  
  2602. float addvalue = 0.0f;
  2603.  
  2604. // polymorphed case
  2605. if (IsPolymorphed())
  2606. addvalue = (float)GetMaxHealth()/3;
  2607. // normal regen case (maybe partly in combat case)
  2608. else if (!isInCombat() || HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT))
  2609. {
  2610. addvalue = OCTRegenHPPerSpirit() * HealthIncreaseRate;
  2611. if (!isInCombat())
  2612. {
  2613. AuraEffectList const& mModHealthRegenPct = GetAuraEffectsByType(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT);
  2614. for (AuraEffectList::const_iterator i = mModHealthRegenPct.begin(); i != mModHealthRegenPct.end(); ++i)
  2615. AddPctN(addvalue, (*i)->GetAmount());
  2616.  
  2617. addvalue += GetTotalAuraModifier(SPELL_AURA_MOD_REGEN) * 2 * IN_MILLISECONDS / (5 * IN_MILLISECONDS);
  2618. }
  2619. else if (HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT))
  2620. ApplyPctN(addvalue, GetTotalAuraModifier(SPELL_AURA_MOD_REGEN_DURING_COMBAT));
  2621.  
  2622. if (!IsStandState())
  2623. addvalue *= 1.5f;
  2624. }
  2625.  
  2626. // always regeneration bonus (including combat)
  2627. addvalue += GetTotalAuraModifier(SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT);
  2628. addvalue += m_baseHealthRegen / 2.5f;
  2629.  
  2630. if (addvalue < 0)
  2631. addvalue = 0;
  2632.  
  2633. ModifyHealth(int32(addvalue));
  2634. }
  2635.  
  2636. void Player::ResetAllPowers()
  2637. {
  2638. SetHealth(GetMaxHealth());
  2639. switch (getPowerType())
  2640. {
  2641. case POWER_MANA:
  2642. SetPower(POWER_MANA, GetMaxPower(POWER_MANA));
  2643. break;
  2644. case POWER_RAGE:
  2645. SetPower(POWER_RAGE, 0);
  2646. break;
  2647. case POWER_ENERGY:
  2648. SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY));
  2649. break;
  2650. case POWER_RUNIC_POWER:
  2651. SetPower(POWER_RUNIC_POWER, 0);
  2652. break;
  2653. default:
  2654. break;
  2655. }
  2656. }
  2657.  
  2658. bool Player::CanInteractWithQuestGiver(Object* questGiver)
  2659. {
  2660. switch (questGiver->GetTypeId())
  2661. {
  2662. case TYPEID_UNIT:
  2663. return GetNPCIfCanInteractWith(questGiver->GetGUID(), UNIT_NPC_FLAG_QUESTGIVER) != NULL;
  2664. case TYPEID_GAMEOBJECT:
  2665. return GetGameObjectIfCanInteractWith(questGiver->GetGUID(), GAMEOBJECT_TYPE_QUESTGIVER) != NULL;
  2666. case TYPEID_PLAYER:
  2667. return isAlive() && questGiver->ToPlayer()->isAlive();
  2668. case TYPEID_ITEM:
  2669. return isAlive();
  2670. default:
  2671. break;
  2672. }
  2673. return false;
  2674. }
  2675.  
  2676. Creature* Player::GetNPCIfCanInteractWith(uint64 guid, uint32 npcflagmask)
  2677. {
  2678. // unit checks
  2679. if (!guid)
  2680. return NULL;
  2681.  
  2682. if (!IsInWorld())
  2683. return NULL;
  2684.  
  2685. if (isInFlight())
  2686. return NULL;
  2687.  
  2688. // exist (we need look pets also for some interaction (quest/etc)
  2689. Creature* creature = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, guid);
  2690. if (!creature)
  2691. return NULL;
  2692.  
  2693. // Deathstate checks
  2694. if (!isAlive() && !(creature->GetCreatureTemplate()->type_flags & CREATURE_TYPEFLAGS_GHOST))
  2695. return NULL;
  2696.  
  2697. // alive or spirit healer
  2698. if (!creature->isAlive() && !(creature->GetCreatureTemplate()->type_flags & CREATURE_TYPEFLAGS_DEAD_INTERACT))
  2699. return NULL;
  2700.  
  2701. // appropriate npc type
  2702. if (npcflagmask && !creature->HasFlag(UNIT_NPC_FLAGS, npcflagmask))
  2703. return NULL;
  2704.  
  2705. // not allow interaction under control, but allow with own pets
  2706. if (creature->GetCharmerGUID())
  2707. return NULL;
  2708.  
  2709. // not enemy
  2710. if (creature->IsHostileTo(this))
  2711. return NULL;
  2712.  
  2713. // not unfriendly
  2714. if (FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(creature->getFaction()))
  2715. if (factionTemplate->faction)
  2716. if (FactionEntry const* faction = sFactionStore.LookupEntry(factionTemplate->faction))
  2717. if (faction->reputationListID >= 0 && GetReputationMgr().GetRank(faction) <= REP_UNFRIENDLY)
  2718. return NULL;
  2719.  
  2720. // not too far
  2721. if (!creature->IsWithinDistInMap(this, INTERACTION_DISTANCE))
  2722. return NULL;
  2723.  
  2724. return creature;
  2725. }
  2726.  
  2727. GameObject* Player::GetGameObjectIfCanInteractWith(uint64 guid, GameobjectTypes type) const
  2728. {
  2729. if (GameObject* go = GetMap()->GetGameObject(guid))
  2730. {
  2731. if (go->GetGoType() == type)
  2732. {
  2733. float maxdist;
  2734. switch (type)
  2735. {
  2736. // TODO: find out how the client calculates the maximal usage distance to spellless working
  2737. // gameobjects like guildbanks and mailboxes - 10.0 is a just an abitrary choosen number
  2738. case GAMEOBJECT_TYPE_GUILD_BANK:
  2739. case GAMEOBJECT_TYPE_MAILBOX:
  2740. maxdist = 10.0f;
  2741. break;
  2742. case GAMEOBJECT_TYPE_FISHINGHOLE:
  2743. maxdist = 20.0f+CONTACT_DISTANCE; // max spell range
  2744. break;
  2745. default:
  2746. maxdist = INTERACTION_DISTANCE;
  2747. break;
  2748. }
  2749.  
  2750. if (go->IsWithinDistInMap(this, maxdist))
  2751. return go;
  2752.  
  2753. sLog->outDebug(LOG_FILTER_MAPS, "IsGameObjectOfTypeInRange: GameObject '%s' [GUID: %u] is too far away from player %s [GUID: %u] to be used by him (distance=%f, maximal 10 is allowed)", go->GetGOInfo()->name.c_str(),
  2754. go->GetGUIDLow(), GetName(), GetGUIDLow(), go->GetDistance(this));
  2755. }
  2756. }
  2757. return NULL;
  2758. }
  2759.  
  2760. bool Player::IsUnderWater() const
  2761. {
  2762. return IsInWater() &&
  2763. GetPositionZ() < (GetBaseMap()->GetWaterLevel(GetPositionX(), GetPositionY())-2);
  2764. }
  2765.  
  2766. void Player::SetInWater(bool apply)
  2767. {
  2768. if (m_isInWater == apply)
  2769. return;
  2770.  
  2771. //define player in water by opcodes
  2772. //move player's guid into HateOfflineList of those mobs
  2773. //which can't swim and move guid back into ThreatList when
  2774. //on surface.
  2775. //TODO: exist also swimming mobs, and function must be symmetric to enter/leave water
  2776. m_isInWater = apply;
  2777.  
  2778. // remove auras that need water/land
  2779. RemoveAurasWithInterruptFlags(apply ? AURA_INTERRUPT_FLAG_NOT_ABOVEWATER : AURA_INTERRUPT_FLAG_NOT_UNDERWATER);
  2780.  
  2781. getHostileRefManager().updateThreatTables();
  2782. }
  2783.  
  2784. void Player::SetGameMaster(bool on)
  2785. {
  2786. if (on)
  2787. {
  2788. m_ExtraFlags |= PLAYER_EXTRA_GM_ON;
  2789. setFaction(35);
  2790. SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM);
  2791. SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_CHEAT_SPELLS);
  2792.  
  2793. if (Pet* pet = GetPet())
  2794. {
  2795. pet->setFaction(35);
  2796. pet->getHostileRefManager().setOnlineOfflineState(false);
  2797. }
  2798.  
  2799. RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
  2800. ResetContestedPvP();
  2801.  
  2802. getHostileRefManager().setOnlineOfflineState(false);
  2803. CombatStopWithPets();
  2804.  
  2805. SetPhaseMask(uint32(PHASEMASK_ANYWHERE), false); // see and visible in all phases
  2806. m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GM, GetSession()->GetSecurity());
  2807. }
  2808. else
  2809. {
  2810. // restore phase
  2811. uint32 newPhase = 0;
  2812. AuraEffectList const& phases = GetAuraEffectsByType(SPELL_AURA_PHASE);
  2813. if (!phases.empty())
  2814. for (AuraEffectList::const_iterator itr = phases.begin(); itr != phases.end(); ++itr)
  2815. newPhase |= (*itr)->GetMiscValue();
  2816.  
  2817. if (!newPhase)
  2818. newPhase = PHASEMASK_NORMAL;
  2819.  
  2820. SetPhaseMask(newPhase, false);
  2821.  
  2822. m_ExtraFlags &= ~ PLAYER_EXTRA_GM_ON;
  2823. setFactionForRace(getRace());
  2824. RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM);
  2825. RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_CHEAT_SPELLS);
  2826.  
  2827. if (Pet* pet = GetPet())
  2828. {
  2829. pet->setFaction(getFaction());
  2830. pet->getHostileRefManager().setOnlineOfflineState(true);
  2831. }
  2832.  
  2833. // restore FFA PvP Server state
  2834. if (sWorld->IsFFAPvPRealm())
  2835. SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP);
  2836.  
  2837. // restore FFA PvP area state, remove not allowed for GM mounts
  2838. UpdateArea(m_areaUpdateId);
  2839.  
  2840. getHostileRefManager().setOnlineOfflineState(true);
  2841. m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GM, SEC_PLAYER);
  2842. }
  2843.  
  2844. UpdateObjectVisibility();
  2845. }
  2846.  
  2847. void Player::SetGMVisible(bool on)
  2848. {
  2849. if (on)
  2850. {
  2851. m_ExtraFlags &= ~PLAYER_EXTRA_GM_INVISIBLE; //remove flag
  2852. m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GM, SEC_PLAYER);
  2853. }
  2854. else
  2855. {
  2856. m_ExtraFlags |= PLAYER_EXTRA_GM_INVISIBLE; //add flag
  2857.  
  2858. SetAcceptWhispers(false);
  2859. SetGameMaster(true);
  2860.  
  2861. m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GM, GetSession()->GetSecurity());
  2862. }
  2863. }
  2864.  
  2865. bool Player::IsGroupVisibleFor(Player const* p) const
  2866. {
  2867. switch (sWorld->getIntConfig(CONFIG_GROUP_VISIBILITY))
  2868. {
  2869. default: return IsInSameGroupWith(p);
  2870. case 1: return IsInSameRaidWith(p);
  2871. case 2: return GetTeam() == p->GetTeam();
  2872. }
  2873. }
  2874.  
  2875. bool Player::IsInSameGroupWith(Player const* p) const
  2876. {
  2877. return p == this || (GetGroup() != NULL &&
  2878. GetGroup() == p->GetGroup() &&
  2879. GetGroup()->SameSubGroup(this, p));
  2880. }
  2881.  
  2882. ///- If the player is invited, remove him. If the group if then only 1 person, disband the group.
  2883. /// \todo Shouldn't we also check if there is no other invitees before disbanding the group?
  2884. void Player::UninviteFromGroup()
  2885. {
  2886. Group* group = GetGroupInvite();
  2887. if (!group)
  2888. return;
  2889.  
  2890. group->RemoveInvite(this);
  2891.  
  2892. if (group->GetMembersCount() <= 1) // group has just 1 member => disband
  2893. {
  2894. if (group->IsCreated())
  2895. {
  2896. group->Disband(true);
  2897. }
  2898. else
  2899. {
  2900. group->RemoveAllInvites();
  2901. delete group;
  2902. }
  2903. }
  2904. }
  2905.  
  2906. void Player::RemoveFromGroup(Group* group, uint64 guid, RemoveMethod method /* = GROUP_REMOVEMETHOD_DEFAULT*/, uint64 kicker /* = 0 */, const char* reason /* = NULL */)
  2907. {
  2908. if (group)
  2909. {
  2910. group->RemoveMember(guid, method, kicker, reason);
  2911. group = NULL;
  2912. }
  2913. }
  2914.  
  2915. void Player::SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 BonusXP, bool recruitAFriend, float /*group_rate*/)
  2916. {
  2917. WorldPacket data(SMSG_LOG_XPGAIN, 21); // guess size?
  2918. data << uint64(victim ? victim->GetGUID() : 0); // guid
  2919. data << uint32(GivenXP + BonusXP); // given experience
  2920. data << uint8(victim ? 0 : 1); // 00-kill_xp type, 01-non_kill_xp type
  2921.  
  2922. if (victim)
  2923. {
  2924. data << uint32(GivenXP); // experience without bonus
  2925.  
  2926. // should use group_rate here but can't figure out how
  2927. data << float(1); // 1 - none 0 - 100% group bonus output
  2928. }
  2929.  
  2930. data << uint8(recruitAFriend ? 1 : 0); // does the GivenXP include a RaF bonus?
  2931. GetSession()->SendPacket(&data);
  2932. }
  2933.  
  2934. void Player::GiveXP(uint32 xp, Unit* victim, float group_rate)
  2935. {
  2936. if (xp < 1)
  2937. return;
  2938.  
  2939. if (!isAlive() && !GetBattlegroundId())
  2940. return;
  2941.  
  2942. if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_NO_XP_GAIN))
  2943. return;
  2944.  
  2945. if (victim && victim->GetTypeId() == TYPEID_UNIT && !victim->ToCreature()->hasLootRecipient())
  2946. return;
  2947.  
  2948. uint8 level = getLevel();
  2949.  
  2950. sScriptMgr->OnGivePlayerXP(this, xp, victim);
  2951.  
  2952. // Favored experience increase START
  2953. uint32 zone = GetZoneId();
  2954. float favored_exp_mult = 0;
  2955. if ((HasAura(32096) || HasAura(32098)) && (zone == 3483 || zone == 3562 || zone == 3836 || zone == 3713 || zone == 3714))
  2956. favored_exp_mult = 0.05f; // Thrallmar's Favor and Honor Hold's Favor
  2957. xp = uint32(xp * (1 + favored_exp_mult));
  2958. // Favored experience increase END
  2959.  
  2960. // XP to money conversion processed in Player::RewardQuest
  2961. if (level >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
  2962. return;
  2963.  
  2964. uint32 bonus_xp = 0;
  2965. bool recruitAFriend = GetsRecruitAFriendBonus(true);
  2966.  
  2967. // RaF does NOT stack with rested experience
  2968. if (recruitAFriend)
  2969. bonus_xp = 2 * xp; // xp + bonus_xp must add up to 3 * xp for RaF; calculation for quests done client-side
  2970. else
  2971. bonus_xp = victim ? GetXPRestBonus(xp) : 0; // XP resting bonus
  2972.  
  2973. SendLogXPGain(xp, victim, bonus_xp, recruitAFriend, group_rate);
  2974.  
  2975. uint32 curXP = GetUInt32Value(PLAYER_XP);
  2976. uint32 nextLvlXP = GetUInt32Value(PLAYER_NEXT_LEVEL_XP);
  2977. uint32 newXP = curXP + xp + bonus_xp;
  2978.  
  2979. while (newXP >= nextLvlXP && level < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
  2980. {
  2981. newXP -= nextLvlXP;
  2982.  
  2983. if (level < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
  2984. GiveLevel(level + 1);
  2985.  
  2986. level = getLevel();
  2987. nextLvlXP = GetUInt32Value(PLAYER_NEXT_LEVEL_XP);
  2988. }
  2989.  
  2990. SetUInt32Value(PLAYER_XP, newXP);
  2991. }
  2992.  
  2993. // Update player to next level
  2994. // Current player experience not update (must be update by caller)
  2995. void Player::GiveLevel(uint8 level)
  2996. {
  2997. uint8 oldLevel = getLevel();
  2998. if (level == oldLevel)
  2999. return;
  3000.  
  3001. PlayerLevelInfo info;
  3002. sObjectMgr->GetPlayerLevelInfo(getRace(), getClass(), level, &info);
  3003.  
  3004. PlayerClassLevelInfo classInfo;
  3005. sObjectMgr->GetPlayerClassLevelInfo(getClass(), level, &classInfo);
  3006.  
  3007. // send levelup info to client
  3008. WorldPacket data(SMSG_LEVELUP_INFO, (4+4+MAX_POWERS*4+MAX_STATS*4));
  3009. data << uint32(level);
  3010. data << uint32(int32(classInfo.basehealth) - int32(GetCreateHealth()));
  3011. // for (int i = 0; i < MAX_POWERS; ++i) // Powers loop (0-6)
  3012. data << uint32(int32(classInfo.basemana) - int32(GetCreateMana()));
  3013. data << uint32(0);
  3014. data << uint32(0);
  3015. data << uint32(0);
  3016. data << uint32(0);
  3017. data << uint32(0);
  3018. data << uint32(0);
  3019. // end for
  3020. for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i) // Stats loop (0-4)
  3021. data << uint32(int32(info.stats[i]) - GetCreateStat(Stats(i)));
  3022.  
  3023. GetSession()->SendPacket(&data);
  3024.  
  3025. SetUInt32Value(PLAYER_NEXT_LEVEL_XP, sObjectMgr->GetXPForLevel(level));
  3026.  
  3027. //update level, max level of skills
  3028. m_Played_time[PLAYED_TIME_LEVEL] = 0; // Level Played Time reset
  3029.  
  3030. _ApplyAllLevelScaleItemMods(false);
  3031.  
  3032. SetLevel(level);
  3033.  
  3034. UpdateSkillsForLevel();
  3035.  
  3036. // save base values (bonuses already included in stored stats
  3037. for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
  3038. SetCreateStat(Stats(i), info.stats[i]);
  3039.  
  3040. SetCreateHealth(classInfo.basehealth);
  3041. SetCreateMana(classInfo.basemana);
  3042.  
  3043. InitTalentForLevel();
  3044. InitTaxiNodesForLevel();
  3045. InitGlyphsForLevel();
  3046.  
  3047. UpdateAllStats();
  3048.  
  3049. if (sWorld->getBoolConfig(CONFIG_ALWAYS_MAXSKILL)) // Max weapon skill when leveling up
  3050. UpdateSkillsToMaxSkillsForLevel();
  3051.  
  3052. // set current level health and mana/energy to maximum after applying all mods.
  3053. SetFullHealth();
  3054. SetPower(POWER_MANA, GetMaxPower(POWER_MANA));
  3055. SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY));
  3056. if (GetPower(POWER_RAGE) > GetMaxPower(POWER_RAGE))
  3057. SetPower(POWER_RAGE, GetMaxPower(POWER_RAGE));
  3058. SetPower(POWER_FOCUS, 0);
  3059. SetPower(POWER_HAPPINESS, 0);
  3060.  
  3061. _ApplyAllLevelScaleItemMods(true);
  3062.  
  3063. // update level to hunter/summon pet
  3064. if (Pet* pet = GetPet())
  3065. pet->SynchronizeLevelWithOwner();
  3066.  
  3067. if (MailLevelReward const* mailReward = sObjectMgr->GetMailLevelReward(level, getRaceMask()))
  3068. {
  3069. //- TODO: Poor design of mail system
  3070. SQLTransaction trans = CharacterDatabase.BeginTransaction();
  3071. MailDraft(mailReward->mailTemplateId).SendMailTo(trans, this, MailSender(MAIL_CREATURE, mailReward->senderEntry));
  3072. CharacterDatabase.CommitTransaction(trans);
  3073. }
  3074.  
  3075. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL);
  3076.  
  3077. // Refer-A-Friend
  3078. if (GetSession()->GetRecruiterId())
  3079. if (level < sWorld->getIntConfig(CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL))
  3080. if (level % 2 == 0)
  3081. {
  3082. ++m_grantableLevels;
  3083.  
  3084. if (!HasByteFlag(PLAYER_FIELD_BYTES, 1, 0x01))
  3085. SetByteFlag(PLAYER_FIELD_BYTES, 1, 0x01);
  3086. }
  3087.  
  3088. sScriptMgr->OnPlayerLevelChanged(this, oldLevel);
  3089. }
  3090.  
  3091. void Player::InitTalentForLevel()
  3092. {
  3093. uint8 level = getLevel();
  3094. // talents base at level diff (talents = level - 9 but some can be used already)
  3095. if (level < 10)
  3096. {
  3097. // Remove all talent points
  3098. if (m_usedTalentCount > 0) // Free any used talents
  3099. {
  3100. resetTalents(true);
  3101. SetFreeTalentPoints(0);
  3102. }
  3103. }
  3104. else
  3105. {
  3106. if (level < sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL) || m_specsCount == 0)
  3107. {
  3108. m_specsCount = 1;
  3109. m_activeSpec = 0;
  3110. }
  3111.  
  3112. uint32 talentPointsForLevel = CalculateTalentsPoints();
  3113.  
  3114. // if used more that have then reset
  3115. if (m_usedTalentCount > talentPointsForLevel)
  3116. {
  3117. if (!AccountMgr::IsAdminAccount(GetSession()->GetSecurity()))
  3118. resetTalents(true);
  3119. else
  3120. SetFreeTalentPoints(0);
  3121. }
  3122. // else update amount of free points
  3123. else
  3124. SetFreeTalentPoints(talentPointsForLevel - m_usedTalentCount);
  3125. }
  3126.  
  3127. if (!GetSession()->PlayerLoading())
  3128. SendTalentsInfoData(false); // update at client
  3129. }
  3130.  
  3131. void Player::InitStatsForLevel(bool reapplyMods)
  3132. {
  3133. if (reapplyMods) //reapply stats values only on .reset stats (level) command
  3134. _RemoveAllStatBonuses();
  3135.  
  3136. PlayerClassLevelInfo classInfo;
  3137. sObjectMgr->GetPlayerClassLevelInfo(getClass(), getLevel(), &classInfo);
  3138.  
  3139. PlayerLevelInfo info;
  3140. sObjectMgr->GetPlayerLevelInfo(getRace(), getClass(), getLevel(), &info);
  3141.  
  3142. SetUInt32Value(PLAYER_FIELD_MAX_LEVEL, sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL));
  3143. SetUInt32Value(PLAYER_NEXT_LEVEL_XP, sObjectMgr->GetXPForLevel(getLevel()));
  3144.  
  3145. // reset before any aura state sources (health set/aura apply)
  3146. SetUInt32Value(UNIT_FIELD_AURASTATE, 0);
  3147.  
  3148. UpdateSkillsForLevel();
  3149.  
  3150. // set default cast time multiplier
  3151. SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f);
  3152.  
  3153. // reset size before reapply auras
  3154. SetObjectScale(1.0f);
  3155.  
  3156. // save base values (bonuses already included in stored stats
  3157. for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
  3158. SetCreateStat(Stats(i), info.stats[i]);
  3159.  
  3160. for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
  3161. SetStat(Stats(i), info.stats[i]);
  3162.  
  3163. SetCreateHealth(classInfo.basehealth);
  3164.  
  3165. //set create powers
  3166. SetCreateMana(classInfo.basemana);
  3167.  
  3168. SetArmor(int32(m_createStats[STAT_AGILITY]*2));
  3169.  
  3170. InitStatBuffMods();
  3171.  
  3172. //reset rating fields values
  3173. for (uint16 index = PLAYER_FIELD_COMBAT_RATING_1; index < PLAYER_FIELD_COMBAT_RATING_1 + MAX_COMBAT_RATING; ++index)
  3174. SetUInt32Value(index, 0);
  3175.  
  3176. SetUInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS, 0);
  3177. for (uint8 i = 0; i < 7; ++i)
  3178. {
  3179. SetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG+i, 0);
  3180. SetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, 0);
  3181. SetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT+i, 1.00f);
  3182. }
  3183.  
  3184. //reset attack power, damage and attack speed fields
  3185. SetFloatValue(UNIT_FIELD_BASEATTACKTIME, 2000.0f);
  3186. SetFloatValue(UNIT_FIELD_BASEATTACKTIME + 1, 2000.0f); // offhand attack time
  3187. SetFloatValue(UNIT_FIELD_RANGEDATTACKTIME, 2000.0f);
  3188.  
  3189. SetFloatValue(UNIT_FIELD_MINDAMAGE, 0.0f);
  3190. SetFloatValue(UNIT_FIELD_MAXDAMAGE, 0.0f);
  3191. SetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE, 0.0f);
  3192. SetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE, 0.0f);
  3193. SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, 0.0f);
  3194. SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, 0.0f);
  3195.  
  3196. SetInt32Value(UNIT_FIELD_ATTACK_POWER, 0);
  3197. SetInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, 0);
  3198. SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, 0.0f);
  3199. SetInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER, 0);
  3200. SetInt32Value(UNIT_FIELD_RANGED_ATTACK_POWER_MODS, 0);
  3201. SetFloatValue(UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER, 0.0f);
  3202.  
  3203. // Base crit values (will be recalculated in UpdateAllStats() at loading and in _ApplyAllStatBonuses() at reset
  3204. SetFloatValue(PLAYER_CRIT_PERCENTAGE, 0.0f);
  3205. SetFloatValue(PLAYER_OFFHAND_CRIT_PERCENTAGE, 0.0f);
  3206. SetFloatValue(PLAYER_RANGED_CRIT_PERCENTAGE, 0.0f);
  3207.  
  3208. // Init spell schools (will be recalculated in UpdateAllStats() at loading and in _ApplyAllStatBonuses() at reset
  3209. for (uint8 i = 0; i < 7; ++i)
  3210. SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1+i, 0.0f);
  3211.  
  3212. SetFloatValue(PLAYER_PARRY_PERCENTAGE, 0.0f);
  3213. SetFloatValue(PLAYER_BLOCK_PERCENTAGE, 0.0f);
  3214. SetUInt32Value(PLAYER_SHIELD_BLOCK, 0);
  3215.  
  3216. // Dodge percentage
  3217. SetFloatValue(PLAYER_DODGE_PERCENTAGE, 0.0f);
  3218.  
  3219. // set armor (resistance 0) to original value (create_agility*2)
  3220. SetArmor(int32(m_createStats[STAT_AGILITY]*2));
  3221. SetResistanceBuffMods(SpellSchools(0), true, 0.0f);
  3222. SetResistanceBuffMods(SpellSchools(0), false, 0.0f);
  3223. // set other resistance to original value (0)
  3224. for (uint8 i = 1; i < MAX_SPELL_SCHOOL; ++i)
  3225. {
  3226. SetResistance(SpellSchools(i), 0);
  3227. SetResistanceBuffMods(SpellSchools(i), true, 0.0f);
  3228. SetResistanceBuffMods(SpellSchools(i), false, 0.0f);
  3229. }
  3230.  
  3231. SetUInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE, 0);
  3232. SetUInt32Value(PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE, 0);
  3233. for (uint8 i = 0; i < MAX_SPELL_SCHOOL; ++i)
  3234. {
  3235. SetUInt32Value(UNIT_FIELD_POWER_COST_MODIFIER+i, 0);
  3236. SetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER+i, 0.0f);
  3237. }
  3238. // Reset no reagent cost field
  3239. for (uint8 i = 0; i < 3; ++i)
  3240. SetUInt32Value(PLAYER_NO_REAGENT_COST_1 + i, 0);
  3241. // Init data for form but skip reapply item mods for form
  3242. InitDataForForm(reapplyMods);
  3243.  
  3244. // save new stats
  3245. for (uint8 i = POWER_MANA; i < MAX_POWERS; ++i)
  3246. SetMaxPower(Powers(i), uint32(GetCreatePowers(Powers(i))));
  3247.  
  3248. SetMaxHealth(classInfo.basehealth); // stamina bonus will applied later
  3249.  
  3250. // cleanup mounted state (it will set correctly at aura loading if player saved at mount.
  3251. SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0);
  3252.  
  3253. // cleanup unit flags (will be re-applied if need at aura load).
  3254. RemoveFlag(UNIT_FIELD_FLAGS,
  3255. UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NOT_ATTACKABLE_1 |
  3256. UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_LOOTING |
  3257. UNIT_FLAG_PET_IN_COMBAT | UNIT_FLAG_SILENCED | UNIT_FLAG_PACIFIED |
  3258. UNIT_FLAG_STUNNED | UNIT_FLAG_IN_COMBAT | UNIT_FLAG_DISARMED |
  3259. UNIT_FLAG_CONFUSED | UNIT_FLAG_FLEEING | UNIT_FLAG_NOT_SELECTABLE |
  3260. UNIT_FLAG_SKINNABLE | UNIT_FLAG_MOUNT | UNIT_FLAG_TAXI_FLIGHT );
  3261. SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); // must be set
  3262.  
  3263. SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER);// must be set
  3264.  
  3265. // cleanup player flags (will be re-applied if need at aura load), to avoid have ghost flag without ghost aura, for example.
  3266. RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK | PLAYER_FLAGS_DND | PLAYER_FLAGS_GM | PLAYER_FLAGS_GHOST | PLAYER_ALLOW_ONLY_ABILITY);
  3267.  
  3268. RemoveStandFlags(UNIT_STAND_FLAGS_ALL); // one form stealth modified bytes
  3269. RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP | UNIT_BYTE2_FLAG_SANCTUARY);
  3270.  
  3271. // restore if need some important flags
  3272. SetUInt32Value(PLAYER_FIELD_BYTES2, 0); // flags empty by default
  3273.  
  3274. if (reapplyMods) // reapply stats values only on .reset stats (level) command
  3275. _ApplyAllStatBonuses();
  3276.  
  3277. // set current level health and mana/energy to maximum after applying all mods.
  3278. SetFullHealth();
  3279. SetPower(POWER_MANA, GetMaxPower(POWER_MANA));
  3280. SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY));
  3281. if (GetPower(POWER_RAGE) > GetMaxPower(POWER_RAGE))
  3282. SetPower(POWER_RAGE, GetMaxPower(POWER_RAGE));
  3283. SetPower(POWER_FOCUS, 0);
  3284. SetPower(POWER_HAPPINESS, 0);
  3285. SetPower(POWER_RUNIC_POWER, 0);
  3286.  
  3287. // update level to hunter/summon pet
  3288. if (Pet* pet = GetPet())
  3289. pet->SynchronizeLevelWithOwner();
  3290. }
  3291.  
  3292. void Player::SendInitialSpells()
  3293. {
  3294. time_t curTime = time(NULL);
  3295. time_t infTime = curTime + infinityCooldownDelayCheck;
  3296.  
  3297. uint16 spellCount = 0;
  3298.  
  3299. WorldPacket data(SMSG_INITIAL_SPELLS, (1+2+4*m_spells.size()+2+m_spellCooldowns.size()*(2+2+2+4+4)));
  3300. data << uint8(0);
  3301.  
  3302. size_t countPos = data.wpos();
  3303. data << uint16(spellCount); // spell count placeholder
  3304.  
  3305. for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
  3306. {
  3307. if (itr->second->state == PLAYERSPELL_REMOVED)
  3308. continue;
  3309.  
  3310. if (!itr->second->active || itr->second->disabled)
  3311. continue;
  3312.  
  3313. data << uint32(itr->first);
  3314. data << uint16(0); // it's not slot id
  3315.  
  3316. spellCount +=1;
  3317. }
  3318.  
  3319. data.put<uint16>(countPos, spellCount); // write real count value
  3320.  
  3321. uint16 spellCooldowns = m_spellCooldowns.size();
  3322. data << uint16(spellCooldowns);
  3323. for (SpellCooldowns::const_iterator itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end(); ++itr)
  3324. {
  3325. SpellInfo const* sEntry = sSpellMgr->GetSpellInfo(itr->first);
  3326. if (!sEntry)
  3327. continue;
  3328.  
  3329. data << uint32(itr->first);
  3330.  
  3331. data << uint16(itr->second.itemid); // cast item id
  3332. data << uint16(sEntry->Category); // spell category
  3333.  
  3334. // send infinity cooldown in special format
  3335. if (itr->second.end >= infTime)
  3336. {
  3337. data << uint32(1); // cooldown
  3338. data << uint32(0x80000000); // category cooldown
  3339. continue;
  3340. }
  3341.  
  3342. time_t cooldown = itr->second.end > curTime ? (itr->second.end-curTime)*IN_MILLISECONDS : 0;
  3343.  
  3344. if (sEntry->Category) // may be wrong, but anyway better than nothing...
  3345. {
  3346. data << uint32(0); // cooldown
  3347. data << uint32(cooldown); // category cooldown
  3348. }
  3349. else
  3350. {
  3351. data << uint32(cooldown); // cooldown
  3352. data << uint32(0); // category cooldown
  3353. }
  3354. }
  3355.  
  3356. GetSession()->SendPacket(&data);
  3357.  
  3358. sLog->outDebug(LOG_FILTER_NETWORKIO, "CHARACTER: Sent Initial Spells");
  3359. }
  3360.  
  3361. void Player::RemoveMail(uint32 id)
  3362. {
  3363. for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr)
  3364. {
  3365. if ((*itr)->messageID == id)
  3366. {
  3367. //do not delete item, because Player::removeMail() is called when returning mail to sender.
  3368. m_mail.erase(itr);
  3369. return;
  3370. }
  3371. }
  3372. }
  3373.  
  3374. void Player::SendMailResult(uint32 mailId, MailResponseType mailAction, MailResponseResult mailError, uint32 equipError, uint32 item_guid, uint32 item_count)
  3375. {
  3376. WorldPacket data(SMSG_SEND_MAIL_RESULT, (4+4+4+(mailError == MAIL_ERR_EQUIP_ERROR?4:(mailAction == MAIL_ITEM_TAKEN?4+4:0))));
  3377. data << (uint32) mailId;
  3378. data << (uint32) mailAction;
  3379. data << (uint32) mailError;
  3380. if (mailError == MAIL_ERR_EQUIP_ERROR)
  3381. data << (uint32) equipError;
  3382. else if (mailAction == MAIL_ITEM_TAKEN)
  3383. {
  3384. data << (uint32) item_guid; // item guid low?
  3385. data << (uint32) item_count; // item count?
  3386. }
  3387. GetSession()->SendPacket(&data);
  3388. }
  3389.  
  3390. void Player::SendNewMail()
  3391. {
  3392. // deliver undelivered mail
  3393. WorldPacket data(SMSG_RECEIVED_MAIL, 4);
  3394. data << (uint32) 0;
  3395. GetSession()->SendPacket(&data);
  3396. }
  3397.  
  3398. void Player::UpdateNextMailTimeAndUnreads()
  3399. {
  3400. // calculate next delivery time (min. from non-delivered mails
  3401. // and recalculate unReadMail
  3402. time_t cTime = time(NULL);
  3403. m_nextMailDelivereTime = 0;
  3404. unReadMails = 0;
  3405. for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr)
  3406. {
  3407. if ((*itr)->deliver_time > cTime)
  3408. {
  3409. if (!m_nextMailDelivereTime || m_nextMailDelivereTime > (*itr)->deliver_time)
  3410. m_nextMailDelivereTime = (*itr)->deliver_time;
  3411. }
  3412. else if (((*itr)->checked & MAIL_CHECK_MASK_READ) == 0)
  3413. ++unReadMails;
  3414. }
  3415. }
  3416.  
  3417. void Player::AddNewMailDeliverTime(time_t deliver_time)
  3418. {
  3419. if (deliver_time <= time(NULL)) // ready now
  3420. {
  3421. ++unReadMails;
  3422. SendNewMail();
  3423. }
  3424. else // not ready and no have ready mails
  3425. {
  3426. if (!m_nextMailDelivereTime || m_nextMailDelivereTime > deliver_time)
  3427. m_nextMailDelivereTime = deliver_time;
  3428. }
  3429. }
  3430.  
  3431. bool Player::AddTalent(uint32 spellId, uint8 spec, bool learning)
  3432. {
  3433. SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
  3434. if (!spellInfo)
  3435. {
  3436. // do character spell book cleanup (all characters)
  3437. if (!IsInWorld() && !learning) // spell load case
  3438. {
  3439. sLog->outError(LOG_FILTER_SPELLS_AURAS, "Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.", spellId);
  3440.  
  3441. PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_SPELL);
  3442.  
  3443. stmt->setUInt32(0, spellId);
  3444.  
  3445. CharacterDatabase.Execute(stmt);
  3446. }
  3447. else
  3448. sLog->outError(LOG_FILTER_SPELLS_AURAS, "Player::addSpell: Non-existed in SpellStore spell #%u request.", spellId);
  3449.  
  3450. return false;
  3451. }
  3452.  
  3453. if (!SpellMgr::IsSpellValid(spellInfo, this, false))
  3454. {
  3455. // do character spell book cleanup (all characters)
  3456. if (!IsInWorld() && !learning) // spell load case
  3457. {
  3458. sLog->outError(LOG_FILTER_SPELLS_AURAS, "Player::addTalent: Broken spell #%u learning not allowed, deleting for all characters in `character_talent`.", spellId);
  3459.  
  3460. PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_SPELL);
  3461.  
  3462. stmt->setUInt32(0, spellId);
  3463.  
  3464. CharacterDatabase.Execute(stmt);
  3465. }
  3466. else
  3467. sLog->outError(LOG_FILTER_SPELLS_AURAS, "Player::addTalent: Broken spell #%u learning not allowed.", spellId);
  3468.  
  3469. return false;
  3470. }
  3471.  
  3472. PlayerTalentMap::iterator itr = m_talents[spec]->find(spellId);
  3473. if (itr != m_talents[spec]->end())
  3474. itr->second->state = PLAYERSPELL_UNCHANGED;
  3475. else if (TalentSpellPos const* talentPos = GetTalentSpellPos(spellId))
  3476. {
  3477. if (TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentPos->talent_id))
  3478. {
  3479. for (uint8 rank = 0; rank < MAX_TALENT_RANK; ++rank)
  3480. {
  3481. // skip learning spell and no rank spell case
  3482. uint32 rankSpellId = talentInfo->RankID[rank];
  3483. if (!rankSpellId || rankSpellId == spellId)
  3484. continue;
  3485.  
  3486. itr = m_talents[spec]->find(rankSpellId);
  3487. if (itr != m_talents[spec]->end())
  3488. itr->second->state = PLAYERSPELL_REMOVED;
  3489. }
  3490. }
  3491.  
  3492. PlayerSpellState state = learning ? PLAYERSPELL_NEW : PLAYERSPELL_UNCHANGED;
  3493. PlayerTalent* newtalent = new PlayerTalent();
  3494.  
  3495. newtalent->state = state;
  3496. newtalent->spec = spec;
  3497.  
  3498. (*m_talents[spec])[spellId] = newtalent;
  3499. return true;
  3500. }
  3501. return false;
  3502. }
  3503.  
  3504. bool Player::addSpell(uint32 spellId, bool active, bool learning, bool dependent, bool disabled, bool loading /*= false*/)
  3505. {
  3506. SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
  3507. if (!spellInfo)
  3508. {
  3509. // do character spell book cleanup (all characters)
  3510. if (!IsInWorld() && !learning) // spell load case
  3511. {
  3512. sLog->outError(LOG_FILTER_SPELLS_AURAS, "Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.", spellId);
  3513.  
  3514. PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_SPELL);
  3515.  
  3516. stmt->setUInt32(0, spellId);
  3517.  
  3518. CharacterDatabase.Execute(stmt);
  3519. }
  3520. else
  3521. sLog->outError(LOG_FILTER_SPELLS_AURAS, "Player::addSpell: Non-existed in SpellStore spell #%u request.", spellId);
  3522.  
  3523. return false;
  3524. }
  3525.  
  3526. if (!SpellMgr::IsSpellValid(spellInfo, this, false))
  3527. {
  3528. // do character spell book cleanup (all characters)
  3529. if (!IsInWorld() && !learning) // spell load case
  3530. {
  3531. sLog->outError(LOG_FILTER_SPELLS_AURAS, "Player::addSpell: Broken spell #%u learning not allowed, deleting for all characters in `character_spell`.", spellId);
  3532.  
  3533. PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_SPELL);
  3534.  
  3535. stmt->setUInt32(0, spellId);
  3536.  
  3537. CharacterDatabase.Execute(stmt);
  3538. }
  3539. else
  3540. sLog->outError(LOG_FILTER_SPELLS_AURAS, "Player::addSpell: Broken spell #%u learning not allowed.", spellId);
  3541.  
  3542. return false;
  3543. }
  3544.  
  3545. PlayerSpellState state = learning ? PLAYERSPELL_NEW : PLAYERSPELL_UNCHANGED;
  3546.  
  3547. bool dependent_set = false;
  3548. bool disabled_case = false;
  3549. bool superceded_old = false;
  3550.  
  3551. PlayerSpellMap::iterator itr = m_spells.find(spellId);
  3552.  
  3553. // Remove temporary spell if found to prevent conflicts
  3554. if (itr != m_spells.end() && itr->second->state == PLAYERSPELL_TEMPORARY)
  3555. RemoveTemporarySpell(spellId);
  3556. else if (itr != m_spells.end())
  3557. {
  3558. uint32 next_active_spell_id = 0;
  3559. // fix activate state for non-stackable low rank (and find next spell for !active case)
  3560. if (!spellInfo->IsStackableWithRanks() && spellInfo->IsRanked())
  3561. {
  3562. if (uint32 next = sSpellMgr->GetNextSpellInChain(spellId))
  3563. {
  3564. if (HasSpell(next))
  3565. {
  3566. // high rank already known so this must !active
  3567. active = false;
  3568. next_active_spell_id = next;
  3569. }
  3570. }
  3571. }
  3572.  
  3573. // not do anything if already known in expected state
  3574. if (itr->second->state != PLAYERSPELL_REMOVED && itr->second->active == active &&
  3575. itr->second->dependent == dependent && itr->second->disabled == disabled)
  3576. {
  3577. if (!IsInWorld() && !learning) // explicitly load from DB and then exist in it already and set correctly
  3578. itr->second->state = PLAYERSPELL_UNCHANGED;
  3579.  
  3580. return false;
  3581. }
  3582.  
  3583. // dependent spell known as not dependent, overwrite state
  3584. if (itr->second->state != PLAYERSPELL_REMOVED && !itr->second->dependent && dependent)
  3585. {
  3586. itr->second->dependent = dependent;
  3587. if (itr->second->state != PLAYERSPELL_NEW)
  3588. itr->second->state = PLAYERSPELL_CHANGED;
  3589. dependent_set = true;
  3590. }
  3591.  
  3592. // update active state for known spell
  3593. if (itr->second->active != active && itr->second->state != PLAYERSPELL_REMOVED && !itr->second->disabled)
  3594. {
  3595. itr->second->active = active;
  3596.  
  3597. if (!IsInWorld() && !learning && !dependent_set) // explicitly load from DB and then exist in it already and set correctly
  3598. itr->second->state = PLAYERSPELL_UNCHANGED;
  3599. else if (itr->second->state != PLAYERSPELL_NEW)
  3600. itr->second->state = PLAYERSPELL_CHANGED;
  3601.  
  3602. if (active)
  3603. {
  3604. if (spellInfo->IsPassive() && IsNeedCastPassiveSpellAtLearn(spellInfo))
  3605. CastSpell (this, spellId, true);
  3606. }
  3607. else if (IsInWorld())
  3608. {
  3609. if (next_active_spell_id)
  3610. {
  3611. // update spell ranks in spellbook and action bar
  3612. WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4);
  3613. data << uint32(spellId);
  3614. data << uint32(next_active_spell_id);
  3615. GetSession()->SendPacket(&data);
  3616. }
  3617. else
  3618. {
  3619. WorldPacket data(SMSG_REMOVED_SPELL, 4);
  3620. data << uint32(spellId);
  3621. GetSession()->SendPacket(&data);
  3622. }
  3623. }
  3624.  
  3625. return active; // learn (show in spell book if active now)
  3626. }
  3627.  
  3628. if (itr->second->disabled != disabled && itr->second->state != PLAYERSPELL_REMOVED)
  3629. {
  3630. if (itr->second->state != PLAYERSPELL_NEW)
  3631. itr->second->state = PLAYERSPELL_CHANGED;
  3632. itr->second->disabled = disabled;
  3633.  
  3634. if (disabled)
  3635. return false;
  3636.  
  3637. disabled_case = true;
  3638. }
  3639. else switch (itr->second->state)
  3640. {
  3641. case PLAYERSPELL_UNCHANGED: // known saved spell
  3642. return false;
  3643. case PLAYERSPELL_REMOVED: // re-learning removed not saved spell
  3644. {
  3645. delete itr->second;
  3646. m_spells.erase(itr);
  3647. state = PLAYERSPELL_CHANGED;
  3648. break; // need re-add
  3649. }
  3650. default: // known not saved yet spell (new or modified)
  3651. {
  3652. // can be in case spell loading but learned at some previous spell loading
  3653. if (!IsInWorld() && !learning && !dependent_set)
  3654. itr->second->state = PLAYERSPELL_UNCHANGED;
  3655.  
  3656. return false;
  3657. }
  3658. }
  3659. }
  3660.  
  3661. if (!disabled_case) // skip new spell adding if spell already known (disabled spells case)
  3662. {
  3663. // talent: unlearn all other talent ranks (high and low)
  3664. if (TalentSpellPos const* talentPos = GetTalentSpellPos(spellId))
  3665. {
  3666. if (TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentPos->talent_id))
  3667. {
  3668. for (uint8 rank = 0; rank < MAX_TALENT_RANK; ++rank)
  3669. {
  3670. // skip learning spell and no rank spell case
  3671. uint32 rankSpellId = talentInfo->RankID[rank];
  3672. if (!rankSpellId || rankSpellId == spellId)
  3673. continue;
  3674.  
  3675. removeSpell(rankSpellId, false, false);
  3676. }
  3677. }
  3678. }
  3679. // non talent spell: learn low ranks (recursive call)
  3680. else if (uint32 prev_spell = sSpellMgr->GetPrevSpellInChain(spellId))
  3681. {
  3682. if (!IsInWorld() || disabled) // at spells loading, no output, but allow save
  3683. addSpell(prev_spell, active, true, true, disabled);
  3684. else // at normal learning
  3685. learnSpell(prev_spell, true);
  3686. }
  3687.  
  3688. PlayerSpell* newspell = new PlayerSpell;
  3689. newspell->state = state;
  3690. newspell->active = active;
  3691. newspell->dependent = dependent;
  3692. newspell->disabled = disabled;
  3693.  
  3694. // replace spells in action bars and spellbook to bigger rank if only one spell rank must be accessible
  3695. if (newspell->active && !newspell->disabled && !spellInfo->IsStackableWithRanks() && spellInfo->IsRanked() != 0)
  3696. {
  3697. for (PlayerSpellMap::iterator itr2 = m_spells.begin(); itr2 != m_spells.end(); ++itr2)
  3698. {
  3699. if (itr2->second->state == PLAYERSPELL_REMOVED)
  3700. continue;
  3701.  
  3702. SpellInfo const* i_spellInfo = sSpellMgr->GetSpellInfo(itr2->first);
  3703. if (!i_spellInfo)
  3704. continue;
  3705.  
  3706. if (spellInfo->IsDifferentRankOf(i_spellInfo))
  3707. {
  3708. if (itr2->second->active)
  3709. {
  3710. if (spellInfo->IsHighRankOf(i_spellInfo))
  3711. {
  3712. if (IsInWorld()) // not send spell (re-/over-)learn packets at loading
  3713. {
  3714. WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4);
  3715. data << uint32(itr2->first);
  3716. data << uint32(spellId);
  3717. GetSession()->SendPacket(&data);
  3718. }
  3719.  
  3720. // mark old spell as disable (SMSG_SUPERCEDED_SPELL replace it in client by new)
  3721. itr2->second->active = false;
  3722. if (itr2->second->state != PLAYERSPELL_NEW)
  3723. itr2->second->state = PLAYERSPELL_CHANGED;
  3724. superceded_old = true; // new spell replace old in action bars and spell book.
  3725. }
  3726. else
  3727. {
  3728. if (IsInWorld()) // not send spell (re-/over-)learn packets at loading
  3729. {
  3730. WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4);
  3731. data << uint32(spellId);
  3732. data << uint32(itr2->first);
  3733. GetSession()->SendPacket(&data);
  3734. }
  3735.  
  3736. // mark new spell as disable (not learned yet for client and will not learned)
  3737. newspell->active = false;
  3738. if (newspell->state != PLAYERSPELL_NEW)
  3739. newspell->state = PLAYERSPELL_CHANGED;
  3740. }
  3741. }
  3742. }
  3743. }
  3744. }
  3745.  
  3746. m_spells[spellId] = newspell;
  3747.  
  3748. // return false if spell disabled
  3749. if (newspell->disabled)
  3750. return false;
  3751. }
  3752.  
  3753. uint32 talentCost = GetTalentSpellCost(spellId);
  3754.  
  3755. // cast talents with SPELL_EFFECT_LEARN_SPELL (other dependent spells will learned later as not auto-learned)
  3756. // note: all spells with SPELL_EFFECT_LEARN_SPELL isn't passive
  3757. if (!loading && talentCost > 0 && spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL))
  3758. {
  3759. // ignore stance requirement for talent learn spell (stance set for spell only for client spell description show)
  3760. CastSpell(this, spellId, true);
  3761. }
  3762. // also cast passive spells (including all talents without SPELL_EFFECT_LEARN_SPELL) with additional checks
  3763. else if (spellInfo->IsPassive())
  3764. {
  3765. if (IsNeedCastPassiveSpellAtLearn(spellInfo))
  3766. CastSpell(this, spellId, true);
  3767. }
  3768. else if (spellInfo->HasEffect(SPELL_EFFECT_SKILL_STEP))
  3769. {
  3770. CastSpell(this, spellId, true);
  3771. return false;
  3772. }
  3773.  
  3774. // update used talent points count
  3775. m_usedTalentCount += talentCost;
  3776.  
  3777. // update free primary prof.points (if any, can be none in case GM .learn prof. learning)
  3778. if (uint32 freeProfs = GetFreePrimaryProfessionPoints())
  3779. {
  3780. if (spellInfo->IsPrimaryProfessionFirstRank())
  3781. SetFreePrimaryProfessions(freeProfs-1);
  3782. }
  3783.  
  3784. // add dependent skills
  3785. uint16 maxskill = GetMaxSkillValueForLevel();
  3786.  
  3787. SpellLearnSkillNode const* spellLearnSkill = sSpellMgr->GetSpellLearnSkill(spellId);
  3788.  
  3789. SkillLineAbilityMapBounds skill_bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId);
  3790.  
  3791. if (spellLearnSkill)
  3792. {
  3793. uint32 skill_value = GetPureSkillValue(spellLearnSkill->skill);
  3794. uint32 skill_max_value = GetPureMaxSkillValue(spellLearnSkill->skill);
  3795.  
  3796. if (skill_value < spellLearnSkill->value)
  3797. skill_value = spellLearnSkill->value;
  3798.  
  3799. uint32 new_skill_max_value = spellLearnSkill->maxvalue == 0 ? maxskill : spellLearnSkill->maxvalue;
  3800.  
  3801. if (skill_max_value < new_skill_max_value)
  3802. skill_max_value = new_skill_max_value;
  3803.  
  3804. SetSkill(spellLearnSkill->skill, spellLearnSkill->step, skill_value, skill_max_value);
  3805. }
  3806. else
  3807. {
  3808. // not ranked skills
  3809. for (SkillLineAbilityMap::const_iterator _spell_idx = skill_bounds.first; _spell_idx != skill_bounds.second; ++_spell_idx)
  3810. {
  3811. SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->skillId);
  3812. if (!pSkill)
  3813. continue;
  3814.  
  3815. if (!Has310Flyer(false) && pSkill->id == SKILL_MOUNTS)
  3816. for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
  3817. if (spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED &&
  3818. spellInfo->Effects[i].CalcValue() == 310)
  3819. SetHas310Flyer(true);
  3820.  
  3821. if (HasSkill(pSkill->id))
  3822. continue;
  3823.  
  3824. if (_spell_idx->second->learnOnGetSkill == ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL ||
  3825. // lockpicking/runeforging special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL
  3826. ((pSkill->id == SKILL_LOCKPICKING || pSkill->id == SKILL_RUNEFORGING) && _spell_idx->second->max_value == 0))
  3827. {
  3828. switch (GetSkillRangeType(pSkill, _spell_idx->second->racemask != 0))
  3829. {
  3830. case SKILL_RANGE_LANGUAGE:
  3831. SetSkill(pSkill->id, GetSkillStep(pSkill->id), 300, 300);
  3832. break;
  3833. case SKILL_RANGE_LEVEL:
  3834. SetSkill(pSkill->id, GetSkillStep(pSkill->id), 1, GetMaxSkillValueForLevel());
  3835. break;
  3836. case SKILL_RANGE_MONO:
  3837. SetSkill(pSkill->id, GetSkillStep(pSkill->id), 1, 1);
  3838. break;
  3839. default:
  3840. break;
  3841. }
  3842. }
  3843. }
  3844. }
  3845.  
  3846. // learn dependent spells
  3847. SpellLearnSpellMapBounds spell_bounds = sSpellMgr->GetSpellLearnSpellMapBounds(spellId);
  3848.  
  3849. for (SpellLearnSpellMap::const_iterator itr2 = spell_bounds.first; itr2 != spell_bounds.second; ++itr2)
  3850. {
  3851. if (!itr2->second.autoLearned)
  3852. {
  3853. if (!IsInWorld() || !itr2->second.active) // at spells loading, no output, but allow save
  3854. addSpell(itr2->second.spell, itr2->second.active, true, true, false);
  3855. else // at normal learning
  3856. learnSpell(itr2->second.spell, true);
  3857. }
  3858. }
  3859.  
  3860. if (!GetSession()->PlayerLoading())
  3861. {
  3862. // not ranked skills
  3863. for (SkillLineAbilityMap::const_iterator _spell_idx = skill_bounds.first; _spell_idx != skill_bounds.second; ++_spell_idx)
  3864. {
  3865. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE, _spell_idx->second->skillId);
  3866. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS, _spell_idx->second->skillId);
  3867. }
  3868.  
  3869. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL, spellId);
  3870. }
  3871.  
  3872. // return true (for send learn packet) only if spell active (in case ranked spells) and not replace old spell
  3873. return active && !disabled && !superceded_old;
  3874. }
  3875.  
  3876. void Player::AddTemporarySpell(uint32 spellId)
  3877. {
  3878. PlayerSpellMap::iterator itr = m_spells.find(spellId);
  3879. // spell already added - do not do anything
  3880. if (itr != m_spells.end())
  3881. return;
  3882. PlayerSpell* newspell = new PlayerSpell;
  3883. newspell->state = PLAYERSPELL_TEMPORARY;
  3884. newspell->active = true;
  3885. newspell->dependent = false;
  3886. newspell->disabled = false;
  3887. m_spells[spellId] = newspell;
  3888. }
  3889.  
  3890. void Player::RemoveTemporarySpell(uint32 spellId)
  3891. {
  3892. PlayerSpellMap::iterator itr = m_spells.find(spellId);
  3893. // spell already not in list - do not do anything
  3894. if (itr == m_spells.end())
  3895. return;
  3896. // spell has other state than temporary - do not change it
  3897. if (itr->second->state != PLAYERSPELL_TEMPORARY)
  3898. return;
  3899. delete itr->second;
  3900. m_spells.erase(itr);
  3901. }
  3902.  
  3903. bool Player::IsNeedCastPassiveSpellAtLearn(SpellInfo const* spellInfo) const
  3904. {
  3905. // note: form passives activated with shapeshift spells be implemented by HandleShapeshiftBoosts instead of spell_learn_spell
  3906. // talent dependent passives activated at form apply have proper stance data
  3907. ShapeshiftForm form = GetShapeshiftForm();
  3908. bool need_cast = (!spellInfo->Stances || (form && (spellInfo->Stances & (1 << (form - 1)))) ||
  3909. (!form && (spellInfo->AttributesEx2 & SPELL_ATTR2_NOT_NEED_SHAPESHIFT)));
  3910.  
  3911. //Check CasterAuraStates
  3912. return need_cast && (!spellInfo->CasterAuraState || HasAuraState(AuraStateType(spellInfo->CasterAuraState)));
  3913. }
  3914.  
  3915. void Player::learnSpell(uint32 spell_id, bool dependent)
  3916. {
  3917. PlayerSpellMap::iterator itr = m_spells.find(spell_id);
  3918.  
  3919. bool disabled = (itr != m_spells.end()) ? itr->second->disabled : false;
  3920. bool active = disabled ? itr->second->active : true;
  3921.  
  3922. bool learning = addSpell(spell_id, active, true, dependent, false);
  3923.  
  3924. // prevent duplicated entires in spell book, also not send if not in world (loading)
  3925. if (learning && IsInWorld())
  3926. {
  3927. WorldPacket data(SMSG_LEARNED_SPELL, 6);
  3928. data << uint32(spell_id);
  3929. data << uint16(0);
  3930. GetSession()->SendPacket(&data);
  3931. }
  3932.  
  3933. // learn all disabled higher ranks and required spells (recursive)
  3934. if (disabled)
  3935. {
  3936. if (uint32 nextSpell = sSpellMgr->GetNextSpellInChain(spell_id))
  3937. {
  3938. PlayerSpellMap::iterator iter = m_spells.find(nextSpell);
  3939. if (iter != m_spells.end() && iter->second->disabled)
  3940. learnSpell(nextSpell, false);
  3941. }
  3942.  
  3943. SpellsRequiringSpellMapBounds spellsRequiringSpell = sSpellMgr->GetSpellsRequiringSpellBounds(spell_id);
  3944. for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequiringSpell.first; itr2 != spellsRequiringSpell.second; ++itr2)
  3945. {
  3946. PlayerSpellMap::iterator iter2 = m_spells.find(itr2->second);
  3947. if (iter2 != m_spells.end() && iter2->second->disabled)
  3948. learnSpell(itr2->second, false);
  3949. }
  3950. }
  3951. }
  3952.  
  3953. void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank)
  3954. {
  3955. PlayerSpellMap::iterator itr = m_spells.find(spell_id);
  3956. if (itr == m_spells.end())
  3957. return;
  3958.  
  3959. if (itr->second->state == PLAYERSPELL_REMOVED || (disabled && itr->second->disabled) || itr->second->state == PLAYERSPELL_TEMPORARY)
  3960. return;
  3961.  
  3962. // unlearn non talent higher ranks (recursive)
  3963. if (uint32 nextSpell = sSpellMgr->GetNextSpellInChain(spell_id))
  3964. {
  3965. if (HasSpell(nextSpell) && !GetTalentSpellPos(nextSpell))
  3966. removeSpell(nextSpell, disabled, false);
  3967. }
  3968. //unlearn spells dependent from recently removed spells
  3969. SpellsRequiringSpellMapBounds spellsRequiringSpell = sSpellMgr->GetSpellsRequiringSpellBounds(spell_id);
  3970. for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequiringSpell.first; itr2 != spellsRequiringSpell.second; ++itr2)
  3971. removeSpell(itr2->second, disabled);
  3972.  
  3973. // re-search, it can be corrupted in prev loop
  3974. itr = m_spells.find(spell_id);
  3975. if (itr == m_spells.end())
  3976. return; // already unleared
  3977.  
  3978. bool giveTalentPoints = disabled || !itr->second->disabled;
  3979.  
  3980. bool cur_active = itr->second->active;
  3981. bool cur_dependent = itr->second->dependent;
  3982.  
  3983. if (disabled)
  3984. {
  3985. itr->second->disabled = disabled;
  3986. if (itr->second->state != PLAYERSPELL_NEW)
  3987. itr->second->state = PLAYERSPELL_CHANGED;
  3988. }
  3989. else
  3990. {
  3991. if (itr->second->state == PLAYERSPELL_NEW)
  3992. {
  3993. delete itr->second;
  3994. m_spells.erase(itr);
  3995. }
  3996. else
  3997. itr->second->state = PLAYERSPELL_REMOVED;
  3998. }
  3999.  
  4000. RemoveAurasDueToSpell(spell_id);
  4001.  
  4002. // remove pet auras
  4003. for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
  4004. if (PetAura const* petSpell = sSpellMgr->GetPetAura(spell_id, i))
  4005. RemovePetAura(petSpell);
  4006.  
  4007. // free talent points
  4008. uint32 talentCosts = GetTalentSpellCost(spell_id);
  4009. if (talentCosts > 0 && giveTalentPoints)
  4010. {
  4011. if (talentCosts < m_usedTalentCount)
  4012. m_usedTalentCount -= talentCosts;
  4013. else
  4014. m_usedTalentCount = 0;
  4015. }
  4016.  
  4017. // update free primary prof.points (if not overflow setting, can be in case GM use before .learn prof. learning)
  4018. SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id);
  4019. if (spellInfo && spellInfo->IsPrimaryProfessionFirstRank())
  4020. {
  4021. uint32 freeProfs = GetFreePrimaryProfessionPoints()+1;
  4022. if (freeProfs <= sWorld->getIntConfig(CONFIG_MAX_PRIMARY_TRADE_SKILL))
  4023. SetFreePrimaryProfessions(freeProfs);
  4024. }
  4025.  
  4026. // remove dependent skill
  4027. SpellLearnSkillNode const* spellLearnSkill = sSpellMgr->GetSpellLearnSkill(spell_id);
  4028. if (spellLearnSkill)
  4029. {
  4030. uint32 prev_spell = sSpellMgr->GetPrevSpellInChain(spell_id);
  4031. if (!prev_spell) // first rank, remove skill
  4032. SetSkill(spellLearnSkill->skill, 0, 0, 0);
  4033. else
  4034. {
  4035. // search prev. skill setting by spell ranks chain
  4036. SpellLearnSkillNode const* prevSkill = sSpellMgr->GetSpellLearnSkill(prev_spell);
  4037. while (!prevSkill && prev_spell)
  4038. {
  4039. prev_spell = sSpellMgr->GetPrevSpellInChain(prev_spell);
  4040. prevSkill = sSpellMgr->GetSpellLearnSkill(sSpellMgr->GetFirstSpellInChain(prev_spell));
  4041. }
  4042.  
  4043. if (!prevSkill) // not found prev skill setting, remove skill
  4044. SetSkill(spellLearnSkill->skill, 0, 0, 0);
  4045. else // set to prev. skill setting values
  4046. {
  4047. uint32 skill_value = GetPureSkillValue(prevSkill->skill);
  4048. uint32 skill_max_value = GetPureMaxSkillValue(prevSkill->skill);
  4049.  
  4050. if (skill_value > prevSkill->value)
  4051. skill_value = prevSkill->value;
  4052.  
  4053. uint32 new_skill_max_value = prevSkill->maxvalue == 0 ? GetMaxSkillValueForLevel() : prevSkill->maxvalue;
  4054.  
  4055. if (skill_max_value > new_skill_max_value)
  4056. skill_max_value = new_skill_max_value;
  4057.  
  4058. SetSkill(prevSkill->skill, prevSkill->step, skill_value, skill_max_value);
  4059. }
  4060. }
  4061. }
  4062. else
  4063. {
  4064. // not ranked skills
  4065. SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spell_id);
  4066.  
  4067. for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
  4068. {
  4069. SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->skillId);
  4070. if (!pSkill)
  4071. continue;
  4072.  
  4073. if ((_spell_idx->second->learnOnGetSkill == ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL &&
  4074. pSkill->categoryId != SKILL_CATEGORY_CLASS) ||// not unlearn class skills (spellbook/talent pages)
  4075. // lockpicking/runeforging special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL
  4076. ((pSkill->id == SKILL_LOCKPICKING || pSkill->id == SKILL_RUNEFORGING) && _spell_idx->second->max_value == 0))
  4077. {
  4078. // not reset skills for professions and racial abilities
  4079. if ((pSkill->categoryId == SKILL_CATEGORY_SECONDARY || pSkill->categoryId == SKILL_CATEGORY_PROFESSION) &&
  4080. (IsProfessionSkill(pSkill->id) || _spell_idx->second->racemask != 0))
  4081. continue;
  4082.  
  4083. SetSkill(pSkill->id, GetSkillStep(pSkill->id), 0, 0);
  4084. }
  4085.  
  4086. // most likely will never be used, haven't heard of cases where players unlearn a mount
  4087. if (Has310Flyer(false) && _spell_idx->second->skillId == SKILL_MOUNTS)
  4088. {
  4089. if (spellInfo)
  4090. for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
  4091. if (spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED &&
  4092. spellInfo->Effects[i].CalcValue() == 310)
  4093. Has310Flyer(true, spell_id); // with true as first argument its also used to set/remove the flag
  4094. }
  4095. }
  4096. }
  4097.  
  4098. // remove dependent spells
  4099. SpellLearnSpellMapBounds spell_bounds = sSpellMgr->GetSpellLearnSpellMapBounds(spell_id);
  4100.  
  4101. for (SpellLearnSpellMap::const_iterator itr2 = spell_bounds.first; itr2 != spell_bounds.second; ++itr2)
  4102. removeSpell(itr2->second.spell, disabled);
  4103.  
  4104. // activate lesser rank in spellbook/action bar, and cast it if need
  4105. bool prev_activate = false;
  4106.  
  4107. if (uint32 prev_id = sSpellMgr->GetPrevSpellInChain(spell_id))
  4108. {
  4109. // if talent then lesser rank also talent and need learn
  4110. if (talentCosts)
  4111. {
  4112. // I cannot see why mangos has these lines.
  4113. //if (learn_low_rank)
  4114. // learnSpell(prev_id, false);
  4115. }
  4116. // if ranked non-stackable spell: need activate lesser rank and update dendence state
  4117. else if (cur_active && !spellInfo->IsStackableWithRanks() && spellInfo->IsRanked())
  4118. {
  4119. // need manually update dependence state (learn spell ignore like attempts)
  4120. PlayerSpellMap::iterator prev_itr = m_spells.find(prev_id);
  4121. if (prev_itr != m_spells.end())
  4122. {
  4123. if (prev_itr->second->dependent != cur_dependent)
  4124. {
  4125. prev_itr->second->dependent = cur_dependent;
  4126. if (prev_itr->second->state != PLAYERSPELL_NEW)
  4127. prev_itr->second->state = PLAYERSPELL_CHANGED;
  4128. }
  4129.  
  4130. // now re-learn if need re-activate
  4131. if (cur_active && !prev_itr->second->active && learn_low_rank)
  4132. {
  4133. if (addSpell(prev_id, true, false, prev_itr->second->dependent, prev_itr->second->disabled))
  4134. {
  4135. // downgrade spell ranks in spellbook and action bar
  4136. WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4);
  4137. data << uint32(spell_id);
  4138. data << uint32(prev_id);
  4139. GetSession()->SendPacket(&data);
  4140. prev_activate = true;
  4141. }
  4142. }
  4143. }
  4144. }
  4145. }
  4146.  
  4147. if (spell_id == 46917 && m_canTitanGrip)
  4148. SetCanTitanGrip(false);
  4149. if (spell_id == 674 && m_canDualWield)
  4150. SetCanDualWield(false);
  4151.  
  4152. if (sWorld->getBoolConfig(CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN))
  4153. AutoUnequipOffhandIfNeed();
  4154.  
  4155. // remove from spell book if not replaced by lesser rank
  4156. if (!prev_activate)
  4157. {
  4158. WorldPacket data(SMSG_REMOVED_SPELL, 4);
  4159. data << uint32(spell_id);
  4160. GetSession()->SendPacket(&data);
  4161. }
  4162. }
  4163.  
  4164. bool Player::Has310Flyer(bool checkAllSpells, uint32 excludeSpellId)
  4165. {
  4166. if (!checkAllSpells)
  4167. return m_ExtraFlags & PLAYER_EXTRA_HAS_310_FLYER;
  4168. else
  4169. {
  4170. SetHas310Flyer(false);
  4171. SpellInfo const* spellInfo;
  4172. for (PlayerSpellMap::iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
  4173. {
  4174. if (itr->first == excludeSpellId)
  4175. continue;
  4176.  
  4177. SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(itr->first);
  4178. for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
  4179. {
  4180. if (_spell_idx->second->skillId != SKILL_MOUNTS)
  4181. break; // We can break because mount spells belong only to one skillline (at least 310 flyers do)
  4182.  
  4183. spellInfo = sSpellMgr->GetSpellInfo(itr->first);
  4184. for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
  4185. if (spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED &&
  4186. spellInfo->Effects[i].CalcValue() == 310)
  4187. {
  4188. SetHas310Flyer(true);
  4189. return true;
  4190. }
  4191. }
  4192. }
  4193. }
  4194.  
  4195. return false;
  4196. }
  4197.  
  4198. void Player::RemoveSpellCooldown(uint32 spell_id, bool update /* = false */)
  4199. {
  4200. m_spellCooldowns.erase(spell_id);
  4201.  
  4202. if (update)
  4203. SendClearCooldown(spell_id, this);
  4204. }
  4205.  
  4206. // I am not sure which one is more efficient
  4207. void Player::RemoveCategoryCooldown(uint32 cat)
  4208. {
  4209. SpellCategoryStore::const_iterator i_scstore = sSpellCategoryStore.find(cat);
  4210. if (i_scstore != sSpellCategoryStore.end())
  4211. for (SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset)
  4212. RemoveSpellCooldown(*i_scset, true);
  4213. }
  4214.  
  4215. void Player::RemoveSpellCategoryCooldown(uint32 cat, bool update /* = false */)
  4216. {
  4217. SpellCategoryStore::const_iterator ct = sSpellCategoryStore.find(cat);
  4218. if (ct == sSpellCategoryStore.end())
  4219. return;
  4220.  
  4221. const SpellCategorySet& ct_set = ct->second;
  4222. for (SpellCooldowns::const_iterator i = m_spellCooldowns.begin(); i != m_spellCooldowns.end();)
  4223. {
  4224. if (ct_set.find(i->first) != ct_set.end())
  4225. RemoveSpellCooldown((i++)->first, update);
  4226. else
  4227. ++i;
  4228. }
  4229. }
  4230.  
  4231. void Player::RemoveArenaSpellCooldowns(bool removeActivePetCooldowns)
  4232. {
  4233. // remove cooldowns on spells that have <= 10 min CD
  4234.  
  4235. SpellCooldowns::iterator itr, next;
  4236. for (itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end(); itr = next)
  4237. {
  4238. next = itr;
  4239. ++next;
  4240. SpellInfo const* entry = sSpellMgr->GetSpellInfo(itr->first);
  4241. // check if spellentry is present and if the cooldown is less or equal to 10 min
  4242. if (entry &&
  4243. entry->RecoveryTime <= 10 * MINUTE * IN_MILLISECONDS &&
  4244. entry->CategoryRecoveryTime <= 10 * MINUTE * IN_MILLISECONDS)
  4245. {
  4246. // remove & notify
  4247. RemoveSpellCooldown(itr->first, true);
  4248. }
  4249. }
  4250.  
  4251. // pet cooldowns
  4252. if (removeActivePetCooldowns)
  4253. if (Pet* pet = GetPet())
  4254. {
  4255. // notify player
  4256. for (CreatureSpellCooldowns::const_iterator itr2 = pet->m_CreatureSpellCooldowns.begin(); itr2 != pet->m_CreatureSpellCooldowns.end(); ++itr2)
  4257. SendClearCooldown(itr2->first, pet);
  4258.  
  4259. // actually clear cooldowns
  4260. pet->m_CreatureSpellCooldowns.clear();
  4261. }
  4262. }
  4263.  
  4264. void Player::RemoveAllSpellCooldown()
  4265. {
  4266. if (!m_spellCooldowns.empty())
  4267. {
  4268. for (SpellCooldowns::const_iterator itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end(); ++itr)
  4269. SendClearCooldown(itr->first, this);
  4270.  
  4271. m_spellCooldowns.clear();
  4272. }
  4273. }
  4274.  
  4275. void Player::_LoadSpellCooldowns(PreparedQueryResult result)
  4276. {
  4277. // some cooldowns can be already set at aura loading...
  4278.  
  4279. //QueryResult* result = CharacterDatabase.PQuery("SELECT spell, item, time FROM character_spell_cooldown WHERE guid = '%u'", GetGUIDLow());
  4280.  
  4281. if (result)
  4282. {
  4283. time_t curTime = time(NULL);
  4284.  
  4285. do
  4286. {
  4287. Field* fields = result->Fetch();
  4288. uint32 spell_id = fields[0].GetUInt32();
  4289. uint32 item_id = fields[1].GetUInt32();
  4290. time_t db_time = time_t(fields[2].GetUInt32());
  4291.  
  4292. if (!sSpellMgr->GetSpellInfo(spell_id))
  4293. {
  4294. sLog->outError(LOG_FILTER_PLAYER_LOADING, "Player %u has unknown spell %u in `character_spell_cooldown`, skipping.", GetGUIDLow(), spell_id);
  4295. continue;
  4296. }
  4297.  
  4298. // skip outdated cooldown
  4299. if (db_time <= curTime)
  4300. continue;
  4301.  
  4302. AddSpellCooldown(spell_id, item_id, db_time);
  4303.  
  4304. sLog->outDebug(LOG_FILTER_PLAYER_LOADING, "Player (GUID: %u) spell %u, item %u cooldown loaded (%u secs).", GetGUIDLow(), spell_id, item_id, uint32(db_time-curTime));
  4305. }
  4306. while (result->NextRow());
  4307. }
  4308. }
  4309.  
  4310. void Player::_SaveSpellCooldowns(SQLTransaction& trans)
  4311. {
  4312. PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_COOLDOWN);
  4313. stmt->setUInt32(0, GetGUIDLow());
  4314. trans->Append(stmt);
  4315.  
  4316. time_t curTime = time(NULL);
  4317. time_t infTime = curTime + infinityCooldownDelayCheck;
  4318.  
  4319. bool first_round = true;
  4320. std::ostringstream ss;
  4321.  
  4322. // remove outdated and save active
  4323. for (SpellCooldowns::iterator itr = m_spellCooldowns.begin(); itr != m_spellCooldowns.end();)
  4324. {
  4325. if (itr->second.end <= curTime)
  4326. m_spellCooldowns.erase(itr++);
  4327. else if (itr->second.end <= infTime) // not save locked cooldowns, it will be reset or set at reload
  4328. {
  4329. if (first_round)
  4330. {
  4331. ss << "INSERT INTO character_spell_cooldown (guid, spell, item, time) VALUES ";
  4332. first_round = false;
  4333. }
  4334. // next new/changed record prefix
  4335. else
  4336. ss << ',';
  4337. ss << '(' << GetGUIDLow() << ',' << itr->first << ',' << itr->second.itemid << ',' << uint64(itr->second.end) << ')';
  4338. ++itr;
  4339. }
  4340. else
  4341. ++itr;
  4342. }
  4343. // if something changed execute
  4344. if (!first_round)
  4345. trans->Append(ss.str().c_str());
  4346. }
  4347.  
  4348. uint32 Player::resetTalentsCost() const
  4349. {
  4350. // The first time reset costs 1 gold
  4351. if (m_resetTalentsCost < 1*GOLD)
  4352. return 1*GOLD;
  4353. // then 5 gold
  4354. else if (m_resetTalentsCost < 5*GOLD)
  4355. return 5*GOLD;
  4356. // After that it increases in increments of 5 gold
  4357. else if (m_resetTalentsCost < 10*GOLD)
  4358. return 10*GOLD;
  4359. else
  4360. {
  4361. uint64 months = (sWorld->GetGameTime() - m_resetTalentsTime)/MONTH;
  4362. if (months > 0)
  4363. {
  4364. // This cost will be reduced by a rate of 5 gold per month
  4365. int32 new_cost = int32(m_resetTalentsCost - 5*GOLD*months);
  4366. // to a minimum of 10 gold.
  4367. return (new_cost < 10*GOLD ? 10*GOLD : new_cost);
  4368. }
  4369. else
  4370. {
  4371. // After that it increases in increments of 5 gold
  4372. int32 new_cost = m_resetTalentsCost + 5*GOLD;
  4373. // until it hits a cap of 50 gold.
  4374. if (new_cost > 50*GOLD)
  4375. new_cost = 50*GOLD;
  4376. return new_cost;
  4377. }
  4378. }
  4379. }
  4380.  
  4381. bool Player::resetTalents(bool no_cost)
  4382. {
  4383. sScriptMgr->OnPlayerTalentsReset(this, no_cost);
  4384.  
  4385. // not need after this call
  4386. if (HasAtLoginFlag(AT_LOGIN_RESET_TALENTS))
  4387. RemoveAtLoginFlag(AT_LOGIN_RESET_TALENTS, true);
  4388.  
  4389. uint32 talentPointsForLevel = CalculateTalentsPoints();
  4390.  
  4391. if (m_usedTalentCount == 0)
  4392. {
  4393. SetFreeTalentPoints(talentPointsForLevel);
  4394. return false;
  4395. }
  4396.  
  4397. uint32 cost = 0;
  4398.  
  4399. if (!no_cost && !sWorld->getBoolConfig(CONFIG_NO_RESET_TALENT_COST))
  4400. {
  4401. cost = resetTalentsCost();
  4402.  
  4403. if (!HasEnoughMoney(cost))
  4404. {
  4405. SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, 0, 0, 0);
  4406. return false;
  4407. }
  4408. }
  4409.  
  4410. RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true);
  4411.  
  4412. for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
  4413. {
  4414. TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
  4415.  
  4416. if (!talentInfo)
  4417. continue;
  4418.  
  4419. TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab);
  4420.  
  4421. if (!talentTabInfo)
  4422. continue;
  4423.  
  4424. // unlearn only talents for character class
  4425. // some spell learned by one class as normal spells or know at creation but another class learn it as talent,
  4426. // to prevent unexpected lost normal learned spell skip another class talents
  4427. if ((getClassMask() & talentTabInfo->ClassMask) == 0)
  4428. continue;
  4429.  
  4430. for (int8 rank = MAX_TALENT_RANK-1; rank >= 0; --rank)
  4431. {
  4432. // skip non-existant talent ranks
  4433. if (talentInfo->RankID[rank] == 0)
  4434. continue;
  4435. const SpellInfo* _spellEntry = sSpellMgr->GetSpellInfo(talentInfo->RankID[rank]);
  4436. if (!_spellEntry)
  4437. continue;
  4438. removeSpell(talentInfo->RankID[rank], true);
  4439. // search for spells that the talent teaches and unlearn them
  4440. for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
  4441. if (_spellEntry->Effects[i].TriggerSpell > 0 && _spellEntry->Effects[i].Effect == SPELL_EFFECT_LEARN_SPELL)
  4442. removeSpell(_spellEntry->Effects[i].TriggerSpell, true);
  4443. // if this talent rank can be found in the PlayerTalentMap, mark the talent as removed so it gets deleted
  4444. PlayerTalentMap::iterator plrTalent = m_talents[m_activeSpec]->find(talentInfo->RankID[rank]);
  4445. if (plrTalent != m_talents[m_activeSpec]->end())
  4446. plrTalent->second->state = PLAYERSPELL_REMOVED;
  4447. }
  4448. }
  4449.  
  4450. SQLTransaction trans = CharacterDatabase.BeginTransaction();
  4451. _SaveTalents(trans);
  4452. _SaveSpells(trans);
  4453. CharacterDatabase.CommitTransaction(trans);
  4454.  
  4455. SetFreeTalentPoints(talentPointsForLevel);
  4456.  
  4457. if (!no_cost)
  4458. {
  4459. ModifyMoney(-(int32)cost);
  4460. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS, cost);
  4461. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS, 1);
  4462.  
  4463. m_resetTalentsCost = cost;
  4464. m_resetTalentsTime = time(NULL);
  4465. }
  4466.  
  4467. /* when prev line will dropped use next line
  4468. if (Pet* pet = GetPet())
  4469. {
  4470. if (pet->getPetType() == HUNTER_PET && !pet->GetCreatureTemplate()->isTameable(CanTameExoticPets()))
  4471. RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true);
  4472. }
  4473. */
  4474.  
  4475. return true;
  4476. }
  4477.  
  4478. void Player::SetFreeTalentPoints(uint32 points)
  4479. {
  4480. sScriptMgr->OnPlayerFreeTalentPointsChanged(this, points);
  4481. SetUInt32Value(PLAYER_CHARACTER_POINTS1, points);
  4482. }
  4483.  
  4484. Mail* Player::GetMail(uint32 id)
  4485. {
  4486. for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr)
  4487. if ((*itr)->messageID == id)
  4488. return (*itr);
  4489.  
  4490. return NULL;
  4491. }
  4492.  
  4493. void Player::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const
  4494. {
  4495. for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i)
  4496. {
  4497. if (m_items[i] == NULL)
  4498. continue;
  4499.  
  4500. m_items[i]->BuildCreateUpdateBlockForPlayer(data, target);
  4501. }
  4502.  
  4503. if (target == this)
  4504. {
  4505. for (uint8 i = INVENTORY_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
  4506. {
  4507. if (m_items[i] == NULL)
  4508. continue;
  4509.  
  4510. m_items[i]->BuildCreateUpdateBlockForPlayer(data, target);
  4511. }
  4512. for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i)
  4513. {
  4514. if (m_items[i] == NULL)
  4515. continue;
  4516.  
  4517. m_items[i]->BuildCreateUpdateBlockForPlayer(data, target);
  4518. }
  4519. }
  4520.  
  4521. Unit::BuildCreateUpdateBlockForPlayer(data, target);
  4522. }
  4523.  
  4524. void Player::DestroyForPlayer(Player* target, bool onDeath) const
  4525. {
  4526. Unit::DestroyForPlayer(target, onDeath);
  4527.  
  4528. for (uint8 i = 0; i < INVENTORY_SLOT_BAG_END; ++i)
  4529. {
  4530. if (m_items[i] == NULL)
  4531. continue;
  4532.  
  4533. m_items[i]->DestroyForPlayer(target);
  4534. }
  4535.  
  4536. if (target == this)
  4537. {
  4538. for (uint8 i = INVENTORY_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
  4539. {
  4540. if (m_items[i] == NULL)
  4541. continue;
  4542.  
  4543. m_items[i]->DestroyForPlayer(target);
  4544. }
  4545. for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i)
  4546. {
  4547. if (m_items[i] == NULL)
  4548. continue;
  4549.  
  4550. m_items[i]->DestroyForPlayer(target);
  4551. }
  4552. }
  4553. }
  4554.  
  4555. bool Player::HasSpell(uint32 spell) const
  4556. {
  4557. PlayerSpellMap::const_iterator itr = m_spells.find(spell);
  4558. return (itr != m_spells.end() && itr->second->state != PLAYERSPELL_REMOVED &&
  4559. !itr->second->disabled);
  4560. }
  4561.  
  4562. bool Player::HasTalent(uint32 spell, uint8 spec) const
  4563. {
  4564. PlayerTalentMap::const_iterator itr = m_talents[spec]->find(spell);
  4565. return (itr != m_talents[spec]->end() && itr->second->state != PLAYERSPELL_REMOVED);
  4566. }
  4567.  
  4568. bool Player::HasActiveSpell(uint32 spell) const
  4569. {
  4570. PlayerSpellMap::const_iterator itr = m_spells.find(spell);
  4571. return (itr != m_spells.end() && itr->second->state != PLAYERSPELL_REMOVED &&
  4572. itr->second->active && !itr->second->disabled);
  4573. }
  4574.  
  4575. TrainerSpellState Player::GetTrainerSpellState(TrainerSpell const* trainer_spell) const
  4576. {
  4577. if (!trainer_spell)
  4578. return TRAINER_SPELL_RED;
  4579.  
  4580. bool hasSpell = true;
  4581. for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
  4582. {
  4583. if (!trainer_spell->learnedSpell[i])
  4584. continue;
  4585.  
  4586. if (!HasSpell(trainer_spell->learnedSpell[i]))
  4587. {
  4588. hasSpell = false;
  4589. break;
  4590. }
  4591. }
  4592. // known spell
  4593. if (hasSpell)
  4594. return TRAINER_SPELL_GRAY;
  4595.  
  4596. // check skill requirement
  4597. if (trainer_spell->reqSkill && GetBaseSkillValue(trainer_spell->reqSkill) < trainer_spell->reqSkillValue)
  4598. return TRAINER_SPELL_RED;
  4599.  
  4600. // check level requirement
  4601. if (getLevel() < trainer_spell->reqLevel)
  4602. return TRAINER_SPELL_RED;
  4603.  
  4604. for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
  4605. {
  4606. if (!trainer_spell->learnedSpell[i])
  4607. continue;
  4608.  
  4609. // check race/class requirement
  4610. if (!IsSpellFitByClassAndRace(trainer_spell->learnedSpell[i]))
  4611. return TRAINER_SPELL_RED;
  4612.  
  4613. if (uint32 prevSpell = sSpellMgr->GetPrevSpellInChain(trainer_spell->learnedSpell[i]))
  4614. {
  4615. // check prev.rank requirement
  4616. if (prevSpell && !HasSpell(prevSpell))
  4617. return TRAINER_SPELL_RED;
  4618. }
  4619.  
  4620. SpellsRequiringSpellMapBounds spellsRequired = sSpellMgr->GetSpellsRequiredForSpellBounds(trainer_spell->learnedSpell[i]);
  4621. for (SpellsRequiringSpellMap::const_iterator itr = spellsRequired.first; itr != spellsRequired.second; ++itr)
  4622. {
  4623. // check additional spell requirement
  4624. if (!HasSpell(itr->second))
  4625. return TRAINER_SPELL_RED;
  4626. }
  4627. }
  4628.  
  4629. // check primary prof. limit
  4630. // first rank of primary profession spell when there are no proffesions avalible is disabled
  4631. for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
  4632. {
  4633. if (!trainer_spell->learnedSpell[i])
  4634. continue;
  4635. SpellInfo const* learnedSpellInfo = sSpellMgr->GetSpellInfo(trainer_spell->learnedSpell[i]);
  4636. if (learnedSpellInfo && learnedSpellInfo->IsPrimaryProfessionFirstRank() && (GetFreePrimaryProfessionPoints() == 0))
  4637. return TRAINER_SPELL_GREEN_DISABLED;
  4638. }
  4639.  
  4640. return TRAINER_SPELL_GREEN;
  4641. }
  4642.  
  4643. /**
  4644. * Deletes a character from the database
  4645. *
  4646. * The way, how the characters will be deleted is decided based on the config option.
  4647. *
  4648. * @see Player::DeleteOldCharacters
  4649. *
  4650. * @param playerguid the low-GUID from the player which should be deleted
  4651. * @param accountId the account id from the player
  4652. * @param updateRealmChars when this flag is set, the amount of characters on that realm will be updated in the realmlist
  4653. * @param deleteFinally if this flag is set, the config option will be ignored and the character will be permanently removed from the database
  4654. */
  4655. void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmChars, bool deleteFinally)
  4656. {
  4657. // for not existed account avoid update realm
  4658. if (accountId == 0)
  4659. updateRealmChars = false;
  4660.  
  4661. uint32 charDelete_method = sWorld->getIntConfig(CONFIG_CHARDELETE_METHOD);
  4662. uint32 charDelete_minLvl = sWorld->getIntConfig(CONFIG_CHARDELETE_MIN_LEVEL);
  4663.  
  4664. // if we want to finally delete the character or the character does not meet the level requirement,
  4665. // we set it to mode CHAR_DELETE_REMOVE
  4666. if (deleteFinally || Player::GetLevelFromDB(playerguid) < charDelete_minLvl)
  4667. charDelete_method = CHAR_DELETE_REMOVE;
  4668.  
  4669. uint32 guid = GUID_LOPART(playerguid);
  4670.  
  4671. // convert corpse to bones if exist (to prevent exiting Corpse in World without DB entry)
  4672. // bones will be deleted by corpse/bones deleting thread shortly
  4673. sObjectAccessor->ConvertCorpseForPlayer(playerguid);
  4674.  
  4675. if (uint32 guildId = GetGuildIdFromDB(playerguid))
  4676. if (Guild* guild = sGuildMgr->GetGuildById(guildId))
  4677. guild->DeleteMember(guid);
  4678.  
  4679. // remove from arena teams
  4680. LeaveAllArenaTeams(playerguid);
  4681.  
  4682. // the player was uninvited already on logout so just remove from group
  4683. PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GROUP_MEMBER);
  4684. stmt->setUInt32(0, guid);
  4685. PreparedQueryResult resultGroup = CharacterDatabase.Query(stmt);
  4686.  
  4687. if (resultGroup)
  4688. if (Group* group = sGroupMgr->GetGroupByDbStoreId((*resultGroup)[0].GetUInt32()))
  4689. RemoveFromGroup(group, playerguid);
  4690.  
  4691. // Remove signs from petitions (also remove petitions if owner);
  4692. RemovePetitionsAndSigns(playerguid, 10);
  4693.  
  4694. switch (charDelete_method)
  4695. {
  4696. // Completely remove from the database
  4697. case CHAR_DELETE_REMOVE:
  4698. {
  4699. SQLTransaction trans = CharacterDatabase.BeginTransaction();
  4700.  
  4701. stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_COD_ITEM_MAIL);
  4702. stmt->setUInt32(0, guid);
  4703. PreparedQueryResult resultMail = CharacterDatabase.Query(stmt);
  4704.  
  4705. if (resultMail)
  4706. {
  4707. do
  4708. {
  4709. Field* mailFields = resultMail->Fetch();
  4710.  
  4711. uint32 mail_id = mailFields[0].GetUInt32();
  4712. uint8 mailType = mailFields[1].GetUInt8();
  4713. uint16 mailTemplateId= mailFields[2].GetUInt16();
  4714. uint32 sender = mailFields[3].GetUInt32();
  4715. std::string subject = mailFields[4].GetString();
  4716. std::string body = mailFields[5].GetString();
  4717. uint32 money = mailFields[6].GetUInt32();
  4718. bool has_items = mailFields[7].GetBool();
  4719.  
  4720. // We can return mail now
  4721. // So firstly delete the old one
  4722. PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_BY_ID);
  4723. stmt->setUInt32(0, mail_id);
  4724. trans->Append(stmt);
  4725.  
  4726. // Mail is not from player
  4727. if (mailType != MAIL_NORMAL)
  4728. {
  4729. if (has_items)
  4730. {
  4731. PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM_BY_ID);
  4732. stmt->setUInt32(0, mail_id);
  4733. trans->Append(stmt);
  4734. }
  4735. continue;
  4736. }
  4737.  
  4738. MailDraft draft(subject, body);
  4739. if (mailTemplateId)
  4740. draft = MailDraft(mailTemplateId, false); // items are already included
  4741.  
  4742. if (has_items)
  4743. {
  4744. // Data needs to be at first place for Item::LoadFromDB
  4745. PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS);
  4746. stmt->setUInt32(0, mail_id);
  4747. PreparedQueryResult resultItems = CharacterDatabase.Query(stmt);
  4748. if (resultItems)
  4749. {
  4750. do
  4751. {
  4752. Field* itemFields = resultItems->Fetch();
  4753. uint32 item_guidlow = itemFields[11].GetUInt32();
  4754. uint32 item_template = itemFields[12].GetUInt32();
  4755.  
  4756. ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(item_template);
  4757. if (!itemProto)
  4758. {
  4759. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
  4760. stmt->setUInt32(0, item_guidlow);
  4761. trans->Append(stmt);
  4762. continue;
  4763. }
  4764.  
  4765. Item* pItem = NewItemOrBag(itemProto);
  4766. if (!pItem->LoadFromDB(item_guidlow, MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER), itemFields, item_template))
  4767. {
  4768. pItem->FSetState(ITEM_REMOVED);
  4769. pItem->SaveToDB(trans); // it also deletes item object!
  4770. continue;
  4771. }
  4772.  
  4773. draft.AddItem(pItem);
  4774. }
  4775. while (resultItems->NextRow());
  4776. }
  4777. }
  4778.  
  4779. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM_BY_ID);
  4780. stmt->setUInt32(0, mail_id);
  4781. trans->Append(stmt);
  4782.  
  4783. uint32 pl_account = sObjectMgr->GetPlayerAccountIdByGUID(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER));
  4784.  
  4785. draft.AddMoney(money).SendReturnToSender(pl_account, guid, sender, trans);
  4786. }
  4787. while (resultMail->NextRow());
  4788. }
  4789.  
  4790. // Unsummon and delete for pets in world is not required: player deleted from CLI or character list with not loaded pet.
  4791. // NOW we can finally clear other DB data related to character
  4792. stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_PETS);
  4793. stmt->setUInt32(0, guid);
  4794. PreparedQueryResult resultPets = CharacterDatabase.Query(stmt);
  4795.  
  4796. if (resultPets)
  4797. {
  4798. do
  4799. {
  4800. uint32 petguidlow = (*resultPets)[0].GetUInt32();
  4801. Pet::DeleteFromDB(petguidlow);
  4802. } while (resultPets->NextRow());
  4803. }
  4804.  
  4805. // Delete char from social list of online chars
  4806. stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_SOCIAL);
  4807. stmt->setUInt32(0, guid);
  4808. PreparedQueryResult resultFriends = CharacterDatabase.Query(stmt);
  4809.  
  4810. if (resultFriends)
  4811. {
  4812. do
  4813. {
  4814. if (Player* pFriend = ObjectAccessor::FindPlayer(MAKE_NEW_GUID((*resultFriends)[0].GetUInt32(), 0, HIGHGUID_PLAYER)))
  4815. {
  4816. if (pFriend->IsInWorld())
  4817. {
  4818. pFriend->GetSocial()->RemoveFromSocialList(guid, false);
  4819. sSocialMgr->SendFriendStatus(pFriend, FRIEND_REMOVED, guid, false);
  4820. }
  4821. }
  4822. } while (resultFriends->NextRow());
  4823. }
  4824.  
  4825. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER);
  4826. stmt->setUInt32(0, guid);
  4827. trans->Append(stmt);
  4828.  
  4829. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_ACCOUNT_DATA);
  4830. stmt->setUInt32(0, guid);
  4831. trans->Append(stmt);
  4832.  
  4833. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_DECLINED_NAME);
  4834. stmt->setUInt32(0, guid);
  4835. trans->Append(stmt);
  4836.  
  4837. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACTION);
  4838. stmt->setUInt32(0, guid);
  4839. trans->Append(stmt);
  4840.  
  4841. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_AURA);
  4842. stmt->setUInt32(0, guid);
  4843. trans->Append(stmt);
  4844.  
  4845. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_GIFT);
  4846. stmt->setUInt32(0, guid);
  4847. trans->Append(stmt);
  4848.  
  4849. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_HOMEBIND);
  4850. stmt->setUInt32(0, guid);
  4851. trans->Append(stmt);
  4852.  
  4853. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INSTANCE);
  4854. stmt->setUInt32(0, guid);
  4855. trans->Append(stmt);
  4856.  
  4857. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INVENTORY);
  4858. stmt->setUInt32(0, guid);
  4859. trans->Append(stmt);
  4860.  
  4861. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS);
  4862. stmt->setUInt32(0, guid);
  4863. trans->Append(stmt);
  4864.  
  4865. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_REWARDED);
  4866. stmt->setUInt32(0, guid);
  4867. trans->Append(stmt);
  4868.  
  4869. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_REPUTATION);
  4870. stmt->setUInt32(0, guid);
  4871. trans->Append(stmt);
  4872.  
  4873. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL);
  4874. stmt->setUInt32(0, guid);
  4875. trans->Append(stmt);
  4876.  
  4877. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_COOLDOWN);
  4878. stmt->setUInt32(0, guid);
  4879. trans->Append(stmt);
  4880.  
  4881. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_GM_TICKETS);
  4882. stmt->setUInt32(0, guid);
  4883. trans->Append(stmt);
  4884.  
  4885. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
  4886. stmt->setUInt32(0, guid);
  4887. trans->Append(stmt);
  4888.  
  4889. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SOCIAL_BY_FRIEND);
  4890. stmt->setUInt32(0, guid);
  4891. trans->Append(stmt);
  4892.  
  4893. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SOCIAL_BY_GUID);
  4894. stmt->setUInt32(0, guid);
  4895. trans->Append(stmt);
  4896.  
  4897. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL);
  4898. stmt->setUInt32(0, guid);
  4899. trans->Append(stmt);
  4900.  
  4901. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEMS);
  4902. stmt->setUInt32(0, guid);
  4903. trans->Append(stmt);
  4904.  
  4905. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_PET_BY_OWNER);
  4906. stmt->setUInt32(0, guid);
  4907. trans->Append(stmt);
  4908.  
  4909. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_PET_DECLINEDNAME_BY_OWNER);
  4910. stmt->setUInt32(0, guid);
  4911. trans->Append(stmt);
  4912.  
  4913. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENTS);
  4914. stmt->setUInt32(0, guid);
  4915. trans->Append(stmt);
  4916.  
  4917. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS);
  4918. stmt->setUInt32(0, guid);
  4919. trans->Append(stmt);
  4920.  
  4921. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_EQUIPMENTSETS);
  4922. stmt->setUInt32(0, guid);
  4923. trans->Append(stmt);
  4924.  
  4925. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_EVENTLOG_BY_PLAYER);
  4926. stmt->setUInt32(0, guid);
  4927. stmt->setUInt32(1, guid);
  4928. trans->Append(stmt);
  4929.  
  4930. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_EVENTLOG_BY_PLAYER);
  4931. stmt->setUInt32(0, guid);
  4932. trans->Append(stmt);
  4933.  
  4934. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_BGDATA);
  4935. stmt->setUInt32(0, guid);
  4936. trans->Append(stmt);
  4937.  
  4938. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_GLYPHS);
  4939. stmt->setUInt32(0, guid);
  4940. trans->Append(stmt);
  4941.  
  4942. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_DAILY);
  4943. stmt->setUInt32(0, guid);
  4944. trans->Append(stmt);
  4945.  
  4946. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TALENT);
  4947. stmt->setUInt32(0, guid);
  4948. trans->Append(stmt);
  4949.  
  4950. stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SKILLS);
  4951. stmt->setUInt32(0, guid);
  4952. trans->Append(stmt);
  4953. /* World of Warcraft Armory */
  4954. trans->PAppend("DELETE FROM armory_character_stats WHERE guid = '%u'",guid);
  4955. trans->PAppend("DELETE FROM character_feed_log WHERE guid = '%u'",guid);
  4956. /* World of Warcraft Armory */
  4957.  
  4958.  
  4959. CharacterDatabase.CommitTransaction(trans);
  4960. break;
  4961. }
  4962. // The character gets unlinked from the account, the name gets freed up and appears as deleted ingame
  4963. case CHAR_DELETE_UNLINK:
  4964. {
  4965. PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_DELETE_INFO);
  4966.  
  4967. stmt->setUInt32(0, guid);
  4968.  
  4969. CharacterDatabase.Execute(stmt);
  4970. break;
  4971. }
  4972. default:
  4973. sLog->outError(LOG_FILTER_PLAYER, "Player::DeleteFromDB: Unsupported delete method: %u.", charDelete_method);
  4974. }
  4975.  
  4976. if (updateRealmChars)
  4977. sWorld->UpdateRealmCharCount(accountId);
  4978. }
  4979.  
  4980. /**
  4981. * Characters which were kept back in the database after being deleted and are now too old (see config option "CharDelete.KeepDays"), will be completely deleted.
  4982. *
  4983. * @see Player::DeleteFromDB
  4984. */
  4985. void Player::DeleteOldCharacters()
  4986. {
  4987. uint32 keepDays = sWorld->getIntConfig(CONFIG_CHARDELETE_KEEP_DAYS);
  4988. if (!keepDays)
  4989. return;
  4990.  
  4991. Player::DeleteOldCharacters(keepDays);
  4992. }
  4993.  
  4994. /**
  4995. * Characters which were kept back in the database after being deleted and are older than the specified amount of days, will be completely deleted.
  4996. *
  4997. * @see Player::DeleteFromDB
  4998. *
  4999. * @param keepDays overrite the config option by another amount of days
  5000. */
  5001. void Player::DeleteOldCharacters(uint32 keepDays)
  5002. {
  5003. sLog->outInfo(LOG_FILTER_PLAYER, "Player::DeleteOldChars: Deleting all characters which have been deleted %u days before...", keepDays);
  5004.  
  5005. PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_OLD_CHARS);
  5006. stmt->setUInt32(0, uint32(time(NULL) - time_t(keepDays * DAY)));
  5007. PreparedQueryResult result = CharacterDatabase.Query(stmt);
  5008.  
  5009. if (result)
  5010. {
  5011. sLog->outDebug(LOG_FILTER_PLAYER, "Player::DeleteOldChars: Found " UI64FMTD " character(s) to delete", result->GetRowCount());
  5012. do
  5013. {
  5014. Field* fields = result->Fetch();
  5015. Player::DeleteFromDB(fields[0].GetUInt32(), fields[1].GetUInt32(), true, true);
  5016. }
  5017. while (result->NextRow());
  5018. }
  5019. }
  5020.  
  5021. void Player::SetMovement(PlayerMovementType pType)
  5022. {
  5023. WorldPacket data;
  5024. switch (pType)
  5025. {
  5026. case MOVE_ROOT: data.Initialize(SMSG_FORCE_MOVE_ROOT, GetPackGUID().size()+4); break;
  5027. case MOVE_UNROOT: data.Initialize(SMSG_FORCE_MOVE_UNROOT, GetPackGUID().size()+4); break;
  5028. case MOVE_WATER_WALK: data.Initialize(SMSG_MOVE_WATER_WALK, GetPackGUID().size()+4); break;
  5029. case MOVE_LAND_WALK: data.Initialize(SMSG_MOVE_LAND_WALK, GetPackGUID().size()+4); break;
  5030. default:
  5031. sLog->outError(LOG_FILTER_PLAYER, "Player::SetMovement: Unsupported move type (%d), data not sent to client.", pType);
  5032. return;
  5033. }
  5034. data.append(GetPackGUID());
  5035. data << uint32(0);
  5036. GetSession()->SendPacket(&data);
  5037. }
  5038.  
  5039. /* Preconditions:
  5040. - a resurrectable corpse must not be loaded for the player (only bones)
  5041. - the player must be in world
  5042. */
  5043. void Player::BuildPlayerRepop()
  5044. {
  5045. WorldPacket data(SMSG_PRE_RESURRECT, GetPackGUID().size());
  5046. data.append(GetPackGUID());
  5047. GetSession()->SendPacket(&data);
  5048.  
  5049. if (getRace() == RACE_NIGHTELF)
  5050. CastSpell(this, 20584, true);
  5051. CastSpell(this, 8326, true);
  5052.  
  5053. // there must be SMSG.FORCE_RUN_SPEED_CHANGE, SMSG.FORCE_SWIM_SPEED_CHANGE, SMSG.MOVE_WATER_WALK
  5054. // there must be SMSG.STOP_MIRROR_TIMER
  5055. // there we must send 888 opcode
  5056.  
  5057. // the player cannot have a corpse already, only bones which are not returned by GetCorpse
  5058. if (GetCorpse())
  5059. {
  5060. sLog->outError(LOG_FILTER_PLAYER, "BuildPlayerRepop: player %s(%d) already has a corpse", GetName(), GetGUIDLow());
  5061. return;
  5062. }
  5063.  
  5064. // create a corpse and place it at the player's location
  5065. CreateCorpse();
  5066. Corpse* corpse = GetCorpse();
  5067. if (!corpse)
  5068. {
  5069. sLog->outError(LOG_FILTER_PLAYER, "Error creating corpse for Player %s [%u]", GetName(), GetGUIDLow());
  5070. return;
  5071. }
  5072. GetMap()->AddToMap(corpse);
  5073.  
  5074. // convert player body to ghost
  5075. SetHealth(1);
  5076.  
  5077. SetMovement(MOVE_WATER_WALK);
  5078. if (!GetSession()->isLogingOut())
  5079. SetMovement(MOVE_UNROOT);
  5080.  
  5081. // BG - remove insignia related
  5082. RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
  5083.  
  5084. // SendCorpseReclaimDelay();
  5085.  
  5086. // to prevent cheating
  5087. corpse->ResetGhostTime();
  5088.  
  5089. StopMirrorTimers(); //disable timers(bars)
  5090.  
  5091. SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, float(1.0f)); //see radius of death player?
  5092.  
  5093. // set and clear other
  5094. SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND);
  5095. }
  5096.  
  5097. void Player::ResurrectPlayer(float restore_percent, bool applySickness)
  5098. {
  5099. WorldPacket data(SMSG_DEATH_RELEASE_LOC, 4*4); // remove spirit healer position
  5100. data << uint32(-1);
  5101. data << float(0);
  5102. data << float(0);
  5103. data << float(0);
  5104. GetSession()->SendPacket(&data);
  5105.  
  5106. // speed change, land walk
  5107.  
  5108. // remove death flag + set aura
  5109. SetByteValue(UNIT_FIELD_BYTES_1, 3, 0x00);
  5110. if (getRace() == RACE_NIGHTELF)
  5111. RemoveAurasDueToSpell(20584); // speed bonuses
  5112. RemoveAurasDueToSpell(8326); // SPELL_AURA_GHOST
  5113.  
  5114. if (GetSession()->IsARecruiter() || (GetSession()->GetRecruiterId() != 0))
  5115. SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_REFER_A_FRIEND);
  5116.  
  5117. setDeathState(ALIVE);
  5118.  
  5119. SetMovement(MOVE_LAND_WALK);
  5120. SetMovement(MOVE_UNROOT);
  5121.  
  5122. m_deathTimer = 0;
  5123.  
  5124. // set health/powers (0- will be set in caller)
  5125. if (restore_percent > 0.0f)
  5126. {
  5127. SetHealth(uint32(GetMaxHealth()*restore_percent));
  5128. SetPower(POWER_MANA, uint32(GetMaxPower(POWER_MANA)*restore_percent));
  5129. SetPower(POWER_RAGE, 0);
  5130. SetPower(POWER_ENERGY, uint32(GetMaxPower(POWER_ENERGY)*restore_percent));
  5131. }
  5132.  
  5133. // trigger update zone for alive state zone updates
  5134. uint32 newzone, newarea;
  5135. GetZoneAndAreaId(newzone, newarea);
  5136. UpdateZone(newzone, newarea);
  5137. sOutdoorPvPMgr->HandlePlayerResurrects(this, newzone);
  5138.  
  5139. if (InBattleground())
  5140. {
  5141. if (Battleground* bg = GetBattleground())
  5142. bg->HandlePlayerResurrect(this);
  5143. }
  5144.  
  5145. // update visibility
  5146. UpdateObjectVisibility();
  5147.  
  5148. if (!applySickness)
  5149. return;
  5150.  
  5151. //Characters from level 1-10 are not affected by resurrection sickness.
  5152. //Characters from level 11-19 will suffer from one minute of sickness
  5153. //for each level they are above 10.
  5154. //Characters level 20 and up suffer from ten minutes of sickness.
  5155. int32 startLevel = sWorld->getIntConfig(CONFIG_DEATH_SICKNESS_LEVEL);
  5156.  
  5157. if (int32(getLevel()) >= startLevel)
  5158. {
  5159. // set resurrection sickness
  5160. CastSpell(this, 15007, true);
  5161.  
  5162. // not full duration
  5163. if (int32(getLevel()) < startLevel+9)
  5164. {
  5165. int32 delta = (int32(getLevel()) - startLevel + 1)*MINUTE;
  5166.  
  5167. if (Aura* aur = GetAura(15007, GetGUID()))
  5168. {
  5169. aur->SetDuration(delta*IN_MILLISECONDS);
  5170. }
  5171. }
  5172. }
  5173. }
  5174.  
  5175. void Player::KillPlayer()
  5176. {
  5177. if (IsFlying() && !GetTransport())
  5178. i_motionMaster.MoveFall();
  5179.  
  5180. SetMovement(MOVE_ROOT);
  5181.  
  5182. StopMirrorTimers(); //disable timers(bars)
  5183.  
  5184. setDeathState(CORPSE);
  5185. //SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_IN_PVP);
  5186.  
  5187. SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_NONE);
  5188. ApplyModFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTE_RELEASE_TIMER, !sMapStore.LookupEntry(GetMapId())->Instanceable() && !HasAuraType(SPELL_AURA_PREVENT_RESURRECTION));
  5189.  
  5190. // 6 minutes until repop at graveyard
  5191. m_deathTimer = 6 * MINUTE * IN_MILLISECONDS;
  5192.  
  5193. UpdateCorpseReclaimDelay(); // dependent at use SetDeathPvP() call before kill
  5194. SendCorpseReclaimDelay();
  5195.  
  5196. // don't create corpse at this moment, player might be falling
  5197.  
  5198. // update visibility
  5199. UpdateObjectVisibility();
  5200. }
  5201.  
  5202. void Player::CreateCorpse()
  5203. {
  5204. // prevent existence 2 corpse for player
  5205. SpawnCorpseBones();
  5206.  
  5207. uint32 _uf, _pb, _pb2, _cfb1, _cfb2;
  5208.  
  5209. Corpse* corpse = new Corpse((m_ExtraFlags & PLAYER_EXTRA_PVP_DEATH) ? CORPSE_RESURRECTABLE_PVP : CORPSE_RESURRECTABLE_PVE);
  5210. SetPvPDeath(false);
  5211.  
  5212. if (!corpse->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_CORPSE), this))
  5213. {
  5214. delete corpse;
  5215. return;
  5216. }
  5217.  
  5218. _uf = GetUInt32Value(UNIT_FIELD_BYTES_0);
  5219. _pb = GetUInt32Value(PLAYER_BYTES);
  5220. _pb2 = GetUInt32Value(PLAYER_BYTES_2);
  5221.  
  5222. uint8 race = (uint8)(_uf);
  5223. uint8 skin = (uint8)(_pb);
  5224. uint8 face = (uint8)(_pb >> 8);
  5225. uint8 hairstyle = (uint8)(_pb >> 16);
  5226. uint8 haircolor = (uint8)(_pb >> 24);
  5227. uint8 facialhair = (uint8)(_pb2);
  5228.  
  5229. _cfb1 = ((0x00) | (race << 8) | (getGender() << 16) | (skin << 24));
  5230. _cfb2 = ((face) | (hairstyle << 8) | (haircolor << 16) | (facialhair << 24));
  5231.  
  5232. corpse->SetUInt32Value(CORPSE_FIELD_BYTES_1, _cfb1);
  5233. corpse->SetUInt32Value(CORPSE_FIELD_BYTES_2, _cfb2);
  5234.  
  5235. uint32 flags = CORPSE_FLAG_UNK2;
  5236. if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM))
  5237. flags |= CORPSE_FLAG_HIDE_HELM;
  5238. if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK))
  5239. flags |= CORPSE_FLAG_HIDE_CLOAK;
  5240. if (InBattleground() && !InArena())
  5241. flags |= CORPSE_FLAG_LOOTABLE; // to be able to remove insignia
  5242. corpse->SetUInt32Value(CORPSE_FIELD_FLAGS, flags);
  5243.  
  5244. corpse->SetUInt32Value(CORPSE_FIELD_DISPLAY_ID, GetNativeDisplayId());
  5245.  
  5246. corpse->SetUInt32Value(CORPSE_FIELD_GUILD, GetGuildId());
  5247.  
  5248. uint32 iDisplayID;
  5249. uint32 iIventoryType;
  5250. uint32 _cfi;
  5251. for (uint8 i = 0; i < EQUIPMENT_SLOT_END; i++)
  5252. {
  5253. if (m_items[i])
  5254. {
  5255. iDisplayID = m_items[i]->GetTemplate()->DisplayInfoID;
  5256. iIventoryType = m_items[i]->GetTemplate()->InventoryType;
  5257.  
  5258. _cfi = iDisplayID | (iIventoryType << 24);
  5259. corpse->SetUInt32Value(CORPSE_FIELD_ITEM + i, _cfi);
  5260. }
  5261. }
  5262.  
  5263. // we do not need to save corpses for BG/arenas
  5264. if (!GetMap()->IsBattlegroundOrArena())
  5265. corpse->SaveToDB();
  5266.  
  5267. // register for player, but not show
  5268. sObjectAccessor->AddCorpse(corpse);
  5269. }
  5270.  
  5271. void Player::SpawnCorpseBones()
  5272. {
  5273. if (sObjectAccessor->ConvertCorpseForPlayer(GetGUID()))
  5274. if (!GetSession()->PlayerLogoutWithSave()) // at logout we will already store the player
  5275. SaveToDB(); // prevent loading as ghost without corpse
  5276. }
  5277.  
  5278. Corpse* Player::GetCorpse() const
  5279. {
  5280. return sObjectAccessor->GetCorpseForPlayerGUID(GetGUID());
  5281. }
  5282.  
  5283. void Player::DurabilityLossAll(double percent, bool inventory)
  5284. {
  5285. for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
  5286. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  5287. DurabilityLoss(pItem, percent);
  5288.  
  5289. if (inventory)
  5290. {
  5291. // bags not have durability
  5292. // for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
  5293.  
  5294. for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
  5295. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  5296. DurabilityLoss(pItem, percent);
  5297.  
  5298. // keys not have durability
  5299. //for (int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++)
  5300.  
  5301. for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
  5302. if (Bag* pBag = GetBagByPos(i))
  5303. for (uint32 j = 0; j < pBag->GetBagSize(); j++)
  5304. if (Item* pItem = GetItemByPos(i, j))
  5305. DurabilityLoss(pItem, percent);
  5306. }
  5307. }
  5308.  
  5309. void Player::DurabilityLoss(Item* item, double percent)
  5310. {
  5311. if (!item)
  5312. return;
  5313.  
  5314. uint32 pMaxDurability = item ->GetUInt32Value(ITEM_FIELD_MAXDURABILITY);
  5315.  
  5316. if (!pMaxDurability)
  5317. return;
  5318.  
  5319. uint32 pDurabilityLoss = uint32(pMaxDurability*percent);
  5320.  
  5321. if (pDurabilityLoss < 1)
  5322. pDurabilityLoss = 1;
  5323.  
  5324. DurabilityPointsLoss(item, pDurabilityLoss);
  5325. }
  5326.  
  5327. void Player::DurabilityPointsLossAll(int32 points, bool inventory)
  5328. {
  5329. for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
  5330. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  5331. DurabilityPointsLoss(pItem, points);
  5332.  
  5333. if (inventory)
  5334. {
  5335. // bags not have durability
  5336. // for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
  5337.  
  5338. for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
  5339. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  5340. DurabilityPointsLoss(pItem, points);
  5341.  
  5342. // keys not have durability
  5343. //for (int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++)
  5344.  
  5345. for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
  5346. if (Bag* pBag = (Bag*)GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  5347. for (uint32 j = 0; j < pBag->GetBagSize(); j++)
  5348. if (Item* pItem = GetItemByPos(i, j))
  5349. DurabilityPointsLoss(pItem, points);
  5350. }
  5351. }
  5352.  
  5353. void Player::DurabilityPointsLoss(Item* item, int32 points)
  5354. {
  5355. int32 pMaxDurability = item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY);
  5356. int32 pOldDurability = item->GetUInt32Value(ITEM_FIELD_DURABILITY);
  5357. int32 pNewDurability = pOldDurability - points;
  5358.  
  5359. if (pNewDurability < 0)
  5360. pNewDurability = 0;
  5361. else if (pNewDurability > pMaxDurability)
  5362. pNewDurability = pMaxDurability;
  5363.  
  5364. if (pOldDurability != pNewDurability)
  5365. {
  5366. // modify item stats _before_ Durability set to 0 to pass _ApplyItemMods internal check
  5367. if (pNewDurability == 0 && pOldDurability > 0 && item->IsEquipped())
  5368. _ApplyItemMods(item, item->GetSlot(), false);
  5369.  
  5370. item->SetUInt32Value(ITEM_FIELD_DURABILITY, pNewDurability);
  5371.  
  5372. // modify item stats _after_ restore durability to pass _ApplyItemMods internal check
  5373. if (pNewDurability > 0 && pOldDurability == 0 && item->IsEquipped())
  5374. _ApplyItemMods(item, item->GetSlot(), true);
  5375.  
  5376. item->SetState(ITEM_CHANGED, this);
  5377. }
  5378. }
  5379.  
  5380. void Player::DurabilityPointLossForEquipSlot(EquipmentSlots slot)
  5381. {
  5382. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
  5383. DurabilityPointsLoss(pItem, 1);
  5384. }
  5385.  
  5386. uint32 Player::DurabilityRepairAll(bool cost, float discountMod, bool guildBank)
  5387. {
  5388. uint32 TotalCost = 0;
  5389. // equipped, backpack, bags itself
  5390. for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++)
  5391. TotalCost += DurabilityRepair(((INVENTORY_SLOT_BAG_0 << 8) | i), cost, discountMod, guildBank);
  5392.  
  5393. // bank, buyback and keys not repaired
  5394.  
  5395. // items in inventory bags
  5396. for (uint8 j = INVENTORY_SLOT_BAG_START; j < INVENTORY_SLOT_BAG_END; j++)
  5397. for (uint8 i = 0; i < MAX_BAG_SIZE; i++)
  5398. TotalCost += DurabilityRepair(((j << 8) | i), cost, discountMod, guildBank);
  5399. return TotalCost;
  5400. }
  5401.  
  5402. uint32 Player::DurabilityRepair(uint16 pos, bool cost, float discountMod, bool guildBank)
  5403. {
  5404. Item* item = GetItemByPos(pos);
  5405.  
  5406. uint32 TotalCost = 0;
  5407. if (!item)
  5408. return TotalCost;
  5409.  
  5410. uint32 maxDurability = item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY);
  5411. if (!maxDurability)
  5412. return TotalCost;
  5413.  
  5414. uint32 curDurability = item->GetUInt32Value(ITEM_FIELD_DURABILITY);
  5415.  
  5416. if (cost)
  5417. {
  5418. uint32 LostDurability = maxDurability - curDurability;
  5419. if (LostDurability>0)
  5420. {
  5421. ItemTemplate const* ditemProto = item->GetTemplate();
  5422.  
  5423. DurabilityCostsEntry const* dcost = sDurabilityCostsStore.LookupEntry(ditemProto->ItemLevel);
  5424. if (!dcost)
  5425. {
  5426. sLog->outError(LOG_FILTER_PLAYER_ITEMS, "RepairDurability: Wrong item lvl %u", ditemProto->ItemLevel);
  5427. return TotalCost;
  5428. }
  5429.  
  5430. uint32 dQualitymodEntryId = (ditemProto->Quality+1)*2;
  5431. DurabilityQualityEntry const* dQualitymodEntry = sDurabilityQualityStore.LookupEntry(dQualitymodEntryId);
  5432. if (!dQualitymodEntry)
  5433. {
  5434. sLog->outError(LOG_FILTER_PLAYER_ITEMS, "RepairDurability: Wrong dQualityModEntry %u", dQualitymodEntryId);
  5435. return TotalCost;
  5436. }
  5437.  
  5438. uint32 dmultiplier = dcost->multiplier[ItemSubClassToDurabilityMultiplierId(ditemProto->Class, ditemProto->SubClass)];
  5439. uint32 costs = uint32(LostDurability*dmultiplier*double(dQualitymodEntry->quality_mod));
  5440.  
  5441. costs = uint32(costs * discountMod * sWorld->getRate(RATE_REPAIRCOST));
  5442.  
  5443. if (costs == 0) //fix for ITEM_QUALITY_ARTIFACT
  5444. costs = 1;
  5445.  
  5446. if (guildBank)
  5447. {
  5448. if (GetGuildId() == 0)
  5449. {
  5450. sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "You are not member of a guild");
  5451. return TotalCost;
  5452. }
  5453.  
  5454. Guild* guild = sGuildMgr->GetGuildById(GetGuildId());
  5455. if (!guild)
  5456. return TotalCost;
  5457.  
  5458. if (!guild->HandleMemberWithdrawMoney(GetSession(), costs, true))
  5459. return TotalCost;
  5460.  
  5461. TotalCost = costs;
  5462. }
  5463. else if (!HasEnoughMoney(costs))
  5464. {
  5465. sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "You do not have enough money");
  5466. return TotalCost;
  5467. }
  5468. else
  5469. ModifyMoney(-int32(costs));
  5470. }
  5471. }
  5472.  
  5473. item->SetUInt32Value(ITEM_FIELD_DURABILITY, maxDurability);
  5474. item->SetState(ITEM_CHANGED, this);
  5475.  
  5476. // reapply mods for total broken and repaired item if equipped
  5477. if (IsEquipmentPos(pos) && !curDurability)
  5478. _ApplyItemMods(item, pos & 255, true);
  5479. return TotalCost;
  5480. }
  5481.  
  5482. void Player::RepopAtGraveyard()
  5483. {
  5484. // note: this can be called also when the player is alive
  5485. // for example from WorldSession::HandleMovementOpcodes
  5486.  
  5487. AreaTableEntry const* zone = GetAreaEntryByAreaID(GetAreaId());
  5488.  
  5489. // Such zones are considered unreachable as a ghost and the player must be automatically revived
  5490. if ((!isAlive() && zone && zone->flags & AREA_FLAG_NEED_FLY) || GetTransport() || GetPositionZ() < -500.0f)
  5491. {
  5492. ResurrectPlayer(0.5f);
  5493. SpawnCorpseBones();
  5494. }
  5495.  
  5496. WorldSafeLocsEntry const* ClosestGrave = NULL;
  5497.  
  5498. // Special handle for battleground maps
  5499. if (Battleground* bg = GetBattleground())
  5500. ClosestGrave = bg->GetClosestGraveYard(this);
  5501. else
  5502. ClosestGrave = sObjectMgr->GetClosestGraveYard(GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId(), GetTeam());
  5503.  
  5504. // stop countdown until repop
  5505. m_deathTimer = 0;
  5506.  
  5507. // if no grave found, stay at the current location
  5508. // and don't show spirit healer location
  5509. if (ClosestGrave)
  5510. {
  5511. TeleportTo(ClosestGrave->map_id, ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, GetOrientation());
  5512. if (isDead()) // not send if alive, because it used in TeleportTo()
  5513. {
  5514. WorldPacket data(SMSG_DEATH_RELEASE_LOC, 4*4); // show spirit healer position on minimap
  5515. data << ClosestGrave->map_id;
  5516. data << ClosestGrave->x;
  5517. data << ClosestGrave->y;
  5518. data << ClosestGrave->z;
  5519. GetSession()->SendPacket(&data);
  5520. }
  5521. }
  5522. else if (GetPositionZ() < -500.0f)
  5523. TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation());
  5524. }
  5525.  
  5526. bool Player::CanJoinConstantChannelInZone(ChatChannelsEntry const* channel, AreaTableEntry const* zone)
  5527. {
  5528. if (channel->flags & CHANNEL_DBC_FLAG_ZONE_DEP && zone->flags & AREA_FLAG_ARENA_INSTANCE)
  5529. return false;
  5530.  
  5531. if ((channel->flags & CHANNEL_DBC_FLAG_CITY_ONLY) && (!(zone->flags & AREA_FLAG_SLAVE_CAPITAL)))
  5532. return false;
  5533.  
  5534. if ((channel->flags & CHANNEL_DBC_FLAG_GUILD_REQ) && GetGuildId())
  5535. return false;
  5536.  
  5537. return true;
  5538. }
  5539.  
  5540. void Player::JoinedChannel(Channel* c)
  5541. {
  5542. m_channels.push_back(c);
  5543. }
  5544.  
  5545. void Player::LeftChannel(Channel* c)
  5546. {
  5547. m_channels.remove(c);
  5548. }
  5549.  
  5550. void Player::CleanupChannels()
  5551. {
  5552. while (!m_channels.empty())
  5553. {
  5554. Channel* ch = *m_channels.begin();
  5555. m_channels.erase(m_channels.begin()); // remove from player's channel list
  5556. ch->Leave(GetGUID(), false); // not send to client, not remove from player's channel list
  5557. if (ChannelMgr* cMgr = channelMgr(GetTeam()))
  5558. cMgr->LeftChannel(ch->GetName()); // deleted channel if empty
  5559. }
  5560. sLog->outDebug(LOG_FILTER_CHATSYS, "Player: channels cleaned up!");
  5561. }
  5562.  
  5563. void Player::UpdateLocalChannels(uint32 newZone)
  5564. {
  5565. if (GetSession()->PlayerLoading() && !IsBeingTeleportedFar())
  5566. return; // The client handles it automatically after loading, but not after teleporting
  5567.  
  5568. AreaTableEntry const* current_zone = GetAreaEntryByAreaID(newZone);
  5569. if (!current_zone)
  5570. return;
  5571.  
  5572. ChannelMgr* cMgr = channelMgr(GetTeam());
  5573. if (!cMgr)
  5574. return;
  5575.  
  5576. std::string current_zone_name = current_zone->area_name[GetSession()->GetSessionDbcLocale()];
  5577.  
  5578. for (uint32 i = 0; i < sChatChannelsStore.GetNumRows(); ++i)
  5579. {
  5580. if (ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(i))
  5581. {
  5582. Channel* usedChannel = NULL;
  5583.  
  5584. for (JoinedChannelsList::iterator itr = m_channels.begin(); itr != m_channels.end(); ++itr)
  5585. {
  5586. if ((*itr)->GetChannelId() == i)
  5587. {
  5588. usedChannel = *itr;
  5589. break;
  5590. }
  5591. }
  5592.  
  5593. Channel* removeChannel = NULL;
  5594. Channel* joinChannel = NULL;
  5595. bool sendRemove = true;
  5596.  
  5597. if (CanJoinConstantChannelInZone(channel, current_zone))
  5598. {
  5599. if (!(channel->flags & CHANNEL_DBC_FLAG_GLOBAL))
  5600. {
  5601. if (channel->flags & CHANNEL_DBC_FLAG_CITY_ONLY && usedChannel)
  5602. continue; // Already on the channel, as city channel names are not changing
  5603.  
  5604. char new_channel_name_buf[100];
  5605. char const* currentNameExt;
  5606.  
  5607. if (channel->flags & CHANNEL_DBC_FLAG_CITY_ONLY)
  5608. currentNameExt = sObjectMgr->GetTrinityStringForDBCLocale(LANG_CHANNEL_CITY);
  5609. else
  5610. currentNameExt = current_zone_name.c_str();
  5611.  
  5612. snprintf(new_channel_name_buf, 100, channel->pattern[m_session->GetSessionDbcLocale()], currentNameExt);
  5613.  
  5614. joinChannel = cMgr->GetJoinChannel(new_channel_name_buf, channel->ChannelID);
  5615. if (usedChannel)
  5616. {
  5617. if (joinChannel != usedChannel)
  5618. {
  5619. removeChannel = usedChannel;
  5620. sendRemove = false; // Do not send leave channel, it already replaced at client
  5621. }
  5622. else
  5623. joinChannel = NULL;
  5624. }
  5625. }
  5626. else
  5627. joinChannel = cMgr->GetJoinChannel(channel->pattern[m_session->GetSessionDbcLocale()], channel->ChannelID);
  5628. }
  5629. else
  5630. removeChannel = usedChannel;
  5631.  
  5632. if (joinChannel)
  5633. joinChannel->Join(GetGUID(), ""); // Changed Channel: ... or Joined Channel: ...
  5634.  
  5635. if (removeChannel)
  5636. {
  5637. removeChannel->Leave(GetGUID(), sendRemove); // Leave old channel
  5638. std::string name = removeChannel->GetName(); // Store name, (*i)erase in LeftChannel
  5639. LeftChannel(removeChannel); // Remove from player's channel list
  5640. cMgr->LeftChannel(name); // Delete if empty
  5641. }
  5642. }
  5643. }
  5644. }
  5645.  
  5646. void Player::LeaveLFGChannel()
  5647. {
  5648. for (JoinedChannelsList::iterator i = m_channels.begin(); i != m_channels.end(); ++i)
  5649. {
  5650. if ((*i)->IsLFG())
  5651. {
  5652. (*i)->Leave(GetGUID());
  5653. break;
  5654. }
  5655. }
  5656. }
  5657.  
  5658. void Player::UpdateDefense()
  5659. {
  5660. uint32 defense_skill_gain = sWorld->getIntConfig(CONFIG_SKILL_GAIN_DEFENSE);
  5661.  
  5662. if (UpdateSkill(SKILL_DEFENSE, defense_skill_gain))
  5663. {
  5664. // update dependent from defense skill part
  5665. UpdateDefenseBonusesMod();
  5666. }
  5667. }
  5668.  
  5669. void Player::HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, float amount, bool apply)
  5670. {
  5671. if (modGroup >= BASEMOD_END || modType >= MOD_END)
  5672. {
  5673. sLog->outError(LOG_FILTER_SPELLS_AURAS, "ERROR in HandleBaseModValue(): non existed BaseModGroup of wrong BaseModType!");
  5674. return;
  5675. }
  5676.  
  5677. switch (modType)
  5678. {
  5679. case FLAT_MOD:
  5680. m_auraBaseMod[modGroup][modType] += apply ? amount : -amount;
  5681. break;
  5682. case PCT_MOD:
  5683. ApplyPercentModFloatVar(m_auraBaseMod[modGroup][modType], amount, apply);
  5684. break;
  5685. }
  5686.  
  5687. if (!CanModifyStats())
  5688. return;
  5689.  
  5690. switch (modGroup)
  5691. {
  5692. case CRIT_PERCENTAGE: UpdateCritPercentage(BASE_ATTACK); break;
  5693. case RANGED_CRIT_PERCENTAGE: UpdateCritPercentage(RANGED_ATTACK); break;
  5694. case OFFHAND_CRIT_PERCENTAGE: UpdateCritPercentage(OFF_ATTACK); break;
  5695. case SHIELD_BLOCK_VALUE: UpdateShieldBlockValue(); break;
  5696. default: break;
  5697. }
  5698. }
  5699.  
  5700. float Player::GetBaseModValue(BaseModGroup modGroup, BaseModType modType) const
  5701. {
  5702. if (modGroup >= BASEMOD_END || modType > MOD_END)
  5703. {
  5704. sLog->outError(LOG_FILTER_SPELLS_AURAS, "trial to access non existed BaseModGroup or wrong BaseModType!");
  5705. return 0.0f;
  5706. }
  5707.  
  5708. if (modType == PCT_MOD && m_auraBaseMod[modGroup][PCT_MOD] <= 0.0f)
  5709. return 0.0f;
  5710.  
  5711. return m_auraBaseMod[modGroup][modType];
  5712. }
  5713.  
  5714. float Player::GetTotalBaseModValue(BaseModGroup modGroup) const
  5715. {
  5716. if (modGroup >= BASEMOD_END)
  5717. {
  5718. sLog->outError(LOG_FILTER_SPELLS_AURAS, "wrong BaseModGroup in GetTotalBaseModValue()!");
  5719. return 0.0f;
  5720. }
  5721.  
  5722. if (m_auraBaseMod[modGroup][PCT_MOD] <= 0.0f)
  5723. return 0.0f;
  5724.  
  5725. return m_auraBaseMod[modGroup][FLAT_MOD] * m_auraBaseMod[modGroup][PCT_MOD];
  5726. }
  5727.  
  5728. uint32 Player::GetShieldBlockValue() const
  5729. {
  5730. float value = (m_auraBaseMod[SHIELD_BLOCK_VALUE][FLAT_MOD] + GetStat(STAT_STRENGTH) * 0.5f - 10)*m_auraBaseMod[SHIELD_BLOCK_VALUE][PCT_MOD];
  5731.  
  5732. value = (value < 0) ? 0 : value;
  5733.  
  5734. return uint32(value);
  5735. }
  5736.  
  5737. float Player::GetMeleeCritFromAgility()
  5738. {
  5739. uint8 level = getLevel();
  5740. uint32 pclass = getClass();
  5741.  
  5742. if (level > GT_MAX_LEVEL)
  5743. level = GT_MAX_LEVEL;
  5744.  
  5745. GtChanceToMeleeCritBaseEntry const* critBase = sGtChanceToMeleeCritBaseStore.LookupEntry(pclass-1);
  5746. GtChanceToMeleeCritEntry const* critRatio = sGtChanceToMeleeCritStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1);
  5747. if (critBase == NULL || critRatio == NULL)
  5748. return 0.0f;
  5749.  
  5750. float crit = critBase->base + GetStat(STAT_AGILITY)*critRatio->ratio;
  5751. return crit*100.0f;
  5752. }
  5753.  
  5754. void Player::GetDodgeFromAgility(float &diminishing, float &nondiminishing)
  5755. {
  5756. // Table for base dodge values
  5757. const float dodge_base[MAX_CLASSES] =
  5758. {
  5759. 0.036640f, // Warrior
  5760. 0.034943f, // Paladi
  5761. -0.040873f, // Hunter
  5762. 0.020957f, // Rogue
  5763. 0.034178f, // Priest
  5764. 0.036640f, // DK
  5765. 0.021080f, // Shaman
  5766. 0.036587f, // Mage
  5767. 0.024211f, // Warlock
  5768. 0.0f, // ??
  5769. 0.056097f // Druid
  5770. };
  5771. // Crit/agility to dodge/agility coefficient multipliers; 3.2.0 increased required agility by 15%
  5772. const float crit_to_dodge[MAX_CLASSES] =
  5773. {
  5774. 0.85f/1.15f, // Warrior
  5775. 1.00f/1.15f, // Paladin
  5776. 1.11f/1.15f, // Hunter
  5777. 2.00f/1.15f, // Rogue
  5778. 1.00f/1.15f, // Priest
  5779. 0.85f/1.15f, // DK
  5780. 1.60f/1.15f, // Shaman
  5781. 1.00f/1.15f, // Mage
  5782. 0.97f/1.15f, // Warlock (?)
  5783. 0.0f, // ??
  5784. 2.00f/1.15f // Druid
  5785. };
  5786.  
  5787. uint8 level = getLevel();
  5788. uint32 pclass = getClass();
  5789.  
  5790. if (level > GT_MAX_LEVEL)
  5791. level = GT_MAX_LEVEL;
  5792.  
  5793. // Dodge per agility is proportional to crit per agility, which is available from DBC files
  5794. GtChanceToMeleeCritEntry const* dodgeRatio = sGtChanceToMeleeCritStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1);
  5795. if (dodgeRatio == NULL || pclass > MAX_CLASSES)
  5796. return;
  5797.  
  5798. // TODO: research if talents/effects that increase total agility by x% should increase non-diminishing part
  5799. float base_agility = GetCreateStat(STAT_AGILITY) * m_auraModifiersGroup[UNIT_MOD_STAT_START + STAT_AGILITY][BASE_PCT];
  5800. float bonus_agility = GetStat(STAT_AGILITY) - base_agility;
  5801.  
  5802. // calculate diminishing (green in char screen) and non-diminishing (white) contribution
  5803. diminishing = 100.0f * bonus_agility * dodgeRatio->ratio * crit_to_dodge[pclass-1];
  5804. nondiminishing = 100.0f * (dodge_base[pclass-1] + base_agility * dodgeRatio->ratio * crit_to_dodge[pclass-1]);
  5805. }
  5806.  
  5807. float Player::GetSpellCritFromIntellect()
  5808. {
  5809. uint8 level = getLevel();
  5810. uint32 pclass = getClass();
  5811.  
  5812. if (level > GT_MAX_LEVEL)
  5813. level = GT_MAX_LEVEL;
  5814.  
  5815. GtChanceToSpellCritBaseEntry const* critBase = sGtChanceToSpellCritBaseStore.LookupEntry(pclass-1);
  5816. GtChanceToSpellCritEntry const* critRatio = sGtChanceToSpellCritStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1);
  5817. if (critBase == NULL || critRatio == NULL)
  5818. return 0.0f;
  5819.  
  5820. float crit=critBase->base + GetStat(STAT_INTELLECT)*critRatio->ratio;
  5821. return crit*100.0f;
  5822. }
  5823.  
  5824. float Player::GetRatingMultiplier(CombatRating cr) const
  5825. {
  5826. uint8 level = getLevel();
  5827.  
  5828. if (level > GT_MAX_LEVEL)
  5829. level = GT_MAX_LEVEL;
  5830.  
  5831. GtCombatRatingsEntry const* Rating = sGtCombatRatingsStore.LookupEntry(cr*GT_MAX_LEVEL+level-1);
  5832. // gtOCTClassCombatRatingScalarStore.dbc starts with 1, CombatRating with zero, so cr+1
  5833. GtOCTClassCombatRatingScalarEntry const* classRating = sGtOCTClassCombatRatingScalarStore.LookupEntry((getClass()-1)*GT_MAX_RATING+cr+1);
  5834. if (!Rating || !classRating)
  5835. return 1.0f; // By default use minimum coefficient (not must be called)
  5836.  
  5837. return classRating->ratio / Rating->ratio;
  5838. }
  5839.  
  5840. float Player::GetRatingBonusValue(CombatRating cr) const
  5841. {
  5842. return float(GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + cr)) * GetRatingMultiplier(cr);
  5843. }
  5844.  
  5845. float Player::GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const
  5846. {
  5847. switch (attType)
  5848. {
  5849. case BASE_ATTACK:
  5850. return GetUInt32Value(PLAYER_EXPERTISE) / 4.0f;
  5851. case OFF_ATTACK:
  5852. return GetUInt32Value(PLAYER_OFFHAND_EXPERTISE) / 4.0f;
  5853. default:
  5854. break;
  5855. }
  5856. return 0.0f;
  5857. }
  5858.  
  5859. float Player::OCTRegenHPPerSpirit()
  5860. {
  5861. uint8 level = getLevel();
  5862. uint32 pclass = getClass();
  5863.  
  5864. if (level > GT_MAX_LEVEL)
  5865. level = GT_MAX_LEVEL;
  5866.  
  5867. GtOCTRegenHPEntry const* baseRatio = sGtOCTRegenHPStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1);
  5868. GtRegenHPPerSptEntry const* moreRatio = sGtRegenHPPerSptStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1);
  5869. if (baseRatio == NULL || moreRatio == NULL)
  5870. return 0.0f;
  5871.  
  5872. // Formula from PaperDollFrame script
  5873. float spirit = GetStat(STAT_SPIRIT);
  5874. float baseSpirit = spirit;
  5875. if (baseSpirit > 50)
  5876. baseSpirit = 50;
  5877. float moreSpirit = spirit - baseSpirit;
  5878. float regen = baseSpirit * baseRatio->ratio + moreSpirit * moreRatio->ratio;
  5879. return regen;
  5880. }
  5881.  
  5882. float Player::OCTRegenMPPerSpirit()
  5883. {
  5884. uint8 level = getLevel();
  5885. uint32 pclass = getClass();
  5886.  
  5887. if (level > GT_MAX_LEVEL)
  5888. level = GT_MAX_LEVEL;
  5889.  
  5890. // GtOCTRegenMPEntry const* baseRatio = sGtOCTRegenMPStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1);
  5891. GtRegenMPPerSptEntry const* moreRatio = sGtRegenMPPerSptStore.LookupEntry((pclass-1)*GT_MAX_LEVEL + level-1);
  5892. if (moreRatio == NULL)
  5893. return 0.0f;
  5894.  
  5895. // Formula get from PaperDollFrame script
  5896. float spirit = GetStat(STAT_SPIRIT);
  5897. float regen = spirit * moreRatio->ratio;
  5898. return regen;
  5899. }
  5900.  
  5901. void Player::ApplyRatingMod(CombatRating cr, int32 value, bool apply)
  5902. {
  5903. m_baseRatingValue[cr]+=(apply ? value : -value);
  5904.  
  5905. // explicit affected values
  5906. switch (cr)
  5907. {
  5908. case CR_HASTE_MELEE:
  5909. {
  5910. float RatingChange = value * GetRatingMultiplier(cr);
  5911. ApplyAttackTimePercentMod(BASE_ATTACK, RatingChange, apply);
  5912. ApplyAttackTimePercentMod(OFF_ATTACK, RatingChange, apply);
  5913. break;
  5914. }
  5915. case CR_HASTE_RANGED:
  5916. {
  5917. float RatingChange = value * GetRatingMultiplier(cr);
  5918. ApplyAttackTimePercentMod(RANGED_ATTACK, RatingChange, apply);
  5919. break;
  5920. }
  5921. case CR_HASTE_SPELL:
  5922. {
  5923. float RatingChange = value * GetRatingMultiplier(cr);
  5924. ApplyCastTimePercentMod(RatingChange, apply);
  5925. break;
  5926. }
  5927. default:
  5928. break;
  5929. }
  5930.  
  5931. UpdateRating(cr);
  5932. }
  5933.  
  5934. void Player::UpdateRating(CombatRating cr)
  5935. {
  5936. int32 amount = m_baseRatingValue[cr];
  5937. // Apply bonus from SPELL_AURA_MOD_RATING_FROM_STAT
  5938. // stat used stored in miscValueB for this aura
  5939. AuraEffectList const& modRatingFromStat = GetAuraEffectsByType(SPELL_AURA_MOD_RATING_FROM_STAT);
  5940. for (AuraEffectList::const_iterator i = modRatingFromStat.begin(); i != modRatingFromStat.end(); ++i)
  5941. if ((*i)->GetMiscValue() & (1<<cr))
  5942. amount += int32(CalculatePctN(GetStat(Stats((*i)->GetMiscValueB())), (*i)->GetAmount()));
  5943. if (amount < 0)
  5944. amount = 0;
  5945. SetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + cr, uint32(amount));
  5946.  
  5947. bool affectStats = CanModifyStats();
  5948.  
  5949. switch (cr)
  5950. {
  5951. case CR_WEAPON_SKILL: // Implemented in Unit::RollMeleeOutcomeAgainst
  5952. case CR_DEFENSE_SKILL:
  5953. UpdateDefenseBonusesMod();
  5954. break;
  5955. case CR_DODGE:
  5956. UpdateDodgePercentage();
  5957. break;
  5958. case CR_PARRY:
  5959. UpdateParryPercentage();
  5960. break;
  5961. case CR_BLOCK:
  5962. UpdateBlockPercentage();
  5963. break;
  5964. case CR_HIT_MELEE:
  5965. UpdateMeleeHitChances();
  5966. break;
  5967. case CR_HIT_RANGED:
  5968. UpdateRangedHitChances();
  5969. break;
  5970. case CR_HIT_SPELL:
  5971. UpdateSpellHitChances();
  5972. break;
  5973. case CR_CRIT_MELEE:
  5974. if (affectStats)
  5975. {
  5976. UpdateCritPercentage(BASE_ATTACK);
  5977. UpdateCritPercentage(OFF_ATTACK);
  5978. }
  5979. break;
  5980. case CR_CRIT_RANGED:
  5981. if (affectStats)
  5982. UpdateCritPercentage(RANGED_ATTACK);
  5983. break;
  5984. case CR_CRIT_SPELL:
  5985. if (affectStats)
  5986. UpdateAllSpellCritChances();
  5987. break;
  5988. case CR_HIT_TAKEN_MELEE: // Implemented in Unit::MeleeMissChanceCalc
  5989. case CR_HIT_TAKEN_RANGED:
  5990. break;
  5991. case CR_HIT_TAKEN_SPELL: // Implemented in Unit::MagicSpellHitResult
  5992. break;
  5993. case CR_CRIT_TAKEN_MELEE: // Implemented in Unit::RollMeleeOutcomeAgainst (only for chance to crit)
  5994. case CR_CRIT_TAKEN_RANGED:
  5995. break;
  5996. case CR_CRIT_TAKEN_SPELL: // Implemented in Unit::SpellCriticalBonus (only for chance to crit)
  5997. break;
  5998. case CR_HASTE_MELEE: // Implemented in Player::ApplyRatingMod
  5999. case CR_HASTE_RANGED:
  6000. case CR_HASTE_SPELL:
  6001. break;
  6002. case CR_WEAPON_SKILL_MAINHAND: // Implemented in Unit::RollMeleeOutcomeAgainst
  6003. case CR_WEAPON_SKILL_OFFHAND:
  6004. case CR_WEAPON_SKILL_RANGED:
  6005. break;
  6006. case CR_EXPERTISE:
  6007. if (affectStats)
  6008. {
  6009. UpdateExpertise(BASE_ATTACK);
  6010. UpdateExpertise(OFF_ATTACK);
  6011. }
  6012. break;
  6013. case CR_ARMOR_PENETRATION:
  6014. if (affectStats)
  6015. UpdateArmorPenetration(amount);
  6016. break;
  6017. }
  6018. }
  6019.  
  6020. void Player::UpdateAllRatings()
  6021. {
  6022. for (int cr = 0; cr < MAX_COMBAT_RATING; ++cr)
  6023. UpdateRating(CombatRating(cr));
  6024. }
  6025.  
  6026. void Player::SetRegularAttackTime()
  6027. {
  6028. for (uint8 i = 0; i < MAX_ATTACK; ++i)
  6029. {
  6030. Item* tmpitem = GetWeaponForAttack(WeaponAttackType(i), true);
  6031. if (tmpitem && !tmpitem->IsBroken())
  6032. {
  6033. ItemTemplate const* proto = tmpitem->GetTemplate();
  6034. if (proto->Delay)
  6035. SetAttackTime(WeaponAttackType(i), proto->Delay);
  6036. }
  6037. else
  6038. SetAttackTime(WeaponAttackType(i), BASE_ATTACK_TIME); // If there is no weapon reset attack time to base (might have been changed from forms)
  6039. }
  6040. }
  6041.  
  6042. //skill+step, checking for max value
  6043. bool Player::UpdateSkill(uint32 skill_id, uint32 step)
  6044. {
  6045. if (!skill_id)
  6046. return false;
  6047.  
  6048. if (skill_id == SKILL_FIST_WEAPONS)
  6049. skill_id = SKILL_UNARMED;
  6050.  
  6051. SkillStatusMap::iterator itr = mSkillStatus.find(skill_id);
  6052. if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED)
  6053. return false;
  6054.  
  6055. uint32 valueIndex = PLAYER_SKILL_VALUE_INDEX(itr->second.pos);
  6056. uint32 data = GetUInt32Value(valueIndex);
  6057. uint32 value = SKILL_VALUE(data);
  6058. uint32 max = SKILL_MAX(data);
  6059.  
  6060. if ((!max) || (!value) || (value >= max))
  6061. return false;
  6062.  
  6063. if (value < max)
  6064. {
  6065. uint32 new_value = value+step;
  6066. if (new_value > max)
  6067. new_value = max;
  6068.  
  6069. SetUInt32Value(valueIndex, MAKE_SKILL_VALUE(new_value, max));
  6070. if (itr->second.uState != SKILL_NEW)
  6071. itr->second.uState = SKILL_CHANGED;
  6072. UpdateSkillEnchantments(skill_id, value, new_value);
  6073. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, skill_id);
  6074. return true;
  6075. }
  6076.  
  6077. return false;
  6078. }
  6079.  
  6080. inline int SkillGainChance(uint32 SkillValue, uint32 GrayLevel, uint32 GreenLevel, uint32 YellowLevel)
  6081. {
  6082. if (SkillValue >= GrayLevel)
  6083. return sWorld->getIntConfig(CONFIG_SKILL_CHANCE_GREY)*10;
  6084. if (SkillValue >= GreenLevel)
  6085. return sWorld->getIntConfig(CONFIG_SKILL_CHANCE_GREEN)*10;
  6086. if (SkillValue >= YellowLevel)
  6087. return sWorld->getIntConfig(CONFIG_SKILL_CHANCE_YELLOW)*10;
  6088. return sWorld->getIntConfig(CONFIG_SKILL_CHANCE_ORANGE)*10;
  6089. }
  6090.  
  6091. bool Player::UpdateCraftSkill(uint32 spellid)
  6092. {
  6093. sLog->outDebug(LOG_FILTER_PLAYER_SKILLS, "UpdateCraftSkill spellid %d", spellid);
  6094.  
  6095. SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellid);
  6096.  
  6097. for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
  6098. {
  6099. if (_spell_idx->second->skillId)
  6100. {
  6101. uint32 SkillValue = GetPureSkillValue(_spell_idx->second->skillId);
  6102.  
  6103. // Alchemy Discoveries here
  6104. SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(spellid);
  6105. if (spellEntry && spellEntry->Mechanic == MECHANIC_DISCOVERY)
  6106. {
  6107. if (uint32 discoveredSpell = GetSkillDiscoverySpell(_spell_idx->second->skillId, spellid, this))
  6108. learnSpell(discoveredSpell, false);
  6109. }
  6110.  
  6111. uint32 craft_skill_gain = sWorld->getIntConfig(CONFIG_SKILL_GAIN_CRAFTING);
  6112.  
  6113. return UpdateSkillPro(_spell_idx->second->skillId, SkillGainChance(SkillValue,
  6114. _spell_idx->second->max_value,
  6115. (_spell_idx->second->max_value + _spell_idx->second->min_value)/2,
  6116. _spell_idx->second->min_value),
  6117. craft_skill_gain);
  6118. }
  6119. }
  6120. return false;
  6121. }
  6122.  
  6123. bool Player::UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLevel, uint32 Multiplicator)
  6124. {
  6125. sLog->outDebug(LOG_FILTER_PLAYER_SKILLS, "UpdateGatherSkill(SkillId %d SkillLevel %d RedLevel %d)", SkillId, SkillValue, RedLevel);
  6126.  
  6127. uint32 gathering_skill_gain = sWorld->getIntConfig(CONFIG_SKILL_GAIN_GATHERING);
  6128.  
  6129. // For skinning and Mining chance decrease with level. 1-74 - no decrease, 75-149 - 2 times, 225-299 - 8 times
  6130. switch (SkillId)
  6131. {
  6132. case SKILL_HERBALISM:
  6133. case SKILL_LOCKPICKING:
  6134. case SKILL_JEWELCRAFTING:
  6135. case SKILL_INSCRIPTION:
  6136. return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator, gathering_skill_gain);
  6137. case SKILL_SKINNING:
  6138. if (sWorld->getIntConfig(CONFIG_SKILL_CHANCE_SKINNING_STEPS) == 0)
  6139. return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator, gathering_skill_gain);
  6140. else
  6141. return UpdateSkillPro(SkillId, (SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator) >> (SkillValue/sWorld->getIntConfig(CONFIG_SKILL_CHANCE_SKINNING_STEPS)), gathering_skill_gain);
  6142. case SKILL_MINING:
  6143. if (sWorld->getIntConfig(CONFIG_SKILL_CHANCE_MINING_STEPS) == 0)
  6144. return UpdateSkillPro(SkillId, SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator, gathering_skill_gain);
  6145. else
  6146. return UpdateSkillPro(SkillId, (SkillGainChance(SkillValue, RedLevel+100, RedLevel+50, RedLevel+25)*Multiplicator) >> (SkillValue/sWorld->getIntConfig(CONFIG_SKILL_CHANCE_MINING_STEPS)), gathering_skill_gain);
  6147. }
  6148. return false;
  6149. }
  6150.  
  6151. bool Player::UpdateFishingSkill()
  6152. {
  6153. sLog->outDebug(LOG_FILTER_PLAYER_SKILLS, "UpdateFishingSkill");
  6154.  
  6155. uint32 SkillValue = GetPureSkillValue(SKILL_FISHING);
  6156.  
  6157. int32 chance = SkillValue < 75 ? 100 : 2500/(SkillValue-50);
  6158.  
  6159. uint32 gathering_skill_gain = sWorld->getIntConfig(CONFIG_SKILL_GAIN_GATHERING);
  6160.  
  6161. return UpdateSkillPro(SKILL_FISHING, chance*10, gathering_skill_gain);
  6162. }
  6163.  
  6164. // levels sync. with spell requirement for skill levels to learn
  6165. // bonus abilities in sSkillLineAbilityStore
  6166. // Used only to avoid scan DBC at each skill grow
  6167. static uint32 bonusSkillLevels[] = {75, 150, 225, 300, 375, 450};
  6168. static const size_t bonusSkillLevelsSize = sizeof(bonusSkillLevels) / sizeof(uint32);
  6169.  
  6170. bool Player::UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step)
  6171. {
  6172. sLog->outDebug(LOG_FILTER_PLAYER_SKILLS, "UpdateSkillPro(SkillId %d, Chance %3.1f%%)", SkillId, Chance / 10.0f);
  6173. if (!SkillId)
  6174. return false;
  6175.  
  6176. if (Chance <= 0) // speedup in 0 chance case
  6177. {
  6178. sLog->outDebug(LOG_FILTER_PLAYER_SKILLS, "Player::UpdateSkillPro Chance=%3.1f%% missed", Chance / 10.0f);
  6179. return false;
  6180. }
  6181.  
  6182. SkillStatusMap::iterator itr = mSkillStatus.find(SkillId);
  6183. if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED)
  6184. return false;
  6185.  
  6186. uint32 valueIndex = PLAYER_SKILL_VALUE_INDEX(itr->second.pos);
  6187.  
  6188. uint32 data = GetUInt32Value(valueIndex);
  6189. uint16 SkillValue = SKILL_VALUE(data);
  6190. uint16 MaxValue = SKILL_MAX(data);
  6191.  
  6192. if (!MaxValue || !SkillValue || SkillValue >= MaxValue)
  6193. return false;
  6194.  
  6195. int32 Roll = irand(1, 1000);
  6196.  
  6197. if (Roll <= Chance)
  6198. {
  6199. uint32 new_value = SkillValue+step;
  6200. if (new_value > MaxValue)
  6201. new_value = MaxValue;
  6202.  
  6203. SetUInt32Value(valueIndex, MAKE_SKILL_VALUE(new_value, MaxValue));
  6204. if (itr->second.uState != SKILL_NEW)
  6205. itr->second.uState = SKILL_CHANGED;
  6206. for (size_t i = 0; i < bonusSkillLevelsSize; ++i)
  6207. {
  6208. uint32 bsl = bonusSkillLevels[i];
  6209. if (SkillValue < bsl && new_value >= bsl)
  6210. {
  6211. learnSkillRewardedSpells(SkillId, new_value);
  6212. break;
  6213. }
  6214. }
  6215. UpdateSkillEnchantments(SkillId, SkillValue, new_value);
  6216. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, SkillId);
  6217. sLog->outDebug(LOG_FILTER_PLAYER_SKILLS, "Player::UpdateSkillPro Chance=%3.1f%% taken", Chance / 10.0f);
  6218. return true;
  6219. }
  6220.  
  6221. sLog->outDebug(LOG_FILTER_PLAYER_SKILLS, "Player::UpdateSkillPro Chance=%3.1f%% missed", Chance / 10.0f);
  6222. return false;
  6223. }
  6224.  
  6225. void Player::UpdateWeaponSkill(WeaponAttackType attType)
  6226. {
  6227. // no skill gain in pvp
  6228. Unit* victim = getVictim();
  6229. if (victim && victim->GetTypeId() == TYPEID_PLAYER)
  6230. return;
  6231.  
  6232. if (IsInFeralForm())
  6233. return; // always maximized SKILL_FERAL_COMBAT in fact
  6234.  
  6235. if (GetShapeshiftForm() == FORM_TREE)
  6236. return; // use weapon but not skill up
  6237.  
  6238. if (victim && victim->GetTypeId() == TYPEID_UNIT && (victim->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_SKILLGAIN))
  6239. return;
  6240.  
  6241. uint32 weapon_skill_gain = sWorld->getIntConfig(CONFIG_SKILL_GAIN_WEAPON);
  6242.  
  6243. Item* tmpitem = GetWeaponForAttack(attType, true);
  6244. if (!tmpitem && attType == BASE_ATTACK)
  6245. UpdateSkill(SKILL_UNARMED, weapon_skill_gain);
  6246. else if (tmpitem && tmpitem->GetTemplate()->SubClass != ITEM_SUBCLASS_WEAPON_FISHING_POLE)
  6247. UpdateSkill(tmpitem->GetSkill(), weapon_skill_gain);
  6248.  
  6249. UpdateAllCritPercentages();
  6250. }
  6251.  
  6252. void Player::UpdateCombatSkills(Unit* victim, WeaponAttackType attType, bool defence)
  6253. {
  6254. uint8 plevel = getLevel(); // if defense than victim == attacker
  6255. uint8 greylevel = Trinity::XP::GetGrayLevel(plevel);
  6256. uint8 moblevel = victim->getLevelForTarget(this);
  6257. if (moblevel < greylevel)
  6258. return;
  6259.  
  6260. if (moblevel > plevel + 5)
  6261. moblevel = plevel + 5;
  6262.  
  6263. uint8 lvldif = moblevel - greylevel;
  6264. if (lvldif < 3)
  6265. lvldif = 3;
  6266.  
  6267. uint32 skilldif = 5 * plevel - (defence ? GetBaseDefenseSkillValue() : GetBaseWeaponSkillValue(attType));
  6268. if (skilldif <= 0)
  6269. return;
  6270.  
  6271. float chance = float(3 * lvldif * skilldif) / plevel;
  6272. if (!defence)
  6273. if (getClass() == CLASS_WARRIOR || getClass() == CLASS_ROGUE)
  6274. chance += chance * 0.02f * GetStat(STAT_INTELLECT);
  6275.  
  6276. chance = chance < 1.0f ? 1.0f : chance; //minimum chance to increase skill is 1%
  6277.  
  6278. if (roll_chance_f(chance))
  6279. {
  6280. if (defence)
  6281. UpdateDefense();
  6282. else
  6283. UpdateWeaponSkill(attType);
  6284. }
  6285. else
  6286. return;
  6287. }
  6288.  
  6289. void Player::ModifySkillBonus(uint32 skillid, int32 val, bool talent)
  6290. {
  6291. SkillStatusMap::const_iterator itr = mSkillStatus.find(skillid);
  6292. if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED)
  6293. return;
  6294.  
  6295. uint32 bonusIndex = PLAYER_SKILL_BONUS_INDEX(itr->second.pos);
  6296.  
  6297. uint32 bonus_val = GetUInt32Value(bonusIndex);
  6298. int16 temp_bonus = SKILL_TEMP_BONUS(bonus_val);
  6299. int16 perm_bonus = SKILL_PERM_BONUS(bonus_val);
  6300.  
  6301. if (talent) // permanent bonus stored in high part
  6302. SetUInt32Value(bonusIndex, MAKE_SKILL_BONUS(temp_bonus, perm_bonus+val));
  6303. else // temporary/item bonus stored in low part
  6304. SetUInt32Value(bonusIndex, MAKE_SKILL_BONUS(temp_bonus+val, perm_bonus));
  6305. }
  6306.  
  6307. void Player::UpdateSkillsForLevel()
  6308. {
  6309. uint16 maxconfskill = sWorld->GetConfigMaxSkillValue();
  6310. uint32 maxSkill = GetMaxSkillValueForLevel();
  6311.  
  6312. bool alwaysMaxSkill = sWorld->getBoolConfig(CONFIG_ALWAYS_MAX_SKILL_FOR_LEVEL);
  6313.  
  6314. for (SkillStatusMap::iterator itr = mSkillStatus.begin(); itr != mSkillStatus.end(); ++itr)
  6315. {
  6316. if (itr->second.uState == SKILL_DELETED)
  6317. continue;
  6318.  
  6319. uint32 pskill = itr->first;
  6320. SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(pskill);
  6321. if (!pSkill)
  6322. continue;
  6323.  
  6324. if (GetSkillRangeType(pSkill, false) != SKILL_RANGE_LEVEL)
  6325. continue;
  6326.  
  6327. uint32 valueIndex = PLAYER_SKILL_VALUE_INDEX(itr->second.pos);
  6328. uint32 data = GetUInt32Value(valueIndex);
  6329. uint32 max = SKILL_MAX(data);
  6330. uint32 val = SKILL_VALUE(data);
  6331.  
  6332. /// update only level dependent max skill values
  6333. if (max != 1)
  6334. {
  6335. /// maximize skill always
  6336. if (alwaysMaxSkill)
  6337. {
  6338. SetUInt32Value(valueIndex, MAKE_SKILL_VALUE(maxSkill, maxSkill));
  6339. if (itr->second.uState != SKILL_NEW)
  6340. itr->second.uState = SKILL_CHANGED;
  6341. }
  6342. else if (max != maxconfskill) /// update max skill value if current max skill not maximized
  6343. {
  6344. SetUInt32Value(valueIndex, MAKE_SKILL_VALUE(val, maxSkill));
  6345. if (itr->second.uState != SKILL_NEW)
  6346. itr->second.uState = SKILL_CHANGED;
  6347. }
  6348. }
  6349. }
  6350. }
  6351.  
  6352. void Player::UpdateSkillsToMaxSkillsForLevel()
  6353. {
  6354. for (SkillStatusMap::iterator itr = mSkillStatus.begin(); itr != mSkillStatus.end(); ++itr)
  6355. {
  6356. if (itr->second.uState == SKILL_DELETED)
  6357. continue;
  6358.  
  6359. uint32 pskill = itr->first;
  6360. if (IsProfessionOrRidingSkill(pskill))
  6361. continue;
  6362. uint32 valueIndex = PLAYER_SKILL_VALUE_INDEX(itr->second.pos);
  6363. uint32 data = GetUInt32Value(valueIndex);
  6364. uint32 max = SKILL_MAX(data);
  6365.  
  6366. if (max > 1)
  6367. {
  6368. SetUInt32Value(valueIndex, MAKE_SKILL_VALUE(max, max));
  6369. if (itr->second.uState != SKILL_NEW)
  6370. itr->second.uState = SKILL_CHANGED;
  6371. }
  6372. if (pskill == SKILL_DEFENSE)
  6373. UpdateDefenseBonusesMod();
  6374. }
  6375. }
  6376.  
  6377. // This functions sets a skill line value (and adds if doesn't exist yet)
  6378. // To "remove" a skill line, set it's values to zero
  6379. void Player::SetSkill(uint16 id, uint16 step, uint16 newVal, uint16 maxVal)
  6380. {
  6381. if (!id)
  6382. return;
  6383.  
  6384. uint16 currVal;
  6385. SkillStatusMap::iterator itr = mSkillStatus.find(id);
  6386.  
  6387. //has skill
  6388. if (itr != mSkillStatus.end() && itr->second.uState != SKILL_DELETED)
  6389. {
  6390. currVal = SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos)));
  6391. if (newVal)
  6392. {
  6393. // if skill value is going down, update enchantments before setting the new value
  6394. if (newVal < currVal)
  6395. UpdateSkillEnchantments(id, currVal, newVal);
  6396. // update step
  6397. SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos), MAKE_PAIR32(id, step));
  6398. // update value
  6399. SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos), MAKE_SKILL_VALUE(newVal, maxVal));
  6400. if (itr->second.uState != SKILL_NEW)
  6401. itr->second.uState = SKILL_CHANGED;
  6402. learnSkillRewardedSpells(id, newVal);
  6403. // if skill value is going up, update enchantments after setting the new value
  6404. if (newVal > currVal)
  6405. UpdateSkillEnchantments(id, currVal, newVal);
  6406. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, id);
  6407. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL, id);
  6408. }
  6409. else //remove
  6410. {
  6411. //remove enchantments needing this skill
  6412. UpdateSkillEnchantments(id, currVal, 0);
  6413. // clear skill fields
  6414. SetUInt32Value(PLAYER_SKILL_INDEX(itr->second.pos), 0);
  6415. SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos), 0);
  6416. SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(itr->second.pos), 0);
  6417.  
  6418. // mark as deleted or simply remove from map if not saved yet
  6419. if (itr->second.uState != SKILL_NEW)
  6420. itr->second.uState = SKILL_DELETED;
  6421. else
  6422. mSkillStatus.erase(itr);
  6423.  
  6424. // remove all spells that related to this skill
  6425. for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j)
  6426. if (SkillLineAbilityEntry const* pAbility = sSkillLineAbilityStore.LookupEntry(j))
  6427. if (pAbility->skillId == id)
  6428. removeSpell(sSpellMgr->GetFirstSpellInChain(pAbility->spellId));
  6429. }
  6430. }
  6431. else if (newVal) //add
  6432. {
  6433. currVal = 0;
  6434. for (int i=0; i < PLAYER_MAX_SKILLS; ++i)
  6435. if (!GetUInt32Value(PLAYER_SKILL_INDEX(i)))
  6436. {
  6437. SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(id);
  6438. if (!pSkill)
  6439. {
  6440. sLog->outError(LOG_FILTER_PLAYER_SKILLS, "Skill not found in SkillLineStore: skill #%u", id);
  6441. return;
  6442. }
  6443.  
  6444. SetUInt32Value(PLAYER_SKILL_INDEX(i), MAKE_PAIR32(id, step));
  6445. SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i), MAKE_SKILL_VALUE(newVal, maxVal));
  6446. UpdateSkillEnchantments(id, currVal, newVal);
  6447. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, id);
  6448. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL, id);
  6449.  
  6450. // insert new entry or update if not deleted old entry yet
  6451. if (itr != mSkillStatus.end())
  6452. {
  6453. itr->second.pos = i;
  6454. itr->second.uState = SKILL_CHANGED;
  6455. }
  6456. else
  6457. mSkillStatus.insert(SkillStatusMap::value_type(id, SkillStatusData(i, SKILL_NEW)));
  6458.  
  6459. // apply skill bonuses
  6460. SetUInt32Value(PLAYER_SKILL_BONUS_INDEX(i), 0);
  6461.  
  6462. // temporary bonuses
  6463. AuraEffectList const& mModSkill = GetAuraEffectsByType(SPELL_AURA_MOD_SKILL);
  6464. for (AuraEffectList::const_iterator j = mModSkill.begin(); j != mModSkill.end(); ++j)
  6465. if ((*j)->GetMiscValue() == int32(id))
  6466. (*j)->HandleEffect(this, AURA_EFFECT_HANDLE_SKILL, true);
  6467.  
  6468. // permanent bonuses
  6469. AuraEffectList const& mModSkillTalent = GetAuraEffectsByType(SPELL_AURA_MOD_SKILL_TALENT);
  6470. for (AuraEffectList::const_iterator j = mModSkillTalent.begin(); j != mModSkillTalent.end(); ++j)
  6471. if ((*j)->GetMiscValue() == int32(id))
  6472. (*j)->HandleEffect(this, AURA_EFFECT_HANDLE_SKILL, true);
  6473.  
  6474. // Learn all spells for skill
  6475. learnSkillRewardedSpells(id, newVal);
  6476. return;
  6477. }
  6478. }
  6479. }
  6480.  
  6481. bool Player::HasSkill(uint32 skill) const
  6482. {
  6483. if (!skill)
  6484. return false;
  6485.  
  6486. SkillStatusMap::const_iterator itr = mSkillStatus.find(skill);
  6487. return (itr != mSkillStatus.end() && itr->second.uState != SKILL_DELETED);
  6488. }
  6489.  
  6490. uint16 Player::GetSkillStep(uint16 skill) const
  6491. {
  6492. if (!skill)
  6493. return 0;
  6494.  
  6495. SkillStatusMap::const_iterator itr = mSkillStatus.find(skill);
  6496. if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED)
  6497. return 0;
  6498.  
  6499. return PAIR32_HIPART(GetUInt32Value(PLAYER_SKILL_INDEX(itr->second.pos)));
  6500. }
  6501.  
  6502. uint16 Player::GetSkillValue(uint32 skill) const
  6503. {
  6504. if (!skill)
  6505. return 0;
  6506.  
  6507. SkillStatusMap::const_iterator itr = mSkillStatus.find(skill);
  6508. if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED)
  6509. return 0;
  6510.  
  6511. uint32 bonus = GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(itr->second.pos));
  6512.  
  6513. int32 result = int32(SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos))));
  6514. result += SKILL_TEMP_BONUS(bonus);
  6515. result += SKILL_PERM_BONUS(bonus);
  6516. return result < 0 ? 0 : result;
  6517. }
  6518.  
  6519. uint16 Player::GetMaxSkillValue(uint32 skill) const
  6520. {
  6521. if (!skill)
  6522. return 0;
  6523.  
  6524. SkillStatusMap::const_iterator itr = mSkillStatus.find(skill);
  6525. if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED)
  6526. return 0;
  6527.  
  6528. uint32 bonus = GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(itr->second.pos));
  6529.  
  6530. int32 result = int32(SKILL_MAX(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos))));
  6531. result += SKILL_TEMP_BONUS(bonus);
  6532. result += SKILL_PERM_BONUS(bonus);
  6533. return result < 0 ? 0 : result;
  6534. }
  6535.  
  6536. uint16 Player::GetPureMaxSkillValue(uint32 skill) const
  6537. {
  6538. if (!skill)
  6539. return 0;
  6540.  
  6541. SkillStatusMap::const_iterator itr = mSkillStatus.find(skill);
  6542. if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED)
  6543. return 0;
  6544.  
  6545. return SKILL_MAX(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos)));
  6546. }
  6547.  
  6548. uint16 Player::GetBaseSkillValue(uint32 skill) const
  6549. {
  6550. if (!skill)
  6551. return 0;
  6552.  
  6553. SkillStatusMap::const_iterator itr = mSkillStatus.find(skill);
  6554. if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED)
  6555. return 0;
  6556.  
  6557. int32 result = int32(SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos))));
  6558. result += SKILL_PERM_BONUS(GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(itr->second.pos)));
  6559. return result < 0 ? 0 : result;
  6560. }
  6561.  
  6562. uint16 Player::GetPureSkillValue(uint32 skill) const
  6563. {
  6564. if (!skill)
  6565. return 0;
  6566.  
  6567. SkillStatusMap::const_iterator itr = mSkillStatus.find(skill);
  6568. if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED)
  6569. return 0;
  6570.  
  6571. return SKILL_VALUE(GetUInt32Value(PLAYER_SKILL_VALUE_INDEX(itr->second.pos)));
  6572. }
  6573.  
  6574. int16 Player::GetSkillPermBonusValue(uint32 skill) const
  6575. {
  6576. if (!skill)
  6577. return 0;
  6578.  
  6579. SkillStatusMap::const_iterator itr = mSkillStatus.find(skill);
  6580. if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED)
  6581. return 0;
  6582.  
  6583. return SKILL_PERM_BONUS(GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(itr->second.pos)));
  6584. }
  6585.  
  6586. int16 Player::GetSkillTempBonusValue(uint32 skill) const
  6587. {
  6588. if (!skill)
  6589. return 0;
  6590.  
  6591. SkillStatusMap::const_iterator itr = mSkillStatus.find(skill);
  6592. if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED)
  6593. return 0;
  6594.  
  6595. return SKILL_TEMP_BONUS(GetUInt32Value(PLAYER_SKILL_BONUS_INDEX(itr->second.pos)));
  6596. }
  6597.  
  6598. void Player::SendActionButtons(uint32 state) const
  6599. {
  6600. WorldPacket data(SMSG_ACTION_BUTTONS, 1+(MAX_ACTION_BUTTONS*4));
  6601. data << uint8(state);
  6602. /*
  6603. state can be 0, 1, 2
  6604. 0 - Looks to be sent when initial action buttons get sent, however on Trinity we use 1 since 0 had some difficulties
  6605. 1 - Used in any SMSG_ACTION_BUTTONS packet with button data on Trinity. Only used after spec swaps on retail.
  6606. 2 - Clears the action bars client sided. This is sent during spec swap before unlearning and before sending the new buttons
  6607. */
  6608. if (state != 2)
  6609. {
  6610. for (uint8 button = 0; button < MAX_ACTION_BUTTONS; ++button)
  6611. {
  6612. ActionButtonList::const_iterator itr = m_actionButtons.find(button);
  6613. if (itr != m_actionButtons.end() && itr->second.uState != ACTIONBUTTON_DELETED)
  6614. data << uint32(itr->second.packedData);
  6615. else
  6616. data << uint32(0);
  6617. }
  6618. }
  6619.  
  6620. GetSession()->SendPacket(&data);
  6621. sLog->outInfo(LOG_FILTER_NETWORKIO, "SMSG_ACTION_BUTTONS sent '%u' spec '%u' Sent", GetGUIDLow(), m_activeSpec);
  6622. }
  6623.  
  6624. bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type)
  6625. {
  6626. if (button >= MAX_ACTION_BUTTONS)
  6627. {
  6628. sLog->outError(LOG_FILTER_PLAYER_LOADING, "Action %u not added into button %u for player %s: button must be < %u", action, button, GetName(), MAX_ACTION_BUTTONS);
  6629. return false;
  6630. }
  6631.  
  6632. if (action >= MAX_ACTION_BUTTON_ACTION_VALUE)
  6633. {
  6634. sLog->outError(LOG_FILTER_PLAYER_LOADING, "Action %u not added into button %u for player %s: action must be < %u", action, button, GetName(), MAX_ACTION_BUTTON_ACTION_VALUE);
  6635. return false;
  6636. }
  6637.  
  6638. switch (type)
  6639. {
  6640. case ACTION_BUTTON_SPELL:
  6641. if (!sSpellMgr->GetSpellInfo(action))
  6642. {
  6643. sLog->outError(LOG_FILTER_PLAYER_LOADING, "Spell action %u not added into button %u for player %s: spell not exist", action, button, GetName());
  6644. return false;
  6645. }
  6646.  
  6647. if (!HasSpell(action))
  6648. {
  6649. sLog->outDebug(LOG_FILTER_PLAYER_LOADING, "Player::IsActionButtonDataValid Spell action %u not added into button %u for player %s: player don't known this spell", action, button, GetName());
  6650. return false;
  6651. }
  6652. break;
  6653. case ACTION_BUTTON_ITEM:
  6654. if (!sObjectMgr->GetItemTemplate(action))
  6655. {
  6656. sLog->outError(LOG_FILTER_PLAYER_LOADING, "Item action %u not added into button %u for player %s: item not exist", action, button, GetName());
  6657. return false;
  6658. }
  6659. break;
  6660. default:
  6661. break; // other cases not checked at this moment
  6662. }
  6663.  
  6664. return true;
  6665. }
  6666.  
  6667. ActionButton* Player::addActionButton(uint8 button, uint32 action, uint8 type)
  6668. {
  6669. if (!IsActionButtonDataValid(button, action, type))
  6670. return NULL;
  6671.  
  6672. // it create new button (NEW state) if need or return existed
  6673. ActionButton& ab = m_actionButtons[button];
  6674.  
  6675. // set data and update to CHANGED if not NEW
  6676. ab.SetActionAndType(action, ActionButtonType(type));
  6677.  
  6678. sLog->outInfo(LOG_FILTER_PLAYER_LOADING, "Player '%u' Added Action '%u' (type %u) to Button '%u'", GetGUIDLow(), action, type, button);
  6679. return &ab;
  6680. }
  6681.  
  6682. void Player::removeActionButton(uint8 button)
  6683. {
  6684. ActionButtonList::iterator buttonItr = m_actionButtons.find(button);
  6685. if (buttonItr == m_actionButtons.end() || buttonItr->second.uState == ACTIONBUTTON_DELETED)
  6686. return;
  6687.  
  6688. if (buttonItr->second.uState == ACTIONBUTTON_NEW)
  6689. m_actionButtons.erase(buttonItr); // new and not saved
  6690. else
  6691. buttonItr->second.uState = ACTIONBUTTON_DELETED; // saved, will deleted at next save
  6692.  
  6693. sLog->outInfo(LOG_FILTER_PLAYER_LOADING, "Action Button '%u' Removed from Player '%u'", button, GetGUIDLow());
  6694. }
  6695.  
  6696. ActionButton const* Player::GetActionButton(uint8 button)
  6697. {
  6698. ActionButtonList::iterator buttonItr = m_actionButtons.find(button);
  6699. if (buttonItr == m_actionButtons.end() || buttonItr->second.uState == ACTIONBUTTON_DELETED)
  6700. return NULL;
  6701.  
  6702. return &buttonItr->second;
  6703. }
  6704.  
  6705. bool Player::UpdatePosition(float x, float y, float z, float orientation, bool teleport)
  6706. {
  6707. if (!Unit::UpdatePosition(x, y, z, orientation, teleport))
  6708. return false;
  6709.  
  6710. //if (movementInfo.flags & MOVEMENTFLAG_MOVING)
  6711. // mover->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOVE);
  6712. //if (movementInfo.flags & MOVEMENTFLAG_TURNING)
  6713. // mover->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TURNING);
  6714. //AURA_INTERRUPT_FLAG_JUMP not sure
  6715.  
  6716. // group update
  6717. if (GetGroup())
  6718. SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POSITION);
  6719.  
  6720. if (GetTrader() && !IsWithinDistInMap(GetTrader(), INTERACTION_DISTANCE))
  6721. GetSession()->SendCancelTrade();
  6722.  
  6723. CheckAreaExploreAndOutdoor();
  6724.  
  6725. return true;
  6726. }
  6727.  
  6728. void Player::SaveRecallPosition()
  6729. {
  6730. m_recallMap = GetMapId();
  6731. m_recallX = GetPositionX();
  6732. m_recallY = GetPositionY();
  6733. m_recallZ = GetPositionZ();
  6734. m_recallO = GetOrientation();
  6735. }
  6736.  
  6737. void Player::SendMessageToSetInRange(WorldPacket* data, float dist, bool self)
  6738. {
  6739. if (self)
  6740. GetSession()->SendPacket(data);
  6741.  
  6742. Trinity::MessageDistDeliverer notifier(this, data, dist);
  6743. VisitNearbyWorldObject(dist, notifier);
  6744. }
  6745.  
  6746. void Player::SendMessageToSetInRange(WorldPacket* data, float dist, bool self, bool own_team_only)
  6747. {
  6748. if (self)
  6749. GetSession()->SendPacket(data);
  6750.  
  6751. Trinity::MessageDistDeliverer notifier(this, data, dist, own_team_only);
  6752. VisitNearbyWorldObject(dist, notifier);
  6753. }
  6754.  
  6755. void Player::SendMessageToSet(WorldPacket* data, Player const* skipped_rcvr)
  6756. {
  6757. if (skipped_rcvr != this)
  6758. GetSession()->SendPacket(data);
  6759.  
  6760. // we use World::GetMaxVisibleDistance() because i cannot see why not use a distance
  6761. // update: replaced by GetMap()->GetVisibilityDistance()
  6762. Trinity::MessageDistDeliverer notifier(this, data, GetVisibilityRange(), false, skipped_rcvr);
  6763. VisitNearbyWorldObject(GetVisibilityRange(), notifier);
  6764. }
  6765.  
  6766. void Player::SendDirectMessage(WorldPacket* data)
  6767. {
  6768. m_session->SendPacket(data);
  6769. }
  6770.  
  6771. void Player::SendCinematicStart(uint32 CinematicSequenceId)
  6772. {
  6773. WorldPacket data(SMSG_TRIGGER_CINEMATIC, 4);
  6774. data << uint32(CinematicSequenceId);
  6775. SendDirectMessage(&data);
  6776. }
  6777.  
  6778. void Player::SendMovieStart(uint32 MovieId)
  6779. {
  6780. WorldPacket data(SMSG_TRIGGER_MOVIE, 4);
  6781. data << uint32(MovieId);
  6782. SendDirectMessage(&data);
  6783. }
  6784.  
  6785. void Player::CheckAreaExploreAndOutdoor()
  6786. {
  6787. if (!isAlive())
  6788. return;
  6789.  
  6790. if (isInFlight())
  6791. return;
  6792.  
  6793. bool isOutdoor;
  6794. uint16 areaFlag = GetBaseMap()->GetAreaFlag(GetPositionX(), GetPositionY(), GetPositionZ(), &isOutdoor);
  6795.  
  6796. if (sWorld->getBoolConfig(CONFIG_VMAP_INDOOR_CHECK) && !isOutdoor)
  6797. RemoveAurasWithAttribute(SPELL_ATTR0_OUTDOORS_ONLY);
  6798.  
  6799. if (areaFlag == 0xffff)
  6800. return;
  6801. int offset = areaFlag / 32;
  6802.  
  6803. if (offset >= PLAYER_EXPLORED_ZONES_SIZE)
  6804. {
  6805. sLog->outError(LOG_FILTER_PLAYER, "Wrong area flag %u in map data for (X: %f Y: %f) point to field PLAYER_EXPLORED_ZONES_1 + %u ( %u must be < %u ).", areaFlag, GetPositionX(), GetPositionY(), offset, offset, PLAYER_EXPLORED_ZONES_SIZE);
  6806. return;
  6807. }
  6808.  
  6809. uint32 val = (uint32)(1 << (areaFlag % 32));
  6810. uint32 currFields = GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset);
  6811.  
  6812. if (!(currFields & val))
  6813. {
  6814. SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, (uint32)(currFields | val));
  6815.  
  6816. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA);
  6817.  
  6818. AreaTableEntry const* areaEntry = GetAreaEntryByAreaFlagAndMap(areaFlag, GetMapId());
  6819. if (!areaEntry)
  6820. {
  6821. sLog->outError(LOG_FILTER_PLAYER, "Player %u discovered unknown area (x: %f y: %f z: %f map: %u", GetGUIDLow(), GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId());
  6822. return;
  6823. }
  6824.  
  6825. if (areaEntry->area_level > 0)
  6826. {
  6827. uint32 area = areaEntry->ID;
  6828. if (getLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
  6829. {
  6830. SendExplorationExperience(area, 0);
  6831. }
  6832. else
  6833. {
  6834. int32 diff = int32(getLevel()) - areaEntry->area_level;
  6835. uint32 XP = 0;
  6836. if (diff < -5)
  6837. {
  6838. XP = uint32(sObjectMgr->GetBaseXP(getLevel()+5)*sWorld->getRate(RATE_XP_EXPLORE));
  6839. }
  6840. else if (diff > 5)
  6841. {
  6842. int32 exploration_percent = (100-((diff-5)*5));
  6843. if (exploration_percent > 100)
  6844. exploration_percent = 100;
  6845. else if (exploration_percent < 0)
  6846. exploration_percent = 0;
  6847.  
  6848. XP = uint32(sObjectMgr->GetBaseXP(areaEntry->area_level)*exploration_percent/100*sWorld->getRate(RATE_XP_EXPLORE));
  6849. }
  6850. else
  6851. {
  6852. XP = uint32(sObjectMgr->GetBaseXP(areaEntry->area_level)*sWorld->getRate(RATE_XP_EXPLORE));
  6853. }
  6854.  
  6855. GiveXP(XP, NULL);
  6856. SendExplorationExperience(area, XP);
  6857. }
  6858. sLog->outInfo(LOG_FILTER_PLAYER, "Player %u discovered a new area: %u", GetGUIDLow(), area);
  6859. }
  6860. }
  6861. }
  6862.  
  6863. uint32 Player::TeamForRace(uint8 race)
  6864. {
  6865. if (ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(race))
  6866. {
  6867. switch (rEntry->TeamID)
  6868. {
  6869. case 1: return HORDE;
  6870. case 7: return ALLIANCE;
  6871. }
  6872. sLog->outError(LOG_FILTER_PLAYER, "Race (%u) has wrong teamid (%u) in DBC: wrong DBC files?", uint32(race), rEntry->TeamID);
  6873. }
  6874. else
  6875. sLog->outError(LOG_FILTER_PLAYER, "Race (%u) not found in DBC: wrong DBC files?", uint32(race));
  6876.  
  6877. return ALLIANCE;
  6878. }
  6879.  
  6880. void Player::setFactionForRace(uint8 race)
  6881. {
  6882. m_team = TeamForRace(race);
  6883.  
  6884. ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(race);
  6885. setFaction(rEntry ? rEntry->FactionID : 0);
  6886. }
  6887.  
  6888. ReputationRank Player::GetReputationRank(uint32 faction) const
  6889. {
  6890. FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction);
  6891. return GetReputationMgr().GetRank(factionEntry);
  6892. }
  6893.  
  6894. //Calculate total reputation percent player gain with quest/creature level
  6895. int32 Player::CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool for_quest, bool noQuestBonus)
  6896. {
  6897. float percent = 100.0f;
  6898.  
  6899. // Get the generic rate first
  6900. if (RepRewardRate const* repData = sObjectMgr->GetRepRewardRate(faction))
  6901. {
  6902. float repRate = for_quest ? repData->quest_rate : repData->creature_rate;
  6903. percent *= repRate;
  6904. }
  6905.  
  6906. float rate = for_quest ? sWorld->getRate(RATE_REPUTATION_LOWLEVEL_QUEST) : sWorld->getRate(RATE_REPUTATION_LOWLEVEL_KILL);
  6907.  
  6908. if (rate != 1.0f && creatureOrQuestLevel <= Trinity::XP::GetGrayLevel(getLevel()))
  6909. percent *= rate;
  6910.  
  6911. float repMod = noQuestBonus ? 0.0f : (float)GetTotalAuraModifier(SPELL_AURA_MOD_REPUTATION_GAIN);
  6912.  
  6913. if (!for_quest)
  6914. repMod += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_FACTION_REPUTATION_GAIN, faction);
  6915.  
  6916. percent += rep > 0 ? repMod : -repMod;
  6917.  
  6918. if (percent <= 0.0f)
  6919. return 0;
  6920.  
  6921. return int32(rep*percent/100);
  6922. }
  6923.  
  6924. //Calculates how many reputation points player gains in victim's enemy factions
  6925. void Player::RewardReputation(Unit* victim, float rate)
  6926. {
  6927. if (!victim || victim->GetTypeId() == TYPEID_PLAYER)
  6928. return;
  6929.  
  6930. if (victim->ToCreature()->IsReputationGainDisabled())
  6931. return;
  6932.  
  6933. ReputationOnKillEntry const* Rep = sObjectMgr->GetReputationOnKilEntry(victim->ToCreature()->GetCreatureTemplate()->Entry);
  6934.  
  6935. if (!Rep)
  6936. return;
  6937.  
  6938. uint32 ChampioningFaction = 0;
  6939.  
  6940. if (GetChampioningFaction())
  6941. {
  6942. // support for: Championing - http://www.wowwiki.com/Championing
  6943.  
  6944. Map const* map = GetMap();
  6945. if (map && map->IsDungeon())
  6946. {
  6947. InstanceTemplate const* instance = sObjectMgr->GetInstanceTemplate(map->GetId());
  6948. if (instance)
  6949. {
  6950. AccessRequirement const* pAccessRequirement = sObjectMgr->GetAccessRequirement(map->GetId(), ((InstanceMap*)map)->GetDifficulty());
  6951. if (pAccessRequirement)
  6952. {
  6953. if (!map->IsRaid() && pAccessRequirement->levelMin == 80)
  6954. ChampioningFaction = GetChampioningFaction();
  6955. }
  6956. }
  6957. }
  6958. }
  6959.  
  6960. // Favored reputation increase START
  6961. uint32 zone = GetZoneId();
  6962. uint32 team = GetTeam();
  6963. float favored_rep_mult = 0;
  6964.  
  6965. if ((HasAura(32096) || HasAura(32098)) && (zone == 3483 || zone == 3562 || zone == 3836 || zone == 3713 || zone == 3714)) favored_rep_mult = 0.25; // Thrallmar's Favor and Honor Hold's Favor
  6966. else if (HasAura(30754) && (Rep->RepFaction1 == 609 || Rep->RepFaction2 == 609) && !ChampioningFaction) favored_rep_mult = 0.25; // Cenarion Favor
  6967.  
  6968. if (favored_rep_mult > 0) favored_rep_mult *= 2; // Multiplied by 2 because the reputation is divided by 2 for some reason (See "donerep1 / 2" and "donerep2 / 2") -- if you know why this is done, please update/explain :)
  6969. // Favored reputation increase END
  6970.  
  6971. bool recruitAFriend = GetsRecruitAFriendBonus(false);
  6972.  
  6973. if (Rep->RepFaction1 && (!Rep->TeamDependent || team == ALLIANCE))
  6974. {
  6975. int32 donerep1 = CalculateReputationGain(victim->getLevel(), Rep->RepValue1, ChampioningFaction ? ChampioningFaction : Rep->RepFaction1, false);
  6976. donerep1 = int32(donerep1*(rate + favored_rep_mult));
  6977.  
  6978. if (recruitAFriend)
  6979. donerep1 = int32(donerep1 * (1 + sWorld->getRate(RATE_REPUTATION_RECRUIT_A_FRIEND_BONUS)));
  6980.  
  6981. FactionEntry const* factionEntry1 = sFactionStore.LookupEntry(ChampioningFaction ? ChampioningFaction : Rep->RepFaction1);
  6982. uint32 current_reputation_rank1 = GetReputationMgr().GetRank(factionEntry1);
  6983. if (factionEntry1 && current_reputation_rank1 <= Rep->ReputationMaxCap1)
  6984. GetReputationMgr().ModifyReputation(factionEntry1, donerep1);
  6985. }
  6986.  
  6987. if (Rep->RepFaction2 && (!Rep->TeamDependent || team == HORDE))
  6988. {
  6989. int32 donerep2 = CalculateReputationGain(victim->getLevel(), Rep->RepValue2, ChampioningFaction ? ChampioningFaction : Rep->RepFaction2, false);
  6990. donerep2 = int32(donerep2*(rate + favored_rep_mult));
  6991.  
  6992. if (recruitAFriend)
  6993. donerep2 = int32(donerep2 * (1 + sWorld->getRate(RATE_REPUTATION_RECRUIT_A_FRIEND_BONUS)));
  6994.  
  6995. FactionEntry const* factionEntry2 = sFactionStore.LookupEntry(ChampioningFaction ? ChampioningFaction : Rep->RepFaction2);
  6996. uint32 current_reputation_rank2 = GetReputationMgr().GetRank(factionEntry2);
  6997. if (factionEntry2 && current_reputation_rank2 <= Rep->ReputationMaxCap2)
  6998. GetReputationMgr().ModifyReputation(factionEntry2, donerep2);
  6999. }
  7000. }
  7001.  
  7002. //Calculate how many reputation points player gain with the quest
  7003. void Player::RewardReputation(Quest const* quest)
  7004. {
  7005. bool recruitAFriend = GetsRecruitAFriendBonus(false);
  7006.  
  7007. // quest reputation reward/loss
  7008. for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i)
  7009. {
  7010. if (!quest->RewardFactionId[i])
  7011. continue;
  7012. if (quest->RewardFactionValueIdOverride[i])
  7013. {
  7014. int32 rep = CalculateReputationGain(GetQuestLevel(quest), quest->RewardFactionValueIdOverride[i]/100, quest->RewardFactionId[i], true, true);
  7015.  
  7016. if (recruitAFriend)
  7017. rep = int32(rep * (1 + sWorld->getRate(RATE_REPUTATION_RECRUIT_A_FRIEND_BONUS)));
  7018.  
  7019. if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(quest->RewardFactionId[i]))
  7020. GetReputationMgr().ModifyReputation(factionEntry, rep);
  7021. }
  7022. else
  7023. {
  7024. uint32 row = ((quest->RewardFactionValueId[i] < 0) ? 1 : 0) + 1;
  7025. uint32 field = abs(quest->RewardFactionValueId[i]);
  7026.  
  7027. if (const QuestFactionRewEntry* pRow = sQuestFactionRewardStore.LookupEntry(row))
  7028. {
  7029. int32 repPoints = pRow->QuestRewFactionValue[field];
  7030.  
  7031. if (!repPoints)
  7032. continue;
  7033.  
  7034. repPoints = CalculateReputationGain(GetQuestLevel(quest), repPoints, quest->RewardFactionId[i], true);
  7035.  
  7036. if (recruitAFriend)
  7037. repPoints = int32(repPoints * (1 + sWorld->getRate(RATE_REPUTATION_RECRUIT_A_FRIEND_BONUS)));
  7038.  
  7039. if (const FactionEntry* factionEntry = sFactionStore.LookupEntry(quest->RewardFactionId[i]))
  7040. GetReputationMgr().ModifyReputation(factionEntry, repPoints);
  7041. }
  7042. }
  7043. }
  7044. }
  7045.  
  7046. void Player::UpdateHonorFields()
  7047. {
  7048. /// called when rewarding honor and at each save
  7049. time_t now = time_t(time(NULL));
  7050. time_t today = time_t(time(NULL) / DAY) * DAY;
  7051.  
  7052. if (m_lastHonorUpdateTime < today)
  7053. {
  7054. time_t yesterday = today - DAY;
  7055.  
  7056. uint16 kills_today = PAIR32_LOPART(GetUInt32Value(PLAYER_FIELD_KILLS));
  7057.  
  7058. // update yesterday's contribution
  7059. if (m_lastHonorUpdateTime >= yesterday)
  7060. {
  7061. SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, GetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION));
  7062.  
  7063. // this is the first update today, reset today's contribution
  7064. SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, 0);
  7065. SetUInt32Value(PLAYER_FIELD_KILLS, MAKE_PAIR32(0, kills_today));
  7066. }
  7067. else
  7068. {
  7069. // no honor/kills yesterday or today, reset
  7070. SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0);
  7071. SetUInt32Value(PLAYER_FIELD_KILLS, 0);
  7072. }
  7073. }
  7074.  
  7075. m_lastHonorUpdateTime = now;
  7076. }
  7077.  
  7078. ///Calculate the amount of honor gained based on the victim
  7079. ///and the size of the group for which the honor is divided
  7080. ///An exact honor value can also be given (overriding the calcs)
  7081. bool Player::RewardHonor(Unit* uVictim, uint32 groupsize, int32 honor, bool pvptoken)
  7082. {
  7083. // do not reward honor in arenas, but enable onkill spellproc
  7084. if (InArena())
  7085. {
  7086. if (!uVictim || uVictim == this || uVictim->GetTypeId() != TYPEID_PLAYER)
  7087. return false;
  7088.  
  7089. if (GetBGTeam() == uVictim->ToPlayer()->GetBGTeam())
  7090. return false;
  7091.  
  7092. return true;
  7093. }
  7094.  
  7095. // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
  7096. if (HasAura(SPELL_AURA_PLAYER_INACTIVE))
  7097. return false;
  7098.  
  7099. uint64 victim_guid = 0;
  7100. uint32 victim_rank = 0;
  7101.  
  7102. // need call before fields update to have chance move yesterday data to appropriate fields before today data change.
  7103. UpdateHonorFields();
  7104.  
  7105. // do not reward honor in arenas, but return true to enable onkill spellproc
  7106. if (InBattleground() && GetBattleground() && GetBattleground()->isArena())
  7107. return true;
  7108.  
  7109. // Promote to float for calculations
  7110. float honor_f = (float)honor;
  7111.  
  7112. if (honor_f <= 0)
  7113. {
  7114. if (!uVictim || uVictim == this || uVictim->HasAuraType(SPELL_AURA_NO_PVP_CREDIT))
  7115. return false;
  7116.  
  7117. victim_guid = uVictim->GetGUID();
  7118.  
  7119. if (uVictim->GetTypeId() == TYPEID_PLAYER)
  7120. {
  7121. Player* victim = uVictim->ToPlayer();
  7122.  
  7123. if (GetTeam() == victim->GetTeam() && !sWorld->IsFFAPvPRealm())
  7124. return false;
  7125.  
  7126. uint8 k_level = getLevel();
  7127. uint8 k_grey = Trinity::XP::GetGrayLevel(k_level);
  7128. uint8 v_level = victim->getLevel();
  7129.  
  7130. if (v_level <= k_grey)
  7131. return false;
  7132.  
  7133. // PLAYER_CHOSEN_TITLE VALUES DESCRIPTION
  7134. // [0] Just name
  7135. // [1..14] Alliance honor titles and player name
  7136. // [15..28] Horde honor titles and player name
  7137. // [29..38] Other title and player name
  7138. // [39+] Nothing
  7139. uint32 victim_title = victim->GetUInt32Value(PLAYER_CHOSEN_TITLE);
  7140. // Get Killer titles, CharTitlesEntry::bit_index
  7141. // Ranks:
  7142. // title[1..14] -> rank[5..18]
  7143. // title[15..28] -> rank[5..18]
  7144. // title[other] -> 0
  7145. if (victim_title == 0)
  7146. victim_guid = 0; // Don't show HK: <rank> message, only log.
  7147. else if (victim_title < 15)
  7148. victim_rank = victim_title + 4;
  7149. else if (victim_title < 29)
  7150. victim_rank = victim_title - 14 + 4;
  7151. else
  7152. victim_guid = 0; // Don't show HK: <rank> message, only log.
  7153.  
  7154. honor_f = ceil(Trinity::Honor::hk_honor_at_level_f(k_level) * (v_level - k_grey) / (k_level - k_grey));
  7155.  
  7156. // count the number of playerkills in one day
  7157. ApplyModUInt32Value(PLAYER_FIELD_KILLS, 1, true);
  7158. // and those in a lifetime
  7159. ApplyModUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, 1, true);
  7160. UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL);
  7161. UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS, victim->getClass());
  7162. UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HK_RACE, victim->getRace());
  7163. UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA, GetAreaId());
  7164. UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL, 1, 0, victim);
  7165. }
  7166. else
  7167. {
  7168. if (!uVictim->ToCreature()->isRacialLeader())
  7169. return false;
  7170.  
  7171. honor_f = 100.0f; // ??? need more info
  7172. victim_rank = 19; // HK: Leader
  7173. }
  7174. }
  7175.  
  7176. if (uVictim != NULL)
  7177. {
  7178. if (groupsize > 1)
  7179. honor_f /= groupsize;
  7180.  
  7181. // apply honor multiplier from aura (not stacking-get highest)
  7182. AddPctN(honor_f, GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HONOR_GAIN_PCT));
  7183. }
  7184.  
  7185. honor_f *= sWorld->getRate(RATE_HONOR);
  7186. // Back to int now
  7187. honor = int32(honor_f);
  7188. // honor - for show honor points in log
  7189. // victim_guid - for show victim name in log
  7190. // victim_rank [1..4] HK: <dishonored rank>
  7191. // victim_rank [5..19] HK: <alliance\horde rank>
  7192. // victim_rank [0, 20+] HK: <>
  7193. WorldPacket data(SMSG_PVP_CREDIT, 4+8+4);
  7194. data << honor;
  7195. data << victim_guid;
  7196. data << victim_rank;
  7197.  
  7198. GetSession()->SendPacket(&data);
  7199.  
  7200. // add honor points
  7201. ModifyHonorPoints(honor);
  7202.  
  7203. ApplyModUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, honor, true);
  7204.  
  7205. if (InBattleground() && honor > 0)
  7206. {
  7207. if (Battleground* bg = GetBattleground())
  7208. {
  7209. bg->UpdatePlayerScore(this, SCORE_BONUS_HONOR, honor, false); //false: prevent looping
  7210. }
  7211. }
  7212.  
  7213. if (sWorld->getBoolConfig(CONFIG_PVP_TOKEN_ENABLE) && pvptoken)
  7214. {
  7215. if (!uVictim || uVictim == this || uVictim->HasAuraType(SPELL_AURA_NO_PVP_CREDIT))
  7216. return true;
  7217.  
  7218. if (uVictim->GetTypeId() == TYPEID_PLAYER)
  7219. {
  7220. // Check if allowed to receive it in current map
  7221. uint8 MapType = sWorld->getIntConfig(CONFIG_PVP_TOKEN_MAP_TYPE);
  7222. if ((MapType == 1 && !InBattleground() && !HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP))
  7223. || (MapType == 2 && !HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP))
  7224. || (MapType == 3 && !InBattleground()))
  7225. return true;
  7226.  
  7227. uint32 itemId = sWorld->getIntConfig(CONFIG_PVP_TOKEN_ID);
  7228. int32 count = sWorld->getIntConfig(CONFIG_PVP_TOKEN_COUNT);
  7229.  
  7230. if (AddItem(itemId, count))
  7231. ChatHandler(this).PSendSysMessage("You have been awarded a token for slaying another player.");
  7232. }
  7233. }
  7234.  
  7235. return true;
  7236. }
  7237.  
  7238. void Player::SetHonorPoints(uint32 value)
  7239. {
  7240. if (value > sWorld->getIntConfig(CONFIG_MAX_HONOR_POINTS))
  7241. value = sWorld->getIntConfig(CONFIG_MAX_HONOR_POINTS);
  7242. SetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY, value);
  7243. if (value)
  7244. AddKnownCurrency(ITEM_HONOR_POINTS_ID);
  7245. }
  7246.  
  7247. void Player::SetArenaPoints(uint32 value)
  7248. {
  7249. if (value > sWorld->getIntConfig(CONFIG_MAX_ARENA_POINTS))
  7250. value = sWorld->getIntConfig(CONFIG_MAX_ARENA_POINTS);
  7251. SetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY, value);
  7252. if (value)
  7253. AddKnownCurrency(ITEM_ARENA_POINTS_ID);
  7254. }
  7255.  
  7256. void Player::ModifyHonorPoints(int32 value, SQLTransaction* trans /*=NULL*/)
  7257. {
  7258. PreparedStatement* stmt = NULL;
  7259.  
  7260. int32 newValue = int32(GetHonorPoints()) + value;
  7261. if (newValue < 0)
  7262. newValue = 0;
  7263. SetHonorPoints(uint32(newValue));
  7264.  
  7265. if (trans && !trans->null())
  7266. {
  7267. stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_HONOR_POINTS);
  7268. stmt->setUInt32(0, newValue);
  7269. stmt->setUInt32(1, GetGUIDLow());
  7270. (*trans)->Append(stmt);
  7271. }
  7272. }
  7273.  
  7274. void Player::ModifyArenaPoints(int32 value, SQLTransaction* trans /*=NULL*/)
  7275. {
  7276. PreparedStatement* stmt = NULL;
  7277.  
  7278. int32 newValue = int32(GetArenaPoints()) + value;
  7279. if (newValue < 0)
  7280. newValue = 0;
  7281. SetArenaPoints(uint32(newValue));
  7282.  
  7283. if (trans && !trans->null())
  7284. {
  7285. stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_ARENA_POINTS);
  7286. stmt->setUInt32(0, newValue);
  7287. stmt->setUInt32(1, GetGUIDLow());
  7288. (*trans)->Append(stmt);
  7289. }
  7290. }
  7291.  
  7292. uint32 Player::GetGuildIdFromDB(uint64 guid)
  7293. {
  7294. PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER);
  7295. stmt->setUInt32(0, GUID_LOPART(guid));
  7296. PreparedQueryResult result = CharacterDatabase.Query(stmt);
  7297.  
  7298. if (!result)
  7299. return 0;
  7300.  
  7301. uint32 id = result->Fetch()[0].GetUInt32();
  7302. return id;
  7303. }
  7304.  
  7305. uint8 Player::GetRankFromDB(uint64 guid)
  7306. {
  7307. PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER);
  7308. stmt->setUInt32(0, GUID_LOPART(guid));
  7309. PreparedQueryResult result = CharacterDatabase.Query(stmt);
  7310.  
  7311. if (result)
  7312. {
  7313. uint32 v = result->Fetch()[1].GetUInt8();
  7314. return v;
  7315. }
  7316. else
  7317. return 0;
  7318. }
  7319.  
  7320. uint32 Player::GetArenaTeamIdFromDB(uint64 guid, uint8 type)
  7321. {
  7322. PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ARENA_TEAM_ID_BY_PLAYER_GUID);
  7323. stmt->setUInt32(0, GUID_LOPART(guid));
  7324. stmt->setUInt8(1, type);
  7325. PreparedQueryResult result = CharacterDatabase.Query(stmt);
  7326.  
  7327. if (!result)
  7328. return 0;
  7329.  
  7330. uint32 id = (*result)[0].GetUInt32();
  7331. return id;
  7332. }
  7333.  
  7334. uint32 Player::GetZoneIdFromDB(uint64 guid)
  7335. {
  7336. uint32 guidLow = GUID_LOPART(guid);
  7337. PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_ZONE);
  7338. stmt->setUInt32(0, guidLow);
  7339. PreparedQueryResult result = CharacterDatabase.Query(stmt);
  7340.  
  7341. if (!result)
  7342. return 0;
  7343. Field* fields = result->Fetch();
  7344. uint32 zone = fields[0].GetUInt16();
  7345.  
  7346. if (!zone)
  7347. {
  7348. // stored zone is zero, use generic and slow zone detection
  7349. PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_POSITION_XYZ);
  7350. stmt->setUInt32(0, guidLow);
  7351. PreparedQueryResult result = CharacterDatabase.Query(stmt);
  7352.  
  7353. if (!result)
  7354. return 0;
  7355. fields = result->Fetch();
  7356. uint32 map = fields[0].GetUInt16();
  7357. float posx = fields[1].GetFloat();
  7358. float posy = fields[2].GetFloat();
  7359. float posz = fields[3].GetFloat();
  7360.  
  7361. zone = sMapMgr->GetZoneId(map, posx, posy, posz);
  7362.  
  7363. if (zone > 0)
  7364. {
  7365. PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ZONE);
  7366.  
  7367. stmt->setUInt16(0, uint16(zone));
  7368. stmt->setUInt32(1, guidLow);
  7369.  
  7370. CharacterDatabase.Execute(stmt);
  7371. }
  7372. }
  7373.  
  7374. return zone;
  7375. }
  7376.  
  7377. uint32 Player::GetLevelFromDB(uint64 guid)
  7378. {
  7379. PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_LEVEL);
  7380. stmt->setUInt32(0, GUID_LOPART(guid));
  7381. PreparedQueryResult result = CharacterDatabase.Query(stmt);
  7382.  
  7383. if (!result)
  7384. return 0;
  7385.  
  7386. Field* fields = result->Fetch();
  7387. uint8 level = fields[0].GetUInt8();
  7388.  
  7389. return level;
  7390. }
  7391.  
  7392. void Player::UpdateArea(uint32 newArea)
  7393. {
  7394. // FFA_PVP flags are area and not zone id dependent
  7395. // so apply them accordingly
  7396. m_areaUpdateId = newArea;
  7397.  
  7398. AreaTableEntry const* area = GetAreaEntryByAreaID(newArea);
  7399. pvpInfo.inFFAPvPArea = area && (area->flags & AREA_FLAG_ARENA);
  7400. UpdatePvPState(true);
  7401.  
  7402. UpdateAreaDependentAuras(newArea);
  7403.  
  7404. // previously this was in UpdateZone (but after UpdateArea) so nothing will break
  7405. pvpInfo.inNoPvPArea = false;
  7406. if (area && area->IsSanctuary()) // in sanctuary
  7407. {
  7408. SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY);
  7409. pvpInfo.inNoPvPArea = true;
  7410. CombatStopWithPets();
  7411. }
  7412. else
  7413. RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY);
  7414. }
  7415.  
  7416. void Player::UpdateZone(uint32 newZone, uint32 newArea)
  7417. {
  7418. if (m_zoneUpdateId != newZone)
  7419. {
  7420. sOutdoorPvPMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
  7421. sOutdoorPvPMgr->HandlePlayerEnterZone(this, newZone);
  7422. SendInitWorldStates(newZone, newArea); // only if really enters to new zone, not just area change, works strange...
  7423. }
  7424.  
  7425. // group update
  7426. if (Group* group = GetGroup())
  7427. {
  7428. SetGroupUpdateFlag(GROUP_UPDATE_FULL);
  7429. if (GetSession() && group->isLFGGroup() && sLFGMgr->IsTeleported(GetGUID()))
  7430. {
  7431. for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
  7432. {
  7433. if (Player* member = itr->getSource())
  7434. GetSession()->SendNameQueryOpcode(member->GetGUID());
  7435. }
  7436. }
  7437. }
  7438.  
  7439. m_zoneUpdateId = newZone;
  7440. m_zoneUpdateTimer = ZONE_UPDATE_INTERVAL;
  7441.  
  7442. // zone changed, so area changed as well, update it
  7443. UpdateArea(newArea);
  7444.  
  7445. AreaTableEntry const* zone = GetAreaEntryByAreaID(newZone);
  7446. if (!zone)
  7447. return;
  7448.  
  7449. if (sWorld->getBoolConfig(CONFIG_WEATHER))
  7450. {
  7451. if (Weather* weather = WeatherMgr::FindWeather(zone->ID))
  7452. weather->SendWeatherUpdateToPlayer(this);
  7453. else
  7454. {
  7455. if (!WeatherMgr::AddWeather(zone->ID))
  7456. {
  7457. // send fine weather packet to remove old zone's weather
  7458. WeatherMgr::SendFineWeatherUpdateToPlayer(this);
  7459. }
  7460. }
  7461. }
  7462.  
  7463. sScriptMgr->OnPlayerUpdateZone(this, newZone, newArea);
  7464.  
  7465. // in PvP, any not controlled zone (except zone->team == 6, default case)
  7466. // in PvE, only opposition team capital
  7467. switch (zone->team)
  7468. {
  7469. case AREATEAM_ALLY:
  7470. pvpInfo.inHostileArea = GetTeam() != ALLIANCE && (sWorld->IsPvPRealm() || zone->flags & AREA_FLAG_CAPITAL);
  7471. break;
  7472. case AREATEAM_HORDE:
  7473. pvpInfo.inHostileArea = GetTeam() != HORDE && (sWorld->IsPvPRealm() || zone->flags & AREA_FLAG_CAPITAL);
  7474. break;
  7475. case AREATEAM_NONE:
  7476. // overwrite for battlegrounds, maybe batter some zone flags but current known not 100% fit to this
  7477. pvpInfo.inHostileArea = sWorld->IsPvPRealm() || InBattleground() || zone->flags & AREA_FLAG_WINTERGRASP;
  7478. break;
  7479. default: // 6 in fact
  7480. pvpInfo.inHostileArea = false;
  7481. break;
  7482. }
  7483.  
  7484. if (zone->flags & AREA_FLAG_CAPITAL) // Is in a capital city
  7485. {
  7486. if (!pvpInfo.inHostileArea || zone->IsSanctuary())
  7487. {
  7488. SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
  7489. SetRestType(REST_TYPE_IN_CITY);
  7490. InnEnter(time(0), GetMapId(), 0, 0, 0);
  7491. }
  7492. pvpInfo.inNoPvPArea = true;
  7493. }
  7494. else
  7495. {
  7496. if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING))
  7497. {
  7498. if (GetRestType() == REST_TYPE_IN_TAVERN) // Still inside a tavern or has recently left
  7499. {
  7500. // Remove rest state if we have recently left a tavern.
  7501. // Why is 40 yd hardcoded?
  7502. if (GetMapId() != GetInnPosMapId() || GetExactDist(GetInnPosX(), GetInnPosY(), GetInnPosZ()) > 40.0f)
  7503. {
  7504. RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
  7505. SetRestType(REST_TYPE_NO);
  7506. }
  7507. }
  7508. else // Recently left a capital city
  7509. {
  7510. RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
  7511. SetRestType(REST_TYPE_NO);
  7512. }
  7513. }
  7514. }
  7515.  
  7516. UpdatePvPState();
  7517.  
  7518. // remove items with area/map limitations (delete only for alive player to allow back in ghost mode)
  7519. // if player resurrected at teleport this will be applied in resurrect code
  7520. if (isAlive())
  7521. DestroyZoneLimitedItem(true, newZone);
  7522.  
  7523. // check some item equip limitations (in result lost CanTitanGrip at talent reset, for example)
  7524. AutoUnequipOffhandIfNeed();
  7525.  
  7526. // recent client version not send leave/join channel packets for built-in local channels
  7527. UpdateLocalChannels(newZone);
  7528.  
  7529. UpdateZoneDependentAuras(newZone);
  7530. }
  7531.  
  7532. //If players are too far away from the duel flag... they lose the duel
  7533. void Player::CheckDuelDistance(time_t currTime)
  7534. {
  7535. if (!duel)
  7536. return;
  7537.  
  7538. uint64 duelFlagGUID = GetUInt64Value(PLAYER_DUEL_ARBITER);
  7539. GameObject* obj = GetMap()->GetGameObject(duelFlagGUID);
  7540. if (!obj)
  7541. return;
  7542.  
  7543. if (duel->outOfBound == 0)
  7544. {
  7545. if (!IsWithinDistInMap(obj, 50))
  7546. {
  7547. duel->outOfBound = currTime;
  7548.  
  7549. WorldPacket data(SMSG_DUEL_OUTOFBOUNDS, 0);
  7550. GetSession()->SendPacket(&data);
  7551. }
  7552. }
  7553. else
  7554. {
  7555. if (IsWithinDistInMap(obj, 40))
  7556. {
  7557. duel->outOfBound = 0;
  7558.  
  7559. WorldPacket data(SMSG_DUEL_INBOUNDS, 0);
  7560. GetSession()->SendPacket(&data);
  7561. }
  7562. else if (currTime >= (duel->outOfBound+10))
  7563. DuelComplete(DUEL_FLED);
  7564. }
  7565. }
  7566.  
  7567. bool Player::IsOutdoorPvPActive()
  7568. {
  7569. return isAlive() && !HasInvisibilityAura() && !HasStealthAura() && (IsPvP() || sWorld->IsPvPRealm()) && !HasUnitMovementFlag(MOVEMENTFLAG_FLYING) && !isInFlight();
  7570. }
  7571.  
  7572. void Player::DuelComplete(DuelCompleteType type)
  7573. {
  7574. // duel not requested
  7575. if (!duel)
  7576. return;
  7577.  
  7578. sLog->outDebug(LOG_FILTER_UNITS, "Duel Complete %s %s", GetName(), duel->opponent->GetName());
  7579.  
  7580. WorldPacket data(SMSG_DUEL_COMPLETE, (1));
  7581. data << (uint8)((type != DUEL_INTERRUPTED) ? 1 : 0);
  7582. GetSession()->SendPacket(&data);
  7583.  
  7584. if (duel->opponent->GetSession())
  7585. duel->opponent->GetSession()->SendPacket(&data);
  7586.  
  7587. if (type != DUEL_INTERRUPTED)
  7588. {
  7589. data.Initialize(SMSG_DUEL_WINNER, (1+20)); // we guess size
  7590. data << uint8(type == DUEL_WON ? 0 : 1); // 0 = just won; 1 = fled
  7591. data << duel->opponent->GetName();
  7592. data << GetName();
  7593. SendMessageToSet(&data, true);
  7594. }
  7595.  
  7596. sScriptMgr->OnPlayerDuelEnd(duel->opponent, this, type);
  7597.  
  7598. switch (type)
  7599. {
  7600. case DUEL_FLED:
  7601. // if initiator and opponent are on the same team
  7602. // or initiator and opponent are not PvP enabled, forcibly stop attacking
  7603. if (duel->initiator->GetTeam() == duel->opponent->GetTeam())
  7604. {
  7605. duel->initiator->AttackStop();
  7606. duel->opponent->AttackStop();
  7607. }
  7608. else
  7609. {
  7610. if (!duel->initiator->IsPvP())
  7611. duel->initiator->AttackStop();
  7612. if (!duel->opponent->IsPvP())
  7613. duel->opponent->AttackStop();
  7614. }
  7615. break;
  7616. case DUEL_WON:
  7617. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL, 1);
  7618. if (duel->opponent)
  7619. {
  7620. duel->opponent->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL, 1);
  7621.  
  7622. //Credit for quest Death's Challenge
  7623. if (getClass() == CLASS_DEATH_KNIGHT && duel->opponent->GetQuestStatus(12733) == QUEST_STATUS_INCOMPLETE)
  7624. duel->opponent->CastSpell(duel->opponent, 52994, true);
  7625. }
  7626. break;
  7627. default:
  7628. break;
  7629. }
  7630.  
  7631. // Victory emote spell
  7632. if (type != DUEL_INTERRUPTED && duel->opponent)
  7633. duel->opponent->CastSpell(duel->opponent, 52852, true);
  7634.  
  7635. //Remove Duel Flag object
  7636. GameObject* obj = GetMap()->GetGameObject(GetUInt64Value(PLAYER_DUEL_ARBITER));
  7637. if (obj)
  7638. duel->initiator->RemoveGameObject(obj, true);
  7639.  
  7640. /* remove auras */
  7641. AuraApplicationMap &itsAuras = duel->opponent->GetAppliedAuras();
  7642. for (AuraApplicationMap::iterator i = itsAuras.begin(); i != itsAuras.end();)
  7643. {
  7644. Aura const* aura = i->second->GetBase();
  7645. if (!i->second->IsPositive() && aura->GetCasterGUID() == GetGUID() && aura->GetApplyTime() >= duel->startTime)
  7646. duel->opponent->RemoveAura(i);
  7647. else
  7648. ++i;
  7649. }
  7650.  
  7651. AuraApplicationMap &myAuras = GetAppliedAuras();
  7652. for (AuraApplicationMap::iterator i = myAuras.begin(); i != myAuras.end();)
  7653. {
  7654. Aura const* aura = i->second->GetBase();
  7655. if (!i->second->IsPositive() && aura->GetCasterGUID() == duel->opponent->GetGUID() && aura->GetApplyTime() >= duel->startTime)
  7656. RemoveAura(i);
  7657. else
  7658. ++i;
  7659. }
  7660.  
  7661. // cleanup combo points
  7662. if (GetComboTarget() == duel->opponent->GetGUID())
  7663. ClearComboPoints();
  7664. else if (GetComboTarget() == duel->opponent->GetPetGUID())
  7665. ClearComboPoints();
  7666.  
  7667. if (duel->opponent->GetComboTarget() == GetGUID())
  7668. duel->opponent->ClearComboPoints();
  7669. else if (duel->opponent->GetComboTarget() == GetPetGUID())
  7670. duel->opponent->ClearComboPoints();
  7671.  
  7672. // Honor points after duel (the winner) - ImpConfig
  7673. if (uint32 amount = sWorld->getIntConfig(CONFIG_HONOR_AFTER_DUEL))
  7674. duel->opponent->RewardHonor(NULL, 1, amount);
  7675.  
  7676. //cleanups
  7677. SetUInt64Value(PLAYER_DUEL_ARBITER, 0);
  7678. SetUInt32Value(PLAYER_DUEL_TEAM, 0);
  7679. duel->opponent->SetUInt64Value(PLAYER_DUEL_ARBITER, 0);
  7680. duel->opponent->SetUInt32Value(PLAYER_DUEL_TEAM, 0);
  7681.  
  7682. delete duel->opponent->duel;
  7683. duel->opponent->duel = NULL;
  7684. delete duel;
  7685. duel = NULL;
  7686. }
  7687.  
  7688. //---------------------------------------------------------//
  7689.  
  7690. void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply)
  7691. {
  7692. if (slot >= INVENTORY_SLOT_BAG_END || !item)
  7693. return;
  7694.  
  7695. ItemTemplate const* proto = item->GetTemplate();
  7696.  
  7697. if (!proto)
  7698. return;
  7699.  
  7700. // not apply/remove mods for broken item
  7701. if (item->IsBroken())
  7702. return;
  7703.  
  7704. sLog->outInfo(LOG_FILTER_PLAYER_ITEMS, "applying mods for item %u ", item->GetGUIDLow());
  7705.  
  7706. uint8 attacktype = Player::GetAttackBySlot(slot);
  7707.  
  7708. if (proto->Socket[0].Color) //only (un)equipping of items with sockets can influence metagems, so no need to waste time with normal items
  7709. CorrectMetaGemEnchants(slot, apply);
  7710.  
  7711. if (attacktype < MAX_ATTACK)
  7712. _ApplyWeaponDependentAuraMods(item, WeaponAttackType(attacktype), apply);
  7713.  
  7714. _ApplyItemBonuses(proto, slot, apply);
  7715.  
  7716. if (slot == EQUIPMENT_SLOT_RANGED)
  7717. _ApplyAmmoBonuses();
  7718.  
  7719. ApplyItemEquipSpell(item, apply);
  7720. ApplyEnchantment(item, apply);
  7721.  
  7722. sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "_ApplyItemMods complete.");
  7723. }
  7724.  
  7725. void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply, bool only_level_scale /*= false*/)
  7726. {
  7727. if (slot >= INVENTORY_SLOT_BAG_END || !proto)
  7728. return;
  7729.  
  7730. ScalingStatDistributionEntry const* ssd = proto->ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(proto->ScalingStatDistribution) : NULL;
  7731. if (only_level_scale && !ssd)
  7732. return;
  7733.  
  7734. // req. check at equip, but allow use for extended range if range limit max level, set proper level
  7735. uint32 ssd_level = getLevel();
  7736. if (ssd && ssd_level > ssd->MaxLevel)
  7737. ssd_level = ssd->MaxLevel;
  7738.  
  7739. ScalingStatValuesEntry const* ssv = proto->ScalingStatValue ? sScalingStatValuesStore.LookupEntry(ssd_level) : NULL;
  7740. if (only_level_scale && !ssv)
  7741. return;
  7742.  
  7743. for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
  7744. {
  7745. uint32 statType = 0;
  7746. int32 val = 0;
  7747. // If set ScalingStatDistribution need get stats and values from it
  7748. if (ssd && ssv)
  7749. {
  7750. if (ssd->StatMod[i] < 0)
  7751. continue;
  7752. statType = ssd->StatMod[i];
  7753. val = (ssv->getssdMultiplier(proto->ScalingStatValue) * ssd->Modifier[i]) / 10000;
  7754. }
  7755. else
  7756. {
  7757. if (i >= proto->StatsCount)
  7758. continue;
  7759. statType = proto->ItemStat[i].ItemStatType;
  7760. val = proto->ItemStat[i].ItemStatValue;
  7761. }
  7762.  
  7763. if (val == 0)
  7764. continue;
  7765.  
  7766. switch (statType)
  7767. {
  7768. case ITEM_MOD_MANA:
  7769. HandleStatModifier(UNIT_MOD_MANA, BASE_VALUE, float(val), apply);
  7770. break;
  7771. case ITEM_MOD_HEALTH: // modify HP
  7772. HandleStatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(val), apply);
  7773. break;
  7774. case ITEM_MOD_AGILITY: // modify agility
  7775. HandleStatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply);
  7776. ApplyStatBuffMod(STAT_AGILITY, float(val), apply);
  7777. break;
  7778. case ITEM_MOD_STRENGTH: //modify strength
  7779. HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply);
  7780. ApplyStatBuffMod(STAT_STRENGTH, float(val), apply);
  7781. break;
  7782. case ITEM_MOD_INTELLECT: //modify intellect
  7783. HandleStatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply);
  7784. ApplyStatBuffMod(STAT_INTELLECT, float(val), apply);
  7785. break;
  7786. case ITEM_MOD_SPIRIT: //modify spirit
  7787. HandleStatModifier(UNIT_MOD_STAT_SPIRIT, BASE_VALUE, float(val), apply);
  7788. ApplyStatBuffMod(STAT_SPIRIT, float(val), apply);
  7789. break;
  7790. case ITEM_MOD_STAMINA: //modify stamina
  7791. HandleStatModifier(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(val), apply);
  7792. ApplyStatBuffMod(STAT_STAMINA, float(val), apply);
  7793. break;
  7794. case ITEM_MOD_DEFENSE_SKILL_RATING:
  7795. ApplyRatingMod(CR_DEFENSE_SKILL, int32(val), apply);
  7796. break;
  7797. case ITEM_MOD_DODGE_RATING:
  7798. ApplyRatingMod(CR_DODGE, int32(val), apply);
  7799. break;
  7800. case ITEM_MOD_PARRY_RATING:
  7801. ApplyRatingMod(CR_PARRY, int32(val), apply);
  7802. break;
  7803. case ITEM_MOD_BLOCK_RATING:
  7804. ApplyRatingMod(CR_BLOCK, int32(val), apply);
  7805. break;
  7806. case ITEM_MOD_HIT_MELEE_RATING:
  7807. ApplyRatingMod(CR_HIT_MELEE, int32(val), apply);
  7808. break;
  7809. case ITEM_MOD_HIT_RANGED_RATING:
  7810. ApplyRatingMod(CR_HIT_RANGED, int32(val), apply);
  7811. break;
  7812. case ITEM_MOD_HIT_SPELL_RATING:
  7813. ApplyRatingMod(CR_HIT_SPELL, int32(val), apply);
  7814. break;
  7815. case ITEM_MOD_CRIT_MELEE_RATING:
  7816. ApplyRatingMod(CR_CRIT_MELEE, int32(val), apply);
  7817. break;
  7818. case ITEM_MOD_CRIT_RANGED_RATING:
  7819. ApplyRatingMod(CR_CRIT_RANGED, int32(val), apply);
  7820. break;
  7821. case ITEM_MOD_CRIT_SPELL_RATING:
  7822. ApplyRatingMod(CR_CRIT_SPELL, int32(val), apply);
  7823. break;
  7824. case ITEM_MOD_HIT_TAKEN_MELEE_RATING:
  7825. ApplyRatingMod(CR_HIT_TAKEN_MELEE, int32(val), apply);
  7826. break;
  7827. case ITEM_MOD_HIT_TAKEN_RANGED_RATING:
  7828. ApplyRatingMod(CR_HIT_TAKEN_RANGED, int32(val), apply);
  7829. break;
  7830. case ITEM_MOD_HIT_TAKEN_SPELL_RATING:
  7831. ApplyRatingMod(CR_HIT_TAKEN_SPELL, int32(val), apply);
  7832. break;
  7833. case ITEM_MOD_CRIT_TAKEN_MELEE_RATING:
  7834. ApplyRatingMod(CR_CRIT_TAKEN_MELEE, int32(val), apply);
  7835. break;
  7836. case ITEM_MOD_CRIT_TAKEN_RANGED_RATING:
  7837. ApplyRatingMod(CR_CRIT_TAKEN_RANGED, int32(val), apply);
  7838. break;
  7839. case ITEM_MOD_CRIT_TAKEN_SPELL_RATING:
  7840. ApplyRatingMod(CR_CRIT_TAKEN_SPELL, int32(val), apply);
  7841. break;
  7842. case ITEM_MOD_HASTE_MELEE_RATING:
  7843. ApplyRatingMod(CR_HASTE_MELEE, int32(val), apply);
  7844. break;
  7845. case ITEM_MOD_HASTE_RANGED_RATING:
  7846. ApplyRatingMod(CR_HASTE_RANGED, int32(val), apply);
  7847. break;
  7848. case ITEM_MOD_HASTE_SPELL_RATING:
  7849. ApplyRatingMod(CR_HASTE_SPELL, int32(val), apply);
  7850. break;
  7851. case ITEM_MOD_HIT_RATING:
  7852. ApplyRatingMod(CR_HIT_MELEE, int32(val), apply);
  7853. ApplyRatingMod(CR_HIT_RANGED, int32(val), apply);
  7854. ApplyRatingMod(CR_HIT_SPELL, int32(val), apply);
  7855. break;
  7856. case ITEM_MOD_CRIT_RATING:
  7857. ApplyRatingMod(CR_CRIT_MELEE, int32(val), apply);
  7858. ApplyRatingMod(CR_CRIT_RANGED, int32(val), apply);
  7859. ApplyRatingMod(CR_CRIT_SPELL, int32(val), apply);
  7860. break;
  7861. case ITEM_MOD_HIT_TAKEN_RATING:
  7862. ApplyRatingMod(CR_HIT_TAKEN_MELEE, int32(val), apply);
  7863. ApplyRatingMod(CR_HIT_TAKEN_RANGED, int32(val), apply);
  7864. ApplyRatingMod(CR_HIT_TAKEN_SPELL, int32(val), apply);
  7865. break;
  7866. case ITEM_MOD_CRIT_TAKEN_RATING:
  7867. ApplyRatingMod(CR_CRIT_TAKEN_MELEE, int32(val), apply);
  7868. ApplyRatingMod(CR_CRIT_TAKEN_RANGED, int32(val), apply);
  7869. ApplyRatingMod(CR_CRIT_TAKEN_SPELL, int32(val), apply);
  7870. break;
  7871. case ITEM_MOD_RESILIENCE_RATING:
  7872. ApplyRatingMod(CR_CRIT_TAKEN_MELEE, int32(val), apply);
  7873. ApplyRatingMod(CR_CRIT_TAKEN_RANGED, int32(val), apply);
  7874. ApplyRatingMod(CR_CRIT_TAKEN_SPELL, int32(val), apply);
  7875. break;
  7876. case ITEM_MOD_HASTE_RATING:
  7877. ApplyRatingMod(CR_HASTE_MELEE, int32(val), apply);
  7878. ApplyRatingMod(CR_HASTE_RANGED, int32(val), apply);
  7879. ApplyRatingMod(CR_HASTE_SPELL, int32(val), apply);
  7880. break;
  7881. case ITEM_MOD_EXPERTISE_RATING:
  7882. ApplyRatingMod(CR_EXPERTISE, int32(val), apply);
  7883. break;
  7884. case ITEM_MOD_ATTACK_POWER:
  7885. HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(val), apply);
  7886. HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply);
  7887. break;
  7888. case ITEM_MOD_RANGED_ATTACK_POWER:
  7889. HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply);
  7890. break;
  7891. // case ITEM_MOD_FERAL_ATTACK_POWER:
  7892. // ApplyFeralAPBonus(int32(val), apply);
  7893. // break;
  7894. case ITEM_MOD_MANA_REGENERATION:
  7895. ApplyManaRegenBonus(int32(val), apply);
  7896. break;
  7897. case ITEM_MOD_ARMOR_PENETRATION_RATING:
  7898. ApplyRatingMod(CR_ARMOR_PENETRATION, int32(val), apply);
  7899. break;
  7900. case ITEM_MOD_SPELL_POWER:
  7901. ApplySpellPowerBonus(int32(val), apply);
  7902. break;
  7903. case ITEM_MOD_HEALTH_REGEN:
  7904. ApplyHealthRegenBonus(int32(val), apply);
  7905. break;
  7906. case ITEM_MOD_SPELL_PENETRATION:
  7907. ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE, -val, apply);
  7908. m_spellPenetrationItemMod += apply ? val : -val;
  7909. break;
  7910. // deprecated item mods
  7911. case ITEM_MOD_SPELL_HEALING_DONE:
  7912. case ITEM_MOD_SPELL_DAMAGE_DONE:
  7913. break;
  7914. }
  7915. }
  7916.  
  7917. // Apply Spell Power from ScalingStatValue if set
  7918. if (ssv)
  7919. if (int32 spellbonus = ssv->getSpellBonus(proto->ScalingStatValue))
  7920. ApplySpellPowerBonus(spellbonus, apply);
  7921.  
  7922. // If set ScalingStatValue armor get it or use item armor
  7923. uint32 armor = proto->Armor;
  7924. if (ssv)
  7925. if (uint32 ssvarmor = ssv->getArmorMod(proto->ScalingStatValue))
  7926. armor = ssvarmor;
  7927.  
  7928. if (armor)
  7929. {
  7930. UnitModifierType modType = TOTAL_VALUE;
  7931. if (proto->Class == ITEM_CLASS_ARMOR)
  7932. {
  7933. switch (proto->SubClass)
  7934. {
  7935. case ITEM_SUBCLASS_ARMOR_CLOTH:
  7936. case ITEM_SUBCLASS_ARMOR_LEATHER:
  7937. case ITEM_SUBCLASS_ARMOR_MAIL:
  7938. case ITEM_SUBCLASS_ARMOR_PLATE:
  7939. case ITEM_SUBCLASS_ARMOR_SHIELD:
  7940. modType = BASE_VALUE;
  7941. break;
  7942. }
  7943. }
  7944. HandleStatModifier(UNIT_MOD_ARMOR, modType, float(armor), apply);
  7945. }
  7946.  
  7947. // Add armor bonus from ArmorDamageModifier if > 0
  7948. if (proto->ArmorDamageModifier > 0)
  7949. HandleStatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(proto->ArmorDamageModifier), apply);
  7950.  
  7951. if (proto->Block)
  7952. HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(proto->Block), apply);
  7953.  
  7954. if (proto->HolyRes)
  7955. HandleStatModifier(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(proto->HolyRes), apply);
  7956.  
  7957. if (proto->FireRes)
  7958. HandleStatModifier(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(proto->FireRes), apply);
  7959.  
  7960. if (proto->NatureRes)
  7961. HandleStatModifier(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(proto->NatureRes), apply);
  7962.  
  7963. if (proto->FrostRes)
  7964. HandleStatModifier(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(proto->FrostRes), apply);
  7965.  
  7966. if (proto->ShadowRes)
  7967. HandleStatModifier(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(proto->ShadowRes), apply);
  7968.  
  7969. if (proto->ArcaneRes)
  7970. HandleStatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(proto->ArcaneRes), apply);
  7971.  
  7972. WeaponAttackType attType = BASE_ATTACK;
  7973.  
  7974. if (slot == EQUIPMENT_SLOT_RANGED && (
  7975. proto->InventoryType == INVTYPE_RANGED || proto->InventoryType == INVTYPE_THROWN ||
  7976. proto->InventoryType == INVTYPE_RANGEDRIGHT))
  7977. {
  7978. attType = RANGED_ATTACK;
  7979. }
  7980. else if (slot == EQUIPMENT_SLOT_OFFHAND)
  7981. {
  7982. attType = OFF_ATTACK;
  7983. }
  7984.  
  7985. if (CanUseAttackType(attType))
  7986. _ApplyWeaponDamage(slot, proto, ssv, apply);
  7987.  
  7988.  
  7989. // Druids get feral AP bonus from weapon dps (also use DPS from ScalingStatValue)
  7990. if (getClass() == CLASS_DRUID)
  7991. {
  7992. int32 dpsMod = 0;
  7993. int32 feral_bonus = 0;
  7994. if (ssv)
  7995. {
  7996. dpsMod = ssv->getDPSMod(proto->ScalingStatValue);
  7997. feral_bonus += ssv->getFeralBonus(proto->ScalingStatValue);
  7998. }
  7999.  
  8000. feral_bonus += proto->getFeralBonus(dpsMod);
  8001. if (feral_bonus)
  8002. ApplyFeralAPBonus(feral_bonus, apply);
  8003. }
  8004. }
  8005.  
  8006. void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, ScalingStatValuesEntry const* ssv, bool apply)
  8007. {
  8008. WeaponAttackType attType = BASE_ATTACK;
  8009. float damage = 0.0f;
  8010.  
  8011. if (slot == EQUIPMENT_SLOT_RANGED && (
  8012. proto->InventoryType == INVTYPE_RANGED || proto->InventoryType == INVTYPE_THROWN ||
  8013. proto->InventoryType == INVTYPE_RANGEDRIGHT))
  8014. {
  8015. attType = RANGED_ATTACK;
  8016. }
  8017. else if (slot == EQUIPMENT_SLOT_OFFHAND)
  8018. {
  8019. attType = OFF_ATTACK;
  8020. }
  8021.  
  8022. float minDamage = proto->Damage[0].DamageMin;
  8023. float maxDamage = proto->Damage[0].DamageMax;
  8024.  
  8025. // If set dpsMod in ScalingStatValue use it for min (70% from average), max (130% from average) damage
  8026. if (ssv)
  8027. {
  8028. int32 extraDPS = ssv->getDPSMod(proto->ScalingStatValue);
  8029. if (extraDPS)
  8030. {
  8031. float average = extraDPS * proto->Delay / 1000.0f;
  8032. minDamage = 0.7f * average;
  8033. maxDamage = 1.3f * average;
  8034. }
  8035. }
  8036.  
  8037. if (minDamage > 0)
  8038. {
  8039. damage = apply ? minDamage : BASE_MINDAMAGE;
  8040. SetBaseWeaponDamage(attType, MINDAMAGE, damage);
  8041. }
  8042.  
  8043. if (maxDamage > 0)
  8044. {
  8045. damage = apply ? maxDamage : BASE_MAXDAMAGE;
  8046. SetBaseWeaponDamage(attType, MAXDAMAGE, damage);
  8047. }
  8048.  
  8049. if (proto->Delay && !IsInFeralForm())
  8050. {
  8051. if (slot == EQUIPMENT_SLOT_RANGED)
  8052. SetAttackTime(RANGED_ATTACK, apply ? proto->Delay: BASE_ATTACK_TIME);
  8053. else if (slot == EQUIPMENT_SLOT_MAINHAND)
  8054. SetAttackTime(BASE_ATTACK, apply ? proto->Delay: BASE_ATTACK_TIME);
  8055. else if (slot == EQUIPMENT_SLOT_OFFHAND)
  8056. SetAttackTime(OFF_ATTACK, apply ? proto->Delay: BASE_ATTACK_TIME);
  8057. }
  8058.  
  8059. // No need to modify any physical damage for ferals as it is calculated from stats only
  8060. if (IsInFeralForm())
  8061. return;
  8062.  
  8063. if (CanModifyStats() && (damage || proto->Delay))
  8064. UpdateDamagePhysical(attType);
  8065. }
  8066.  
  8067. void Player::_ApplyWeaponDependentAuraMods(Item* item, WeaponAttackType attackType, bool apply)
  8068. {
  8069. AuraEffectList const& auraCritList = GetAuraEffectsByType(SPELL_AURA_MOD_WEAPON_CRIT_PERCENT);
  8070. for (AuraEffectList::const_iterator itr = auraCritList.begin(); itr != auraCritList.end(); ++itr)
  8071. _ApplyWeaponDependentAuraCritMod(item, attackType, *itr, apply);
  8072.  
  8073. AuraEffectList const& auraDamageFlatList = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE);
  8074. for (AuraEffectList::const_iterator itr = auraDamageFlatList.begin(); itr != auraDamageFlatList.end(); ++itr)
  8075. _ApplyWeaponDependentAuraDamageMod(item, attackType, *itr, apply);
  8076.  
  8077. AuraEffectList const& auraDamagePctList = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
  8078. for (AuraEffectList::const_iterator itr = auraDamagePctList.begin(); itr != auraDamagePctList.end(); ++itr)
  8079. _ApplyWeaponDependentAuraDamageMod(item, attackType, *itr, apply);
  8080. }
  8081.  
  8082. void Player::_ApplyWeaponDependentAuraCritMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply)
  8083. {
  8084. // don't apply mod if item is broken or cannot be used
  8085. if (item->IsBroken() || !CanUseAttackType(attackType))
  8086. return;
  8087.  
  8088. // generic not weapon specific case processes in aura code
  8089. if (aura->GetSpellInfo()->EquippedItemClass == -1)
  8090. return;
  8091.  
  8092. BaseModGroup mod = BASEMOD_END;
  8093. switch (attackType)
  8094. {
  8095. case BASE_ATTACK: mod = CRIT_PERCENTAGE; break;
  8096. case OFF_ATTACK: mod = OFFHAND_CRIT_PERCENTAGE;break;
  8097. case RANGED_ATTACK: mod = RANGED_CRIT_PERCENTAGE; break;
  8098. default: return;
  8099. }
  8100.  
  8101. if (item->IsFitToSpellRequirements(aura->GetSpellInfo()))
  8102. HandleBaseModValue(mod, FLAT_MOD, float (aura->GetAmount()), apply);
  8103. }
  8104.  
  8105. void Player::_ApplyWeaponDependentAuraDamageMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply)
  8106. {
  8107. // don't apply mod if item is broken or cannot be used
  8108. if (item->IsBroken() || !CanUseAttackType(attackType))
  8109. return;
  8110.  
  8111. // ignore spell mods for not wands
  8112. if ((aura->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) == 0 && (getClassMask() & CLASSMASK_WAND_USERS) == 0)
  8113. return;
  8114.  
  8115. // generic not weapon specific case processes in aura code
  8116. if (aura->GetSpellInfo()->EquippedItemClass == -1)
  8117. return;
  8118.  
  8119. UnitMods unitMod = UNIT_MOD_END;
  8120. switch (attackType)
  8121. {
  8122. case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
  8123. case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
  8124. case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
  8125. default: return;
  8126. }
  8127.  
  8128. UnitModifierType unitModType = TOTAL_VALUE;
  8129. switch (aura->GetAuraType())
  8130. {
  8131. case SPELL_AURA_MOD_DAMAGE_DONE: unitModType = TOTAL_VALUE; break;
  8132. case SPELL_AURA_MOD_DAMAGE_PERCENT_DONE: unitModType = TOTAL_PCT; break;
  8133. default: return;
  8134. }
  8135.  
  8136. if (item->IsFitToSpellRequirements(aura->GetSpellInfo()))
  8137. {
  8138. HandleStatModifier(unitMod, unitModType, float(aura->GetAmount()), apply);
  8139. if (unitModType == TOTAL_VALUE)
  8140. ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, aura->GetAmount(), apply);
  8141. }
  8142. }
  8143.  
  8144. void Player::ApplyItemEquipSpell(Item* item, bool apply, bool form_change)
  8145. {
  8146. if (!item)
  8147. return;
  8148.  
  8149. ItemTemplate const* proto = item->GetTemplate();
  8150. if (!proto)
  8151. return;
  8152.  
  8153. for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
  8154. {
  8155. _Spell const& spellData = proto->Spells[i];
  8156.  
  8157. // no spell
  8158. if (!spellData.SpellId)
  8159. continue;
  8160.  
  8161. // wrong triggering type
  8162. if (apply && spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_EQUIP)
  8163. continue;
  8164.  
  8165. // check if it is valid spell
  8166. SpellInfo const* spellproto = sSpellMgr->GetSpellInfo(spellData.SpellId);
  8167. if (!spellproto)
  8168. continue;
  8169.  
  8170. ApplyEquipSpell(spellproto, item, apply, form_change);
  8171. }
  8172. }
  8173.  
  8174. void Player::ApplyEquipSpell(SpellInfo const* spellInfo, Item* item, bool apply, bool form_change)
  8175. {
  8176. if (apply)
  8177. {
  8178. // Cannot be used in this stance/form
  8179. if (spellInfo->CheckShapeshift(GetShapeshiftForm()) != SPELL_CAST_OK)
  8180. return;
  8181.  
  8182. if (form_change) // check aura active state from other form
  8183. {
  8184. AuraApplicationMap const& auras = GetAppliedAuras();
  8185. for (AuraApplicationMap::const_iterator itr = auras.lower_bound(spellInfo->Id); itr != auras.upper_bound(spellInfo->Id); ++itr)
  8186. if (!item || itr->second->GetBase()->GetCastItemGUID() == item->GetGUID())
  8187. return;
  8188. }
  8189.  
  8190. sLog->outDebug(LOG_FILTER_PLAYER, "WORLD: cast %s Equip spellId - %i", (item ? "item" : "itemset"), spellInfo->Id);
  8191.  
  8192. CastSpell(this, spellInfo, true, item);
  8193. }
  8194. else
  8195. {
  8196. if (form_change) // check aura compatibility
  8197. {
  8198. // Cannot be used in this stance/form
  8199. if (spellInfo->CheckShapeshift(GetShapeshiftForm()) == SPELL_CAST_OK)
  8200. return; // and remove only not compatible at form change
  8201. }
  8202.  
  8203. if (item)
  8204. RemoveAurasDueToItemSpell(item, spellInfo->Id); // un-apply all spells, not only at-equipped
  8205. else
  8206. RemoveAurasDueToSpell(spellInfo->Id); // un-apply spell (item set case)
  8207. }
  8208. }
  8209.  
  8210. void Player::UpdateEquipSpellsAtFormChange()
  8211. {
  8212. for (uint8 i = 0; i < INVENTORY_SLOT_BAG_END; ++i)
  8213. {
  8214. if (m_items[i] && !m_items[i]->IsBroken() && CanUseAttackType(GetAttackBySlot(i)))
  8215. {
  8216. ApplyItemEquipSpell(m_items[i], false, true); // remove spells that not fit to form
  8217. ApplyItemEquipSpell(m_items[i], true, true); // add spells that fit form but not active
  8218. }
  8219. }
  8220.  
  8221. // item set bonuses not dependent from item broken state
  8222. for (size_t setindex = 0; setindex < ItemSetEff.size(); ++setindex)
  8223. {
  8224. ItemSetEffect* eff = ItemSetEff[setindex];
  8225. if (!eff)
  8226. continue;
  8227.  
  8228. for (uint32 y = 0; y < MAX_ITEM_SET_SPELLS; ++y)
  8229. {
  8230. SpellInfo const* spellInfo = eff->spells[y];
  8231. if (!spellInfo)
  8232. continue;
  8233.  
  8234. ApplyEquipSpell(spellInfo, NULL, false, true); // remove spells that not fit to form
  8235. ApplyEquipSpell(spellInfo, NULL, true, true); // add spells that fit form but not active
  8236. }
  8237. }
  8238. }
  8239. void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx)
  8240. {
  8241. if (!target || !target->isAlive() || target == this)
  8242. return;
  8243.  
  8244. for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)
  8245. {
  8246. // If usable, try to cast item spell
  8247. if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  8248. if (!item->IsBroken() && CanUseAttackType(attType))
  8249. if (ItemTemplate const* proto = item->GetTemplate())
  8250. {
  8251. // Additional check for weapons
  8252. if (proto->Class == ITEM_CLASS_WEAPON)
  8253. {
  8254. // offhand item cannot proc from main hand hit etc
  8255. EquipmentSlots slot;
  8256. switch (attType)
  8257. {
  8258. case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
  8259. case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
  8260. case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break;
  8261. default: slot = EQUIPMENT_SLOT_END; break;
  8262. }
  8263. if (slot != i)
  8264. continue;
  8265. // Check if item is useable (forms or disarm)
  8266. if (attType == BASE_ATTACK)
  8267. if (!IsUseEquipedWeapon(true) && !IsInFeralForm())
  8268. continue;
  8269. }
  8270. CastItemCombatSpell(target, attType, procVictim, procEx, item, proto);
  8271. }
  8272. }
  8273. }
  8274.  
  8275. void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item* item, ItemTemplate const* proto)
  8276. {
  8277. // Can do effect if any damage done to target
  8278. if (procVictim & PROC_FLAG_TAKEN_DAMAGE)
  8279. //if (damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE)
  8280. {
  8281. for (uint8 i = 0; i < MAX_ITEM_SPELLS; ++i)
  8282. {
  8283. _Spell const& spellData = proto->Spells[i];
  8284.  
  8285. // no spell
  8286. if (!spellData.SpellId)
  8287. continue;
  8288.  
  8289. // wrong triggering type
  8290. if (spellData.SpellTrigger != ITEM_SPELLTRIGGER_CHANCE_ON_HIT)
  8291. continue;
  8292.  
  8293. SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellData.SpellId);
  8294. if (!spellInfo)
  8295. {
  8296. sLog->outError(LOG_FILTER_PLAYER_ITEMS, "WORLD: unknown Item spellid %i", spellData.SpellId);
  8297. continue;
  8298. }
  8299.  
  8300. // not allow proc extra attack spell at extra attack
  8301. if (m_extraAttacks && spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS))
  8302. return;
  8303.  
  8304. float chance = (float)spellInfo->ProcChance;
  8305.  
  8306. if (spellData.SpellPPMRate)
  8307. {
  8308. if (spellData.SpellId == 52781) // Persuasive Strike
  8309. {
  8310. switch (target->GetEntry())
  8311. {
  8312. default:
  8313. return;
  8314. case 28939:
  8315. case 28940:
  8316. case 28610:
  8317. break;
  8318. }
  8319. }
  8320. uint32 WeaponSpeed = GetAttackTime(attType);
  8321. chance = GetPPMProcChance(WeaponSpeed, spellData.SpellPPMRate, spellInfo);
  8322. }
  8323. else if (chance > 100.0f)
  8324. {
  8325. chance = GetWeaponProcChance();
  8326. }
  8327.  
  8328. if (roll_chance_f(chance))
  8329. CastSpell(target, spellInfo->Id, true, item);
  8330. }
  8331. }
  8332.  
  8333. // item combat enchantments
  8334. for (uint8 e_slot = 0; e_slot < MAX_ENCHANTMENT_SLOT; ++e_slot)
  8335. {
  8336. uint32 enchant_id = item->GetEnchantmentId(EnchantmentSlot(e_slot));
  8337. SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
  8338. if (!pEnchant)
  8339. continue;
  8340.  
  8341. for (uint8 s = 0; s < MAX_ITEM_ENCHANTMENT_EFFECTS; ++s)
  8342. {
  8343. if (pEnchant->type[s] != ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
  8344. continue;
  8345.  
  8346. SpellEnchantProcEntry const* entry = sSpellMgr->GetSpellEnchantProcEvent(enchant_id);
  8347.  
  8348. if (entry && entry->procEx)
  8349. {
  8350. // Check hit/crit/dodge/parry requirement
  8351. if ((entry->procEx & procEx) == 0)
  8352. continue;
  8353. }
  8354. else
  8355. {
  8356. // Can do effect if any damage done to target
  8357. if (!(procVictim & PROC_FLAG_TAKEN_DAMAGE))
  8358. //if (!(damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE))
  8359. continue;
  8360. }
  8361.  
  8362. SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(pEnchant->spellid[s]);
  8363. if (!spellInfo)
  8364. {
  8365. sLog->outError(LOG_FILTER_PLAYER_ITEMS, "Player::CastItemCombatSpell(GUID: %u, name: %s, enchant: %i): unknown spell %i is casted, ignoring...",
  8366. GetGUIDLow(), GetName(), pEnchant->ID, pEnchant->spellid[s]);
  8367. continue;
  8368. }
  8369.  
  8370. float chance = pEnchant->amount[s] != 0 ? float(pEnchant->amount[s]) : GetWeaponProcChance();
  8371.  
  8372. if (entry)
  8373. {
  8374. if (entry->PPMChance)
  8375. chance = GetPPMProcChance(proto->Delay, entry->PPMChance, spellInfo);
  8376. else if (entry->customChance)
  8377. chance = (float)entry->customChance;
  8378. }
  8379.  
  8380. // Apply spell mods
  8381. ApplySpellMod(pEnchant->spellid[s], SPELLMOD_CHANCE_OF_SUCCESS, chance);
  8382.  
  8383. // Shiv has 100% chance to apply the poison
  8384. if (FindCurrentSpellBySpellId(5938) && e_slot == TEMP_ENCHANTMENT_SLOT)
  8385. chance = 100.0f;
  8386.  
  8387. if (roll_chance_f(chance))
  8388. {
  8389. if (spellInfo->IsPositive())
  8390. CastSpell(this, spellInfo, true, item);
  8391. else
  8392. CastSpell(target, spellInfo, true, item);
  8393. }
  8394. }
  8395. }
  8396. }
  8397.  
  8398. void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8 cast_count, uint32 glyphIndex)
  8399. {
  8400. ItemTemplate const* proto = item->GetTemplate();
  8401. // special learning case
  8402. if (proto->Spells[0].SpellId == 483 || proto->Spells[0].SpellId == 55884)
  8403. {
  8404. uint32 learn_spell_id = proto->Spells[0].SpellId;
  8405. uint32 learning_spell_id = proto->Spells[1].SpellId;
  8406.  
  8407. SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(learn_spell_id);
  8408. if (!spellInfo)
  8409. {
  8410. sLog->outError(LOG_FILTER_PLAYER, "Player::CastItemUseSpell: Item (Entry: %u) in have wrong spell id %u, ignoring ", proto->ItemId, learn_spell_id);
  8411. SendEquipError(EQUIP_ERR_NONE, item, NULL);
  8412. return;
  8413. }
  8414.  
  8415. Spell* spell = new Spell(this, spellInfo, TRIGGERED_NONE);
  8416. spell->m_CastItem = item;
  8417. spell->m_cast_count = cast_count; //set count of casts
  8418. spell->SetSpellValue(SPELLVALUE_BASE_POINT0, learning_spell_id);
  8419. spell->prepare(&targets);
  8420. return;
  8421. }
  8422.  
  8423. // use triggered flag only for items with many spell casts and for not first cast
  8424. uint8 count = 0;
  8425.  
  8426. // item spells casted at use
  8427. for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
  8428. {
  8429. _Spell const& spellData = proto->Spells[i];
  8430.  
  8431. // no spell
  8432. if (!spellData.SpellId)
  8433. continue;
  8434.  
  8435. // wrong triggering type
  8436. if (spellData.SpellTrigger != ITEM_SPELLTRIGGER_ON_USE)
  8437. continue;
  8438.  
  8439. SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellData.SpellId);
  8440. if (!spellInfo)
  8441. {
  8442. sLog->outError(LOG_FILTER_PLAYER, "Player::CastItemUseSpell: Item (Entry: %u) in have wrong spell id %u, ignoring", proto->ItemId, spellData.SpellId);
  8443. continue;
  8444. }
  8445.  
  8446. Spell* spell = new Spell(this, spellInfo, (count > 0) ? TRIGGERED_FULL_MASK : TRIGGERED_NONE);
  8447. spell->m_CastItem = item;
  8448. spell->m_cast_count = cast_count; // set count of casts
  8449. spell->m_glyphIndex = glyphIndex; // glyph index
  8450. spell->prepare(&targets);
  8451.  
  8452. ++count;
  8453. }
  8454.  
  8455. // Item enchantments spells casted at use
  8456. for (uint8 e_slot = 0; e_slot < MAX_ENCHANTMENT_SLOT; ++e_slot)
  8457. {
  8458. uint32 enchant_id = item->GetEnchantmentId(EnchantmentSlot(e_slot));
  8459. SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
  8460. if (!pEnchant)
  8461. continue;
  8462. for (uint8 s = 0; s < MAX_ITEM_ENCHANTMENT_EFFECTS; ++s)
  8463. {
  8464. if (pEnchant->type[s] != ITEM_ENCHANTMENT_TYPE_USE_SPELL)
  8465. continue;
  8466.  
  8467. SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(pEnchant->spellid[s]);
  8468. if (!spellInfo)
  8469. {
  8470. sLog->outError(LOG_FILTER_PLAYER, "Player::CastItemUseSpell Enchant %i, cast unknown spell %i", pEnchant->ID, pEnchant->spellid[s]);
  8471. continue;
  8472. }
  8473.  
  8474. Spell* spell = new Spell(this, spellInfo, (count > 0) ? TRIGGERED_FULL_MASK : TRIGGERED_NONE);
  8475. spell->m_CastItem = item;
  8476. spell->m_cast_count = cast_count; // set count of casts
  8477. spell->m_glyphIndex = glyphIndex; // glyph index
  8478. spell->prepare(&targets);
  8479.  
  8480. ++count;
  8481. }
  8482. }
  8483. }
  8484.  
  8485. void Player::_RemoveAllItemMods()
  8486. {
  8487. sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "_RemoveAllItemMods start.");
  8488.  
  8489. for (uint8 i = 0; i < INVENTORY_SLOT_BAG_END; ++i)
  8490. {
  8491. if (m_items[i])
  8492. {
  8493. ItemTemplate const* proto = m_items[i]->GetTemplate();
  8494. if (!proto)
  8495. continue;
  8496.  
  8497. // item set bonuses not dependent from item broken state
  8498. if (proto->ItemSet)
  8499. RemoveItemsSetItem(this, proto);
  8500.  
  8501. if (m_items[i]->IsBroken() || !CanUseAttackType(GetAttackBySlot(i)))
  8502. continue;
  8503.  
  8504. ApplyItemEquipSpell(m_items[i], false);
  8505. ApplyEnchantment(m_items[i], false);
  8506. }
  8507. }
  8508.  
  8509. for (uint8 i = 0; i < INVENTORY_SLOT_BAG_END; ++i)
  8510. {
  8511. if (m_items[i])
  8512. {
  8513. if (m_items[i]->IsBroken() || !CanUseAttackType(GetAttackBySlot(i)))
  8514. continue;
  8515. ItemTemplate const* proto = m_items[i]->GetTemplate();
  8516. if (!proto)
  8517. continue;
  8518.  
  8519. uint32 attacktype = Player::GetAttackBySlot(i);
  8520. if (attacktype < MAX_ATTACK)
  8521. _ApplyWeaponDependentAuraMods(m_items[i], WeaponAttackType(attacktype), false);
  8522.  
  8523. _ApplyItemBonuses(proto, i, false);
  8524.  
  8525. if (i == EQUIPMENT_SLOT_RANGED)
  8526. _ApplyAmmoBonuses();
  8527. }
  8528. }
  8529.  
  8530. sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "_RemoveAllItemMods complete.");
  8531. }
  8532.  
  8533. void Player::_ApplyAllItemMods()
  8534. {
  8535. sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "_ApplyAllItemMods start.");
  8536.  
  8537. for (uint8 i = 0; i < INVENTORY_SLOT_BAG_END; ++i)
  8538. {
  8539. if (m_items[i])
  8540. {
  8541. if (m_items[i]->IsBroken() || !CanUseAttackType(GetAttackBySlot(i)))
  8542. continue;
  8543.  
  8544. ItemTemplate const* proto = m_items[i]->GetTemplate();
  8545. if (!proto)
  8546. continue;
  8547.  
  8548. uint32 attacktype = Player::GetAttackBySlot(i);
  8549. if (attacktype < MAX_ATTACK)
  8550. _ApplyWeaponDependentAuraMods(m_items[i], WeaponAttackType(attacktype), true);
  8551.  
  8552. _ApplyItemBonuses(proto, i, true);
  8553.  
  8554. if (i == EQUIPMENT_SLOT_RANGED)
  8555. _ApplyAmmoBonuses();
  8556. }
  8557. }
  8558.  
  8559. for (uint8 i = 0; i < INVENTORY_SLOT_BAG_END; ++i)
  8560. {
  8561. if (m_items[i])
  8562. {
  8563. ItemTemplate const* proto = m_items[i]->GetTemplate();
  8564. if (!proto)
  8565. continue;
  8566.  
  8567. // item set bonuses not dependent from item broken state
  8568. if (proto->ItemSet)
  8569. AddItemsSetItem(this, m_items[i]);
  8570.  
  8571. if (m_items[i]->IsBroken() || !CanUseAttackType(GetAttackBySlot(i)))
  8572. continue;
  8573.  
  8574. ApplyItemEquipSpell(m_items[i], true);
  8575. ApplyEnchantment(m_items[i], true);
  8576. }
  8577. }
  8578.  
  8579. sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "_ApplyAllItemMods complete.");
  8580. }
  8581.  
  8582. void Player::_ApplyAllLevelScaleItemMods(bool apply)
  8583. {
  8584. for (uint8 i = 0; i < INVENTORY_SLOT_BAG_END; ++i)
  8585. {
  8586. if (m_items[i])
  8587. {
  8588. if (m_items[i]->IsBroken() || !CanUseAttackType(GetAttackBySlot(i)))
  8589. continue;
  8590.  
  8591. ItemTemplate const* proto = m_items[i]->GetTemplate();
  8592. if (!proto)
  8593. continue;
  8594.  
  8595. _ApplyItemBonuses(proto, i, apply, true);
  8596. }
  8597. }
  8598. }
  8599.  
  8600. void Player::_ApplyAmmoBonuses()
  8601. {
  8602. // check ammo
  8603. uint32 ammo_id = GetUInt32Value(PLAYER_AMMO_ID);
  8604. if (!ammo_id)
  8605. return;
  8606.  
  8607. float currentAmmoDPS;
  8608.  
  8609. ItemTemplate const* ammo_proto = sObjectMgr->GetItemTemplate(ammo_id);
  8610. if (!ammo_proto || ammo_proto->Class != ITEM_CLASS_PROJECTILE || !CheckAmmoCompatibility(ammo_proto))
  8611. currentAmmoDPS = 0.0f;
  8612. else
  8613. currentAmmoDPS = (ammo_proto->Damage[0].DamageMin + ammo_proto->Damage[0].DamageMax) / 2;
  8614.  
  8615. if (currentAmmoDPS == GetAmmoDPS())
  8616. return;
  8617.  
  8618. m_ammoDPS = currentAmmoDPS;
  8619.  
  8620. if (CanModifyStats())
  8621. UpdateDamagePhysical(RANGED_ATTACK);
  8622. }
  8623.  
  8624. bool Player::CheckAmmoCompatibility(const ItemTemplate* ammo_proto) const
  8625. {
  8626. if (!ammo_proto)
  8627. return false;
  8628.  
  8629. // check ranged weapon
  8630. Item* weapon = GetWeaponForAttack(RANGED_ATTACK);
  8631. if (!weapon || weapon->IsBroken())
  8632. return false;
  8633.  
  8634. ItemTemplate const* weapon_proto = weapon->GetTemplate();
  8635. if (!weapon_proto || weapon_proto->Class != ITEM_CLASS_WEAPON)
  8636. return false;
  8637.  
  8638. // check ammo ws. weapon compatibility
  8639. switch (weapon_proto->SubClass)
  8640. {
  8641. case ITEM_SUBCLASS_WEAPON_BOW:
  8642. case ITEM_SUBCLASS_WEAPON_CROSSBOW:
  8643. if (ammo_proto->SubClass != ITEM_SUBCLASS_ARROW)
  8644. return false;
  8645. break;
  8646. case ITEM_SUBCLASS_WEAPON_GUN:
  8647. if (ammo_proto->SubClass != ITEM_SUBCLASS_BULLET)
  8648. return false;
  8649. break;
  8650. default:
  8651. return false;
  8652. }
  8653.  
  8654. return true;
  8655. }
  8656.  
  8657. /* If in a battleground a player dies, and an enemy removes the insignia, the player's bones is lootable
  8658. Called by remove insignia spell effect */
  8659. void Player::RemovedInsignia(Player* looterPlr)
  8660. {
  8661. if (!GetBattlegroundId())
  8662. return;
  8663.  
  8664. // If not released spirit, do it !
  8665. if (m_deathTimer > 0)
  8666. {
  8667. m_deathTimer = 0;
  8668. BuildPlayerRepop();
  8669. RepopAtGraveyard();
  8670. }
  8671.  
  8672. // We have to convert player corpse to bones, not to be able to resurrect there
  8673. // SpawnCorpseBones isn't handy, 'cos it saves player while he in BG
  8674. Corpse* bones = sObjectAccessor->ConvertCorpseForPlayer(GetGUID(), true);
  8675. if (!bones)
  8676. return;
  8677.  
  8678. // Now we must make bones lootable, and send player loot
  8679. bones->SetFlag(CORPSE_FIELD_DYNAMIC_FLAGS, CORPSE_DYNFLAG_LOOTABLE);
  8680.  
  8681. // We store the level of our player in the gold field
  8682. // We retrieve this information at Player::SendLoot()
  8683. bones->loot.gold = getLevel();
  8684. bones->lootRecipient = looterPlr;
  8685. looterPlr->SendLoot(bones->GetGUID(), LOOT_INSIGNIA);
  8686. }
  8687.  
  8688. void Player::SendLootRelease(uint64 guid)
  8689. {
  8690. WorldPacket data(SMSG_LOOT_RELEASE_RESPONSE, (8+1));
  8691. data << uint64(guid) << uint8(1);
  8692. SendDirectMessage(&data);
  8693. }
  8694.  
  8695. void Player::SendLoot(uint64 guid, LootType loot_type)
  8696. {
  8697. if (uint64 lguid = GetLootGUID())
  8698. m_session->DoLootRelease(lguid);
  8699.  
  8700. Loot* loot = 0;
  8701. PermissionTypes permission = ALL_PERMISSION;
  8702.  
  8703. sLog->outDebug(LOG_FILTER_LOOT, "Player::SendLoot");
  8704. if (IS_GAMEOBJECT_GUID(guid))
  8705. {
  8706. sLog->outDebug(LOG_FILTER_LOOT, "IS_GAMEOBJECT_GUID(guid)");
  8707. GameObject* go = GetMap()->GetGameObject(guid);
  8708.  
  8709. // not check distance for GO in case owned GO (fishing bobber case, for example)
  8710. // And permit out of range GO with no owner in case fishing hole
  8711. if (!go || (loot_type != LOOT_FISHINGHOLE && (loot_type != LOOT_FISHING || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this, INTERACTION_DISTANCE)) || (loot_type == LOOT_CORPSE && go->GetRespawnTime() && go->isSpawnedByDefault()))
  8712. {
  8713. SendLootRelease(guid);
  8714. return;
  8715. }
  8716.  
  8717. loot = &go->loot;
  8718.  
  8719. if (go->getLootState() == GO_READY)
  8720. {
  8721. uint32 lootid = go->GetGOInfo()->GetLootId();
  8722.  
  8723. //TODO: fix this big hack
  8724. if ((go->GetEntry() == BG_AV_OBJECTID_MINE_N || go->GetEntry() == BG_AV_OBJECTID_MINE_S))
  8725. if (Battleground* bg = GetBattleground())
  8726. if (bg->GetTypeID(true) == BATTLEGROUND_AV)
  8727. if (!(((BattlegroundAV*)bg)->PlayerCanDoMineQuest(go->GetEntry(), GetTeam())))
  8728. {
  8729. SendLootRelease(guid);
  8730. return;
  8731. }
  8732.  
  8733. if (lootid)
  8734. {
  8735. loot->clear();
  8736.  
  8737. Group* group = GetGroup();
  8738. bool groupRules = (group && go->GetGOInfo()->type == GAMEOBJECT_TYPE_CHEST && go->GetGOInfo()->chest.groupLootRules);
  8739.  
  8740. // check current RR player and get next if necessary
  8741. if (groupRules)
  8742. group->UpdateLooterGuid(go, true);
  8743.  
  8744. loot->FillLoot(lootid, LootTemplates_Gameobject, this, !groupRules, false, go->GetLootMode());
  8745.  
  8746. // get next RR player (for next loot)
  8747. if (groupRules)
  8748. group->UpdateLooterGuid(go);
  8749. }
  8750.  
  8751. if (loot_type == LOOT_FISHING)
  8752. go->getFishLoot(loot, this);
  8753.  
  8754. if (go->GetGOInfo()->type == GAMEOBJECT_TYPE_CHEST && go->GetGOInfo()->chest.groupLootRules)
  8755. {
  8756. if (Group* group = GetGroup())
  8757. {
  8758. switch (group->GetLootMethod())
  8759. {
  8760. case GROUP_LOOT:
  8761. // GroupLoot: rolls items over threshold. Items with quality < threshold, round robin
  8762. group->GroupLoot(loot, go);
  8763. break;
  8764. case NEED_BEFORE_GREED:
  8765. group->NeedBeforeGreed(loot, go);
  8766. break;
  8767. case MASTER_LOOT:
  8768. group->MasterLoot(loot, go);
  8769. break;
  8770. default:
  8771. break;
  8772. }
  8773. }
  8774. }
  8775.  
  8776. go->SetLootState(GO_ACTIVATED, this);
  8777. }
  8778.  
  8779. if (go->getLootState() == GO_ACTIVATED)
  8780. {
  8781. if (Group* group = GetGroup())
  8782. {
  8783. switch (group->GetLootMethod())
  8784. {
  8785. case MASTER_LOOT:
  8786. permission = MASTER_PERMISSION;
  8787. break;
  8788. case FREE_FOR_ALL:
  8789. permission = ALL_PERMISSION;
  8790. break;
  8791. case ROUND_ROBIN:
  8792. permission = ROUND_ROBIN_PERMISSION;
  8793. break;
  8794. default:
  8795. permission = GROUP_PERMISSION;
  8796. break;
  8797. }
  8798. }
  8799. else
  8800. permission = ALL_PERMISSION;
  8801. }
  8802. }
  8803. else if (IS_ITEM_GUID(guid))
  8804. {
  8805. Item* item = GetItemByGuid(guid);
  8806.  
  8807. if (!item)
  8808. {
  8809. SendLootRelease(guid);
  8810. return;
  8811. }
  8812.  
  8813. permission = OWNER_PERMISSION;
  8814.  
  8815. loot = &item->loot;
  8816.  
  8817. if (!item->m_lootGenerated)
  8818. {
  8819. item->m_lootGenerated = true;
  8820. loot->clear();
  8821.  
  8822. switch (loot_type)
  8823. {
  8824. case LOOT_DISENCHANTING:
  8825. loot->FillLoot(item->GetTemplate()->DisenchantID, LootTemplates_Disenchant, this, true);
  8826. break;
  8827. case LOOT_PROSPECTING:
  8828. loot->FillLoot(item->GetEntry(), LootTemplates_Prospecting, this, true);
  8829. break;
  8830. case LOOT_MILLING:
  8831. loot->FillLoot(item->GetEntry(), LootTemplates_Milling, this, true);
  8832. break;
  8833. default:
  8834. loot->generateMoneyLoot(item->GetTemplate()->MinMoneyLoot, item->GetTemplate()->MaxMoneyLoot);
  8835. loot->FillLoot(item->GetEntry(), LootTemplates_Item, this, true, loot->gold != 0);
  8836. break;
  8837. }
  8838. }
  8839. }
  8840. else if (IS_CORPSE_GUID(guid)) // remove insignia
  8841. {
  8842. Corpse* bones = ObjectAccessor::GetCorpse(*this, guid);
  8843.  
  8844. if (!bones || !(loot_type == LOOT_CORPSE || loot_type == LOOT_INSIGNIA) || bones->GetType() != CORPSE_BONES)
  8845. {
  8846. SendLootRelease(guid);
  8847. return;
  8848. }
  8849.  
  8850. loot = &bones->loot;
  8851.  
  8852. if (!bones->lootForBody)
  8853. {
  8854. bones->lootForBody = true;
  8855. uint32 pLevel = bones->loot.gold;
  8856. bones->loot.clear();
  8857. if (Battleground* bg = GetBattleground())
  8858. if (bg->GetTypeID(true) == BATTLEGROUND_AV)
  8859. loot->FillLoot(1, LootTemplates_Creature, this, true);
  8860. // It may need a better formula
  8861. // Now it works like this: lvl10: ~6copper, lvl70: ~9silver
  8862. bones->loot.gold = uint32(urand(50, 150) * 0.016f * pow(float(pLevel)/5.76f, 2.5f) * sWorld->getRate(RATE_DROP_MONEY));
  8863. }
  8864.  
  8865. if (bones->lootRecipient != this)
  8866. permission = NONE_PERMISSION;
  8867. else
  8868. permission = OWNER_PERMISSION;
  8869. }
  8870. else
  8871. {
  8872. Creature* creature = GetMap()->GetCreature(guid);
  8873.  
  8874. // must be in range and creature must be alive for pickpocket and must be dead for another loot
  8875. if (!creature || creature->isAlive() != (loot_type == LOOT_PICKPOCKETING) || !creature->IsWithinDistInMap(this, INTERACTION_DISTANCE))
  8876. {
  8877. SendLootRelease(guid);
  8878. return;
  8879. }
  8880.  
  8881. if (loot_type == LOOT_PICKPOCKETING && IsFriendlyTo(creature))
  8882. {
  8883. SendLootRelease(guid);
  8884. return;
  8885. }
  8886.  
  8887. loot = &creature->loot;
  8888.  
  8889. if (loot_type == LOOT_PICKPOCKETING)
  8890. {
  8891. if (!creature->lootForPickPocketed)
  8892. {
  8893. creature->lootForPickPocketed = true;
  8894. loot->clear();
  8895.  
  8896. if (uint32 lootid = creature->GetCreatureTemplate()->pickpocketLootId)
  8897. loot->FillLoot(lootid, LootTemplates_Pickpocketing, this, true);
  8898.  
  8899. // Generate extra money for pick pocket loot
  8900. const uint32 a = urand(0, creature->getLevel()/2);
  8901. const uint32 b = urand(0, getLevel()/2);
  8902. loot->gold = uint32(10 * (a + b) * sWorld->getRate(RATE_DROP_MONEY));
  8903. permission = OWNER_PERMISSION;
  8904. }
  8905. }
  8906. else
  8907. {
  8908. // the player whose group may loot the corpse
  8909. Player* recipient = creature->GetLootRecipient();
  8910. if (!recipient)
  8911. return;
  8912.  
  8913. if (!creature->lootForBody)
  8914. {
  8915. creature->lootForBody = true;
  8916.  
  8917. // for creature, loot is filled when creature is killed.
  8918.  
  8919. if (Group* group = recipient->GetGroup())
  8920. {
  8921. switch (group->GetLootMethod())
  8922. {
  8923. case GROUP_LOOT:
  8924. // GroupLoot: rolls items over threshold. Items with quality < threshold, round robin
  8925. group->GroupLoot(loot, creature);
  8926. break;
  8927. case NEED_BEFORE_GREED:
  8928. group->NeedBeforeGreed(loot, creature);
  8929. break;
  8930. case MASTER_LOOT:
  8931. group->MasterLoot(loot, creature);
  8932. break;
  8933. default:
  8934. break;
  8935. }
  8936. }
  8937. }
  8938.  
  8939. // possible only if creature->lootForBody && loot->empty() at spell cast check
  8940. if (loot_type == LOOT_SKINNING)
  8941. {
  8942. loot->clear();
  8943. loot->FillLoot(creature->GetCreatureTemplate()->SkinLootId, LootTemplates_Skinning, this, true);
  8944. permission = OWNER_PERMISSION;
  8945. }
  8946. // set group rights only for loot_type != LOOT_SKINNING
  8947. else
  8948. {
  8949. if (Group* group = GetGroup())
  8950. {
  8951. if (group == recipient->GetGroup())
  8952. {
  8953. switch (group->GetLootMethod())
  8954. {
  8955. case MASTER_LOOT:
  8956. permission = MASTER_PERMISSION;
  8957. break;
  8958. case FREE_FOR_ALL:
  8959. permission = ALL_PERMISSION;
  8960. break;
  8961. case ROUND_ROBIN:
  8962. permission = ROUND_ROBIN_PERMISSION;
  8963. break;
  8964. default:
  8965. permission = GROUP_PERMISSION;
  8966. break;
  8967. }
  8968. }
  8969. else
  8970. permission = NONE_PERMISSION;
  8971. }
  8972. else if (recipient == this)
  8973. permission = OWNER_PERMISSION;
  8974. else
  8975. permission = NONE_PERMISSION;
  8976. }
  8977. }
  8978. }
  8979.  
  8980. SetLootGUID(guid);
  8981.  
  8982. // LOOT_INSIGNIA and LOOT_FISHINGHOLE unsupported by client
  8983. switch (loot_type)
  8984. {
  8985. case LOOT_INSIGNIA: loot_type = LOOT_SKINNING; break;
  8986. case LOOT_FISHINGHOLE: loot_type = LOOT_FISHING; break;
  8987. default: break;
  8988. }
  8989.  
  8990. // need know merged fishing/corpse loot type for achievements
  8991. loot->loot_type = loot_type;
  8992.  
  8993. WorldPacket data(SMSG_LOOT_RESPONSE, (9+50)); // we guess size
  8994. data << uint64(guid);
  8995. data << uint8(loot_type);
  8996. data << LootView(*loot, this, permission);
  8997.  
  8998. SendDirectMessage(&data);
  8999.  
  9000. // add 'this' player as one of the players that are looting 'loot'
  9001. if (permission != NONE_PERMISSION)
  9002. loot->AddLooter(GetGUID());
  9003.  
  9004. if (loot_type == LOOT_CORPSE && !IS_ITEM_GUID(guid))
  9005. SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING);
  9006. }
  9007.  
  9008. void Player::SendNotifyLootMoneyRemoved()
  9009. {
  9010. WorldPacket data(SMSG_LOOT_CLEAR_MONEY, 0);
  9011. GetSession()->SendPacket(&data);
  9012. }
  9013.  
  9014. void Player::SendNotifyLootItemRemoved(uint8 lootSlot)
  9015. {
  9016. WorldPacket data(SMSG_LOOT_REMOVED, 1);
  9017. data << uint8(lootSlot);
  9018. GetSession()->SendPacket(&data);
  9019. }
  9020.  
  9021. void Player::SendUpdateWorldState(uint32 Field, uint32 Value)
  9022. {
  9023. WorldPacket data(SMSG_UPDATE_WORLD_STATE, 8);
  9024. data << Field;
  9025. data << Value;
  9026. GetSession()->SendPacket(&data);
  9027. }
  9028.  
  9029. void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid)
  9030. {
  9031. // data depends on zoneid/mapid...
  9032. Battleground* bg = GetBattleground();
  9033. uint16 NumberOfFields = 0;
  9034. uint32 mapid = GetMapId();
  9035. OutdoorPvP* pvp = sOutdoorPvPMgr->GetOutdoorPvPToZoneId(zoneid);
  9036. InstanceScript* instance = GetInstanceScript();
  9037.  
  9038. sLog->outDebug(LOG_FILTER_NETWORKIO, "Sending SMSG_INIT_WORLD_STATES to Map: %u, Zone: %u", mapid, zoneid);
  9039.  
  9040. // may be exist better way to do this...
  9041. switch (zoneid)
  9042. {
  9043. case 0:
  9044. case 1:
  9045. case 4:
  9046. case 8:
  9047. case 10:
  9048. case 11:
  9049. case 12:
  9050. case 36:
  9051. case 38:
  9052. case 40:
  9053. case 41:
  9054. case 51:
  9055. case 267:
  9056. case 1519:
  9057. case 1537:
  9058. case 2257:
  9059. case 2918:
  9060. NumberOfFields = 8;
  9061. break;
  9062. case 139:
  9063. NumberOfFields = 41;
  9064. break;
  9065. case 1377:
  9066. NumberOfFields = 15;
  9067. break;
  9068. case 2597:
  9069. NumberOfFields = 83;
  9070. break;
  9071. case 3277:
  9072. NumberOfFields = 16;
  9073. break;
  9074. case 3358:
  9075. case 3820:
  9076. NumberOfFields = 40;
  9077. break;
  9078. case 3483:
  9079. NumberOfFields = 27;
  9080. break;
  9081. case 3518:
  9082. NumberOfFields = 39;
  9083. break;
  9084. case 3519:
  9085. NumberOfFields = 38;
  9086. break;
  9087. case 3521:
  9088. NumberOfFields = 37;
  9089. break;
  9090. case 3698:
  9091. case 3702:
  9092. case 3968:
  9093. case 4378:
  9094. case 3703:
  9095. NumberOfFields = 11;
  9096. break;
  9097. case 4384:
  9098. NumberOfFields = 30;
  9099. break;
  9100. case 4710:
  9101. NumberOfFields = 28;
  9102. break;
  9103. case 4812: // Icecrown Citadel
  9104. case 4100: // The Culling of Stratholme
  9105. NumberOfFields = 13;
  9106. break;
  9107. case 4273: // Ulduar
  9108. NumberOfFields = 10;
  9109. break;
  9110. default:
  9111. NumberOfFields = 12;
  9112. break;
  9113. }
  9114.  
  9115. WorldPacket data(SMSG_INIT_WORLD_STATES, (4+4+4+2+(NumberOfFields*8)));
  9116. data << uint32(mapid); // mapid
  9117. data << uint32(zoneid); // zone id
  9118. data << uint32(areaid); // area id, new 2.1.0
  9119. data << uint16(NumberOfFields); // count of uint64 blocks
  9120. data << uint32(0x8d8) << uint32(0x0); // 1
  9121. data << uint32(0x8d7) << uint32(0x0); // 2
  9122. data << uint32(0x8d6) << uint32(0x0); // 3
  9123. data << uint32(0x8d5) << uint32(0x0); // 4
  9124. data << uint32(0x8d4) << uint32(0x0); // 5
  9125. data << uint32(0x8d3) << uint32(0x0); // 6
  9126. // 7 1 - Arena season in progress, 0 - end of season
  9127. data << uint32(0xC77) << uint32(sWorld->getBoolConfig(CONFIG_ARENA_SEASON_IN_PROGRESS));
  9128. // 8 Arena season id
  9129. data << uint32(0xF3D) << uint32(sWorld->getIntConfig(CONFIG_ARENA_SEASON_ID));
  9130.  
  9131. if (mapid == 530) // Outland
  9132. {
  9133. data << uint32(0x9bf) << uint32(0x0); // 7
  9134. data << uint32(0x9bd) << uint32(0xF); // 8
  9135. data << uint32(0x9bb) << uint32(0xF); // 9
  9136. }
  9137.  
  9138. // insert <field> <value>
  9139. switch (zoneid)
  9140. {
  9141. case 1: // Dun Morogh
  9142. case 11: // Wetlands
  9143. case 12: // Elwynn Forest
  9144. case 38: // Loch Modan
  9145. case 40: // Westfall
  9146. case 51: // Searing Gorge
  9147. case 1519: // Stormwind City
  9148. case 1537: // Ironforge
  9149. case 2257: // Deeprun Tram
  9150. case 3703: // Shattrath City
  9151. break;
  9152. case 139: // Eastern Plaguelands
  9153. if (pvp && pvp->GetTypeId() == OUTDOOR_PVP_EP)
  9154. pvp->FillInitialWorldStates(data);
  9155. else
  9156. {
  9157. data << uint32(0x97a) << uint32(0x0); // 10 2426
  9158. data << uint32(0x917) << uint32(0x0); // 11 2327
  9159. data << uint32(0x918) << uint32(0x0); // 12 2328
  9160. data << uint32(0x97b) << uint32(0x32); // 13 2427
  9161. data << uint32(0x97c) << uint32(0x32); // 14 2428
  9162. data << uint32(0x933) << uint32(0x1); // 15 2355
  9163. data << uint32(0x946) << uint32(0x0); // 16 2374
  9164. data << uint32(0x947) << uint32(0x0); // 17 2375
  9165. data << uint32(0x948) << uint32(0x0); // 18 2376
  9166. data << uint32(0x949) << uint32(0x0); // 19 2377
  9167. data << uint32(0x94a) << uint32(0x0); // 20 2378
  9168. data << uint32(0x94b) << uint32(0x0); // 21 2379
  9169. data << uint32(0x932) << uint32(0x0); // 22 2354
  9170. data << uint32(0x934) << uint32(0x0); // 23 2356
  9171. data << uint32(0x935) << uint32(0x0); // 24 2357
  9172. data << uint32(0x936) << uint32(0x0); // 25 2358
  9173. data << uint32(0x937) << uint32(0x0); // 26 2359
  9174. data << uint32(0x938) << uint32(0x0); // 27 2360
  9175. data << uint32(0x939) << uint32(0x1); // 28 2361
  9176. data << uint32(0x930) << uint32(0x1); // 29 2352
  9177. data << uint32(0x93a) << uint32(0x0); // 30 2362
  9178. data << uint32(0x93b) << uint32(0x0); // 31 2363
  9179. data << uint32(0x93c) << uint32(0x0); // 32 2364
  9180. data << uint32(0x93d) << uint32(0x0); // 33 2365
  9181. data << uint32(0x944) << uint32(0x0); // 34 2372
  9182. data << uint32(0x945) << uint32(0x0); // 35 2373
  9183. data << uint32(0x931) << uint32(0x1); // 36 2353
  9184. data << uint32(0x93e) << uint32(0x0); // 37 2366
  9185. data << uint32(0x931) << uint32(0x1); // 38 2367 ?? grey horde not in dbc! send for consistency's sake, and to match field count
  9186. data << uint32(0x940) << uint32(0x0); // 39 2368
  9187. data << uint32(0x941) << uint32(0x0); // 7 2369
  9188. data << uint32(0x942) << uint32(0x0); // 8 2370
  9189. data << uint32(0x943) << uint32(0x0); // 9 2371
  9190. }
  9191. break;
  9192. case 1377: // Silithus
  9193. if (pvp && pvp->GetTypeId() == OUTDOOR_PVP_SI)
  9194. pvp->FillInitialWorldStates(data);
  9195. else
  9196. {
  9197. // states are always shown
  9198. data << uint32(2313) << uint32(0x0); // 7 ally silityst gathered
  9199. data << uint32(2314) << uint32(0x0); // 8 horde silityst gathered
  9200. data << uint32(2317) << uint32(0x0); // 9 max silithyst
  9201. }
  9202. // dunno about these... aq opening event maybe?
  9203. data << uint32(2322) << uint32(0x0); // 10 sandworm N
  9204. data << uint32(2323) << uint32(0x0); // 11 sandworm S
  9205. data << uint32(2324) << uint32(0x0); // 12 sandworm SW
  9206. data << uint32(2325) << uint32(0x0); // 13 sandworm E
  9207. break;
  9208. case 2597: // Alterac Valley
  9209. if (bg && bg->GetTypeID(true) == BATTLEGROUND_AV)
  9210. bg->FillInitialWorldStates(data);
  9211. else
  9212. {
  9213. data << uint32(0x7ae) << uint32(0x1); // 7 snowfall n
  9214. data << uint32(0x532) << uint32(0x1); // 8 frostwolfhut hc
  9215. data << uint32(0x531) << uint32(0x0); // 9 frostwolfhut ac
  9216. data << uint32(0x52e) << uint32(0x0); // 10 stormpike firstaid a_a
  9217. data << uint32(0x571) << uint32(0x0); // 11 east frostwolf tower horde assaulted -unused
  9218. data << uint32(0x570) << uint32(0x0); // 12 west frostwolf tower horde assaulted - unused
  9219. data << uint32(0x567) << uint32(0x1); // 13 frostwolfe c
  9220. data << uint32(0x566) << uint32(0x1); // 14 frostwolfw c
  9221. data << uint32(0x550) << uint32(0x1); // 15 irondeep (N) ally
  9222. data << uint32(0x544) << uint32(0x0); // 16 ice grave a_a
  9223. data << uint32(0x536) << uint32(0x0); // 17 stormpike grave h_c
  9224. data << uint32(0x535) << uint32(0x1); // 18 stormpike grave a_c
  9225. data << uint32(0x518) << uint32(0x0); // 19 stoneheart grave a_a
  9226. data << uint32(0x517) << uint32(0x0); // 20 stoneheart grave h_a
  9227. data << uint32(0x574) << uint32(0x0); // 21 1396 unk
  9228. data << uint32(0x573) << uint32(0x0); // 22 iceblood tower horde assaulted -unused
  9229. data << uint32(0x572) << uint32(0x0); // 23 towerpoint horde assaulted - unused
  9230. data << uint32(0x56f) << uint32(0x0); // 24 1391 unk
  9231. data << uint32(0x56e) << uint32(0x0); // 25 iceblood a
  9232. data << uint32(0x56d) << uint32(0x0); // 26 towerp a
  9233. data << uint32(0x56c) << uint32(0x0); // 27 frostwolfe a
  9234. data << uint32(0x56b) << uint32(0x0); // 28 froswolfw a
  9235. data << uint32(0x56a) << uint32(0x1); // 29 1386 unk
  9236. data << uint32(0x569) << uint32(0x1); // 30 iceblood c
  9237. data << uint32(0x568) << uint32(0x1); // 31 towerp c
  9238. data << uint32(0x565) << uint32(0x0); // 32 stoneh tower a
  9239. data << uint32(0x564) << uint32(0x0); // 33 icewing tower a
  9240. data << uint32(0x563) << uint32(0x0); // 34 dunn a
  9241. data << uint32(0x562) << uint32(0x0); // 35 duns a
  9242. data << uint32(0x561) << uint32(0x0); // 36 stoneheart bunker alliance assaulted - unused
  9243. data << uint32(0x560) << uint32(0x0); // 37 icewing bunker alliance assaulted - unused
  9244. data << uint32(0x55f) << uint32(0x0); // 38 dunbaldar south alliance assaulted - unused
  9245. data << uint32(0x55e) << uint32(0x0); // 39 dunbaldar north alliance assaulted - unused
  9246. data << uint32(0x55d) << uint32(0x0); // 40 stone tower d
  9247. data << uint32(0x3c6) << uint32(0x0); // 41 966 unk
  9248. data << uint32(0x3c4) << uint32(0x0); // 42 964 unk
  9249. data << uint32(0x3c2) << uint32(0x0); // 43 962 unk
  9250. data << uint32(0x516) << uint32(0x1); // 44 stoneheart grave a_c
  9251. data << uint32(0x515) << uint32(0x0); // 45 stonheart grave h_c
  9252. data << uint32(0x3b6) << uint32(0x0); // 46 950 unk
  9253. data << uint32(0x55c) << uint32(0x0); // 47 icewing tower d
  9254. data << uint32(0x55b) << uint32(0x0); // 48 dunn d
  9255. data << uint32(0x55a) << uint32(0x0); // 49 duns d
  9256. data << uint32(0x559) << uint32(0x0); // 50 1369 unk
  9257. data << uint32(0x558) << uint32(0x0); // 51 iceblood d
  9258. data << uint32(0x557) << uint32(0x0); // 52 towerp d
  9259. data << uint32(0x556) << uint32(0x0); // 53 frostwolfe d
  9260. data << uint32(0x555) << uint32(0x0); // 54 frostwolfw d
  9261. data << uint32(0x554) << uint32(0x1); // 55 stoneh tower c
  9262. data << uint32(0x553) << uint32(0x1); // 56 icewing tower c
  9263. data << uint32(0x552) << uint32(0x1); // 57 dunn c
  9264. data << uint32(0x551) << uint32(0x1); // 58 duns c
  9265. data << uint32(0x54f) << uint32(0x0); // 59 irondeep (N) horde
  9266. data << uint32(0x54e) << uint32(0x0); // 60 irondeep (N) ally
  9267. data << uint32(0x54d) << uint32(0x1); // 61 mine (S) neutral
  9268. data << uint32(0x54c) << uint32(0x0); // 62 mine (S) horde
  9269. data << uint32(0x54b) << uint32(0x0); // 63 mine (S) ally
  9270. data << uint32(0x545) << uint32(0x0); // 64 iceblood h_a
  9271. data << uint32(0x543) << uint32(0x1); // 65 iceblod h_c
  9272. data << uint32(0x542) << uint32(0x0); // 66 iceblood a_c
  9273. data << uint32(0x540) << uint32(0x0); // 67 snowfall h_a
  9274. data << uint32(0x53f) << uint32(0x0); // 68 snowfall a_a
  9275. data << uint32(0x53e) << uint32(0x0); // 69 snowfall h_c
  9276. data << uint32(0x53d) << uint32(0x0); // 70 snowfall a_c
  9277. data << uint32(0x53c) << uint32(0x0); // 71 frostwolf g h_a
  9278. data << uint32(0x53b) << uint32(0x0); // 72 frostwolf g a_a
  9279. data << uint32(0x53a) << uint32(0x1); // 73 frostwolf g h_c
  9280. data << uint32(0x539) << uint32(0x0); // 74 frostwolf g a_c
  9281. data << uint32(0x538) << uint32(0x0); // 75 stormpike grave h_a
  9282. data << uint32(0x537) << uint32(0x0); // 76 stormpike grave a_a
  9283. data << uint32(0x534) << uint32(0x0); // 77 frostwolf hut h_a
  9284. data << uint32(0x533) << uint32(0x0); // 78 frostwolf hut a_a
  9285. data << uint32(0x530) << uint32(0x0); // 79 stormpike first aid h_a
  9286. data << uint32(0x52f) << uint32(0x0); // 80 stormpike first aid h_c
  9287. data << uint32(0x52d) << uint32(0x1); // 81 stormpike first aid a_c
  9288. }
  9289. break;
  9290. case 3277: // Warsong Gulch
  9291. if (bg && bg->GetTypeID(true) == BATTLEGROUND_WS)
  9292. bg->FillInitialWorldStates(data);
  9293. else
  9294. {
  9295. data << uint32(0x62d) << uint32(0x0); // 7 1581 alliance flag captures
  9296. data << uint32(0x62e) << uint32(0x0); // 8 1582 horde flag captures
  9297. data << uint32(0x609) << uint32(0x0); // 9 1545 unk, set to 1 on alliance flag pickup...
  9298. data << uint32(0x60a) << uint32(0x0); // 10 1546 unk, set to 1 on horde flag pickup, after drop it's -1
  9299. data << uint32(0x60b) << uint32(0x2); // 11 1547 unk
  9300. data << uint32(0x641) << uint32(0x3); // 12 1601 unk (max flag captures?)
  9301. data << uint32(0x922) << uint32(0x1); // 13 2338 horde (0 - hide, 1 - flag ok, 2 - flag picked up (flashing), 3 - flag picked up (not flashing)
  9302. data << uint32(0x923) << uint32(0x1); // 14 2339 alliance (0 - hide, 1 - flag ok, 2 - flag picked up (flashing), 3 - flag picked up (not flashing)
  9303. }
  9304. break;
  9305. case 3358: // Arathi Basin
  9306. if (bg && bg->GetTypeID(true) == BATTLEGROUND_AB)
  9307. bg->FillInitialWorldStates(data);
  9308. else
  9309. {
  9310. data << uint32(0x6e7) << uint32(0x0); // 7 1767 stables alliance
  9311. data << uint32(0x6e8) << uint32(0x0); // 8 1768 stables horde
  9312. data << uint32(0x6e9) << uint32(0x0); // 9 1769 unk, ST?
  9313. data << uint32(0x6ea) << uint32(0x0); // 10 1770 stables (show/hide)
  9314. data << uint32(0x6ec) << uint32(0x0); // 11 1772 farm (0 - horde controlled, 1 - alliance controlled)
  9315. data << uint32(0x6ed) << uint32(0x0); // 12 1773 farm (show/hide)
  9316. data << uint32(0x6ee) << uint32(0x0); // 13 1774 farm color
  9317. data << uint32(0x6ef) << uint32(0x0); // 14 1775 gold mine color, may be FM?
  9318. data << uint32(0x6f0) << uint32(0x0); // 15 1776 alliance resources
  9319. data << uint32(0x6f1) << uint32(0x0); // 16 1777 horde resources
  9320. data << uint32(0x6f2) << uint32(0x0); // 17 1778 horde bases
  9321. data << uint32(0x6f3) << uint32(0x0); // 18 1779 alliance bases
  9322. data << uint32(0x6f4) << uint32(0x7d0); // 19 1780 max resources (2000)
  9323. data << uint32(0x6f6) << uint32(0x0); // 20 1782 blacksmith color
  9324. data << uint32(0x6f7) << uint32(0x0); // 21 1783 blacksmith (show/hide)
  9325. data << uint32(0x6f8) << uint32(0x0); // 22 1784 unk, bs?
  9326. data << uint32(0x6f9) << uint32(0x0); // 23 1785 unk, bs?
  9327. data << uint32(0x6fb) << uint32(0x0); // 24 1787 gold mine (0 - horde contr, 1 - alliance contr)
  9328. data << uint32(0x6fc) << uint32(0x0); // 25 1788 gold mine (0 - conflict, 1 - horde)
  9329. data << uint32(0x6fd) << uint32(0x0); // 26 1789 gold mine (1 - show/0 - hide)
  9330. data << uint32(0x6fe) << uint32(0x0); // 27 1790 gold mine color
  9331. data << uint32(0x700) << uint32(0x0); // 28 1792 gold mine color, wtf?, may be LM?
  9332. data << uint32(0x701) << uint32(0x0); // 29 1793 lumber mill color (0 - conflict, 1 - horde contr)
  9333. data << uint32(0x702) << uint32(0x0); // 30 1794 lumber mill (show/hide)
  9334. data << uint32(0x703) << uint32(0x0); // 31 1795 lumber mill color color
  9335. data << uint32(0x732) << uint32(0x1); // 32 1842 stables (1 - uncontrolled)
  9336. data << uint32(0x733) << uint32(0x1); // 33 1843 gold mine (1 - uncontrolled)
  9337. data << uint32(0x734) << uint32(0x1); // 34 1844 lumber mill (1 - uncontrolled)
  9338. data << uint32(0x735) << uint32(0x1); // 35 1845 farm (1 - uncontrolled)
  9339. data << uint32(0x736) << uint32(0x1); // 36 1846 blacksmith (1 - uncontrolled)
  9340. data << uint32(0x745) << uint32(0x2); // 37 1861 unk
  9341. data << uint32(0x7a3) << uint32(0x708); // 38 1955 warning limit (1800)
  9342. }
  9343. break;
  9344. case 3820: // Eye of the Storm
  9345. if (bg && bg->GetTypeID(true) == BATTLEGROUND_EY)
  9346. bg->FillInitialWorldStates(data);
  9347. else
  9348. {
  9349. data << uint32(0xac1) << uint32(0x0); // 7 2753 Horde Bases
  9350. data << uint32(0xac0) << uint32(0x0); // 8 2752 Alliance Bases
  9351. data << uint32(0xab6) << uint32(0x0); // 9 2742 Mage Tower - Horde conflict
  9352. data << uint32(0xab5) << uint32(0x0); // 10 2741 Mage Tower - Alliance conflict
  9353. data << uint32(0xab4) << uint32(0x0); // 11 2740 Fel Reaver - Horde conflict
  9354. data << uint32(0xab3) << uint32(0x0); // 12 2739 Fel Reaver - Alliance conflict
  9355. data << uint32(0xab2) << uint32(0x0); // 13 2738 Draenei - Alliance conflict
  9356. data << uint32(0xab1) << uint32(0x0); // 14 2737 Draenei - Horde conflict
  9357. data << uint32(0xab0) << uint32(0x0); // 15 2736 unk // 0 at start
  9358. data << uint32(0xaaf) << uint32(0x0); // 16 2735 unk // 0 at start
  9359. data << uint32(0xaad) << uint32(0x0); // 17 2733 Draenei - Horde control
  9360. data << uint32(0xaac) << uint32(0x0); // 18 2732 Draenei - Alliance control
  9361. data << uint32(0xaab) << uint32(0x1); // 19 2731 Draenei uncontrolled (1 - yes, 0 - no)
  9362. data << uint32(0xaaa) << uint32(0x0); // 20 2730 Mage Tower - Alliance control
  9363. data << uint32(0xaa9) << uint32(0x0); // 21 2729 Mage Tower - Horde control
  9364. data << uint32(0xaa8) << uint32(0x1); // 22 2728 Mage Tower uncontrolled (1 - yes, 0 - no)
  9365. data << uint32(0xaa7) << uint32(0x0); // 23 2727 Fel Reaver - Horde control
  9366. data << uint32(0xaa6) << uint32(0x0); // 24 2726 Fel Reaver - Alliance control
  9367. data << uint32(0xaa5) << uint32(0x1); // 25 2725 Fel Reaver uncontrolled (1 - yes, 0 - no)
  9368. data << uint32(0xaa4) << uint32(0x0); // 26 2724 Boold Elf - Horde control
  9369. data << uint32(0xaa3) << uint32(0x0); // 27 2723 Boold Elf - Alliance control
  9370. data << uint32(0xaa2) << uint32(0x1); // 28 2722 Boold Elf uncontrolled (1 - yes, 0 - no)
  9371. data << uint32(0xac5) << uint32(0x1); // 29 2757 Flag (1 - show, 0 - hide) - doesn't work exactly this way!
  9372. data << uint32(0xad2) << uint32(0x1); // 30 2770 Horde top-stats (1 - show, 0 - hide) // 02 -> horde picked up the flag
  9373. data << uint32(0xad1) << uint32(0x1); // 31 2769 Alliance top-stats (1 - show, 0 - hide) // 02 -> alliance picked up the flag
  9374. data << uint32(0xabe) << uint32(0x0); // 32 2750 Horde resources
  9375. data << uint32(0xabd) << uint32(0x0); // 33 2749 Alliance resources
  9376. data << uint32(0xa05) << uint32(0x8e); // 34 2565 unk, constant?
  9377. data << uint32(0xaa0) << uint32(0x0); // 35 2720 Capturing progress-bar (100 -> empty (only grey), 0 -> blue|red (no grey), default 0)
  9378. data << uint32(0xa9f) << uint32(0x0); // 36 2719 Capturing progress-bar (0 - left, 100 - right)
  9379. data << uint32(0xa9e) << uint32(0x0); // 37 2718 Capturing progress-bar (1 - show, 0 - hide)
  9380. data << uint32(0xc0d) << uint32(0x17b); // 38 3085 unk
  9381. // and some more ... unknown
  9382. }
  9383. break;
  9384. // any of these needs change! the client remembers the prev setting!
  9385. // ON EVERY ZONE LEAVE, RESET THE OLD ZONE'S WORLD STATE, BUT AT LEAST THE UI STUFF!
  9386. case 3483: // Hellfire Peninsula
  9387. if (pvp && pvp->GetTypeId() == OUTDOOR_PVP_HP)
  9388. pvp->FillInitialWorldStates(data);
  9389. else
  9390. {
  9391. data << uint32(0x9ba) << uint32(0x1); // 10 // add ally tower main gui icon // maybe should be sent only on login?
  9392. data << uint32(0x9b9) << uint32(0x1); // 11 // add horde tower main gui icon // maybe should be sent only on login?
  9393. data << uint32(0x9b5) << uint32(0x0); // 12 // show neutral broken hill icon // 2485
  9394. data << uint32(0x9b4) << uint32(0x1); // 13 // show icon above broken hill // 2484
  9395. data << uint32(0x9b3) << uint32(0x0); // 14 // show ally broken hill icon // 2483
  9396. data << uint32(0x9b2) << uint32(0x0); // 15 // show neutral overlook icon // 2482
  9397. data << uint32(0x9b1) << uint32(0x1); // 16 // show the overlook arrow // 2481
  9398. data << uint32(0x9b0) << uint32(0x0); // 17 // show ally overlook icon // 2480
  9399. data << uint32(0x9ae) << uint32(0x0); // 18 // horde pvp objectives captured // 2478
  9400. data << uint32(0x9ac) << uint32(0x0); // 19 // ally pvp objectives captured // 2476
  9401. data << uint32(2475) << uint32(100); //: ally / horde slider grey area // show only in direct vicinity!
  9402. data << uint32(2474) << uint32(50); //: ally / horde slider percentage, 100 for ally, 0 for horde // show only in direct vicinity!
  9403. data << uint32(2473) << uint32(0); //: ally / horde slider display // show only in direct vicinity!
  9404. data << uint32(0x9a8) << uint32(0x0); // 20 // show the neutral stadium icon // 2472
  9405. data << uint32(0x9a7) << uint32(0x0); // 21 // show the ally stadium icon // 2471
  9406. data << uint32(0x9a6) << uint32(0x1); // 22 // show the horde stadium icon // 2470
  9407. }
  9408. break;
  9409. case 3518: // Nagrand
  9410. if (pvp && pvp->GetTypeId() == OUTDOOR_PVP_NA)
  9411. pvp->FillInitialWorldStates(data);
  9412. else
  9413. {
  9414. data << uint32(2503) << uint32(0x0); // 10
  9415. data << uint32(2502) << uint32(0x0); // 11
  9416. data << uint32(2493) << uint32(0x0); // 12
  9417. data << uint32(2491) << uint32(0x0); // 13
  9418.  
  9419. data << uint32(2495) << uint32(0x0); // 14
  9420. data << uint32(2494) << uint32(0x0); // 15
  9421. data << uint32(2497) << uint32(0x0); // 16
  9422.  
  9423. data << uint32(2762) << uint32(0x0); // 17
  9424. data << uint32(2662) << uint32(0x0); // 18
  9425. data << uint32(2663) << uint32(0x0); // 19
  9426. data << uint32(2664) << uint32(0x0); // 20
  9427.  
  9428. data << uint32(2760) << uint32(0x0); // 21
  9429. data << uint32(2670) << uint32(0x0); // 22
  9430. data << uint32(2668) << uint32(0x0); // 23
  9431. data << uint32(2669) << uint32(0x0); // 24
  9432.  
  9433. data << uint32(2761) << uint32(0x0); // 25
  9434. data << uint32(2667) << uint32(0x0); // 26
  9435. data << uint32(2665) << uint32(0x0); // 27
  9436. data << uint32(2666) << uint32(0x0); // 28
  9437.  
  9438. data << uint32(2763) << uint32(0x0); // 29
  9439. data << uint32(2659) << uint32(0x0); // 30
  9440. data << uint32(2660) << uint32(0x0); // 31
  9441. data << uint32(2661) << uint32(0x0); // 32
  9442.  
  9443. data << uint32(2671) << uint32(0x0); // 33
  9444. data << uint32(2676) << uint32(0x0); // 34
  9445. data << uint32(2677) << uint32(0x0); // 35
  9446. data << uint32(2672) << uint32(0x0); // 36
  9447. data << uint32(2673) << uint32(0x0); // 37
  9448. }
  9449. break;
  9450. case 3519: // Terokkar Forest
  9451. if (pvp && pvp->GetTypeId() == OUTDOOR_PVP_TF)
  9452. pvp->FillInitialWorldStates(data);
  9453. else
  9454. {
  9455. data << uint32(0xa41) << uint32(0x0); // 10 // 2625 capture bar pos
  9456. data << uint32(0xa40) << uint32(0x14); // 11 // 2624 capture bar neutral
  9457. data << uint32(0xa3f) << uint32(0x0); // 12 // 2623 show capture bar
  9458. data << uint32(0xa3e) << uint32(0x0); // 13 // 2622 horde towers controlled
  9459. data << uint32(0xa3d) << uint32(0x5); // 14 // 2621 ally towers controlled
  9460. data << uint32(0xa3c) << uint32(0x0); // 15 // 2620 show towers controlled
  9461. data << uint32(0xa88) << uint32(0x0); // 16 // 2696 SE Neu
  9462. data << uint32(0xa87) << uint32(0x0); // 17 // SE Horde
  9463. data << uint32(0xa86) << uint32(0x0); // 18 // SE Ally
  9464. data << uint32(0xa85) << uint32(0x0); // 19 //S Neu
  9465. data << uint32(0xa84) << uint32(0x0); // 20 S Horde
  9466. data << uint32(0xa83) << uint32(0x0); // 21 S Ally
  9467. data << uint32(0xa82) << uint32(0x0); // 22 NE Neu
  9468. data << uint32(0xa81) << uint32(0x0); // 23 NE Horde
  9469. data << uint32(0xa80) << uint32(0x0); // 24 NE Ally
  9470. data << uint32(0xa7e) << uint32(0x0); // 25 // 2686 N Neu
  9471. data << uint32(0xa7d) << uint32(0x0); // 26 N Horde
  9472. data << uint32(0xa7c) << uint32(0x0); // 27 N Ally
  9473. data << uint32(0xa7b) << uint32(0x0); // 28 NW Ally
  9474. data << uint32(0xa7a) << uint32(0x0); // 29 NW Horde
  9475. data << uint32(0xa79) << uint32(0x0); // 30 NW Neutral
  9476. data << uint32(0x9d0) << uint32(0x5); // 31 // 2512 locked time remaining seconds first digit
  9477. data << uint32(0x9ce) << uint32(0x0); // 32 // 2510 locked time remaining seconds second digit
  9478. data << uint32(0x9cd) << uint32(0x0); // 33 // 2509 locked time remaining minutes
  9479. data << uint32(0x9cc) << uint32(0x0); // 34 // 2508 neutral locked time show
  9480. data << uint32(0xad0) << uint32(0x0); // 35 // 2768 horde locked time show
  9481. data << uint32(0xacf) << uint32(0x1); // 36 // 2767 ally locked time show
  9482. }
  9483. break;
  9484. case 3521: // Zangarmarsh
  9485. if (pvp && pvp->GetTypeId() == OUTDOOR_PVP_ZM)
  9486. pvp->FillInitialWorldStates(data);
  9487. else
  9488. {
  9489. data << uint32(0x9e1) << uint32(0x0); // 10 //2529
  9490. data << uint32(0x9e0) << uint32(0x0); // 11
  9491. data << uint32(0x9df) << uint32(0x0); // 12
  9492. data << uint32(0xa5d) << uint32(0x1); // 13 //2653
  9493. data << uint32(0xa5c) << uint32(0x0); // 14 //2652 east beacon neutral
  9494. data << uint32(0xa5b) << uint32(0x1); // 15 horde
  9495. data << uint32(0xa5a) << uint32(0x0); // 16 ally
  9496. data << uint32(0xa59) << uint32(0x1); // 17 // 2649 Twin spire graveyard horde 12???
  9497. data << uint32(0xa58) << uint32(0x0); // 18 ally 14 ???
  9498. data << uint32(0xa57) << uint32(0x0); // 19 neutral 7???
  9499. data << uint32(0xa56) << uint32(0x0); // 20 // 2646 west beacon neutral
  9500. data << uint32(0xa55) << uint32(0x1); // 21 horde
  9501. data << uint32(0xa54) << uint32(0x0); // 22 ally
  9502. data << uint32(0x9e7) << uint32(0x0); // 23 // 2535
  9503. data << uint32(0x9e6) << uint32(0x0); // 24
  9504. data << uint32(0x9e5) << uint32(0x0); // 25
  9505. data << uint32(0xa00) << uint32(0x0); // 26 // 2560
  9506. data << uint32(0x9ff) << uint32(0x1); // 27
  9507. data << uint32(0x9fe) << uint32(0x0); // 28
  9508. data << uint32(0x9fd) << uint32(0x0); // 29
  9509. data << uint32(0x9fc) << uint32(0x1); // 30
  9510. data << uint32(0x9fb) << uint32(0x0); // 31
  9511. data << uint32(0xa62) << uint32(0x0); // 32 // 2658
  9512. data << uint32(0xa61) << uint32(0x1); // 33
  9513. data << uint32(0xa60) << uint32(0x1); // 34
  9514. data << uint32(0xa5f) << uint32(0x0); // 35
  9515. }
  9516. break;
  9517. case 3698: // Nagrand Arena
  9518. if (bg && bg->GetTypeID(true) == BATTLEGROUND_NA)
  9519. bg->FillInitialWorldStates(data);
  9520. else
  9521. {
  9522. data << uint32(0xa0f) << uint32(0x0); // 7
  9523. data << uint32(0xa10) << uint32(0x0); // 8
  9524. data << uint32(0xa11) << uint32(0x0); // 9 show
  9525. }
  9526. break;
  9527. case 3702: // Blade's Edge Arena
  9528. if (bg && bg->GetTypeID(true) == BATTLEGROUND_BE)
  9529. bg->FillInitialWorldStates(data);
  9530. else
  9531. {
  9532. data << uint32(0x9f0) << uint32(0x0); // 7 gold
  9533. data << uint32(0x9f1) << uint32(0x0); // 8 green
  9534. data << uint32(0x9f3) << uint32(0x0); // 9 show
  9535. }
  9536. break;
  9537. case 3968: // Ruins of Lordaeron
  9538. if (bg && bg->GetTypeID(true) == BATTLEGROUND_RL)
  9539. bg->FillInitialWorldStates(data);
  9540. else
  9541. {
  9542. data << uint32(0xbb8) << uint32(0x0); // 7 gold
  9543. data << uint32(0xbb9) << uint32(0x0); // 8 green
  9544. data << uint32(0xbba) << uint32(0x0); // 9 show
  9545. }
  9546. break;
  9547. case 4378: // Dalaran Sewers
  9548. if (bg && bg->GetTypeID(true) == BATTLEGROUND_DS)
  9549. bg->FillInitialWorldStates(data);
  9550. else
  9551. {
  9552. data << uint32(3601) << uint32(0x0); // 7 gold
  9553. data << uint32(3600) << uint32(0x0); // 8 green
  9554. data << uint32(3610) << uint32(0x0); // 9 show
  9555. }
  9556. break;
  9557. case 4384: // Strand of the Ancients
  9558. if (bg && bg->GetTypeID(true) == BATTLEGROUND_SA)
  9559. bg->FillInitialWorldStates(data);
  9560. else
  9561. {
  9562. // 1-3 A defend, 4-6 H defend, 7-9 unk defend, 1 - ok, 2 - half destroyed, 3 - destroyed
  9563. data << uint32(0xf09) << uint32(0x0); // 7 3849 Gate of Temple
  9564. data << uint32(0xe36) << uint32(0x0); // 8 3638 Gate of Yellow Moon
  9565. data << uint32(0xe27) << uint32(0x0); // 9 3623 Gate of Green Emerald
  9566. data << uint32(0xe24) << uint32(0x0); // 10 3620 Gate of Blue Sapphire
  9567. data << uint32(0xe21) << uint32(0x0); // 11 3617 Gate of Red Sun
  9568. data << uint32(0xe1e) << uint32(0x0); // 12 3614 Gate of Purple Ametyst
  9569.  
  9570. data << uint32(0xdf3) << uint32(0x0); // 13 3571 bonus timer (1 - on, 0 - off)
  9571. data << uint32(0xded) << uint32(0x0); // 14 3565 Horde Attacker
  9572. data << uint32(0xdec) << uint32(0x0); // 15 3564 Alliance Attacker
  9573. // End Round (timer), better explain this by example, eg. ends in 19:59 -> A:BC
  9574. data << uint32(0xde9) << uint32(0x0); // 16 3561 C
  9575. data << uint32(0xde8) << uint32(0x0); // 17 3560 B
  9576. data << uint32(0xde7) << uint32(0x0); // 18 3559 A
  9577. data << uint32(0xe35) << uint32(0x0); // 19 3637 East g - Horde control
  9578. data << uint32(0xe34) << uint32(0x0); // 20 3636 West g - Horde control
  9579. data << uint32(0xe33) << uint32(0x0); // 21 3635 South g - Horde control
  9580. data << uint32(0xe32) << uint32(0x0); // 22 3634 East g - Alliance control
  9581. data << uint32(0xe31) << uint32(0x0); // 23 3633 West g - Alliance control
  9582. data << uint32(0xe30) << uint32(0x0); // 24 3632 South g - Alliance control
  9583. data << uint32(0xe2f) << uint32(0x0); // 25 3631 Chamber of Ancients - Horde control
  9584. data << uint32(0xe2e) << uint32(0x0); // 26 3630 Chamber of Ancients - Alliance control
  9585. data << uint32(0xe2d) << uint32(0x0); // 27 3629 Beach1 - Horde control
  9586. data << uint32(0xe2c) << uint32(0x0); // 28 3628 Beach2 - Horde control
  9587. data << uint32(0xe2b) << uint32(0x0); // 29 3627 Beach1 - Alliance control
  9588. data << uint32(0xe2a) << uint32(0x0); // 30 3626 Beach2 - Alliance control
  9589. // and many unks...
  9590. }
  9591. break;
  9592. case 4406: // Ring of Valor
  9593. if (bg && bg->GetTypeID(true) == BATTLEGROUND_RV)
  9594. bg->FillInitialWorldStates(data);
  9595. else
  9596. {
  9597. data << uint32(0xe10) << uint32(0x0); // 7 gold
  9598. data << uint32(0xe11) << uint32(0x0); // 8 green
  9599. data << uint32(0xe1a) << uint32(0x0); // 9 show
  9600. }
  9601. break;
  9602. case 4710:
  9603. if (bg && bg->GetTypeID(true) == BATTLEGROUND_IC)
  9604. bg->FillInitialWorldStates(data);
  9605. else
  9606. {
  9607. data << uint32(4221) << uint32(1); // 7 BG_IC_ALLIANCE_RENFORT_SET
  9608. data << uint32(4222) << uint32(1); // 8 BG_IC_HORDE_RENFORT_SET
  9609. data << uint32(4226) << uint32(300); // 9 BG_IC_ALLIANCE_RENFORT
  9610. data << uint32(4227) << uint32(300); // 10 BG_IC_HORDE_RENFORT
  9611. data << uint32(4322) << uint32(1); // 11 BG_IC_GATE_FRONT_H_WS_OPEN
  9612. data << uint32(4321) << uint32(1); // 12 BG_IC_GATE_WEST_H_WS_OPEN
  9613. data << uint32(4320) << uint32(1); // 13 BG_IC_GATE_EAST_H_WS_OPEN
  9614. data << uint32(4323) << uint32(1); // 14 BG_IC_GATE_FRONT_A_WS_OPEN
  9615. data << uint32(4324) << uint32(1); // 15 BG_IC_GATE_WEST_A_WS_OPEN
  9616. data << uint32(4325) << uint32(1); // 16 BG_IC_GATE_EAST_A_WS_OPEN
  9617. data << uint32(4317) << uint32(1); // 17 unknown
  9618.  
  9619. data << uint32(4301) << uint32(1); // 18 BG_IC_DOCKS_UNCONTROLLED
  9620. data << uint32(4296) << uint32(1); // 19 BG_IC_HANGAR_UNCONTROLLED
  9621. data << uint32(4306) << uint32(1); // 20 BG_IC_QUARRY_UNCONTROLLED
  9622. data << uint32(4311) << uint32(1); // 21 BG_IC_REFINERY_UNCONTROLLED
  9623. data << uint32(4294) << uint32(1); // 22 BG_IC_WORKSHOP_UNCONTROLLED
  9624. data << uint32(4243) << uint32(1); // 23 unknown
  9625. data << uint32(4345) << uint32(1); // 24 unknown
  9626. }
  9627. break;
  9628. // Icecrown Citadel
  9629. case 4812:
  9630. if (instance && mapid == 631)
  9631. instance->FillInitialWorldStates(data);
  9632. else
  9633. {
  9634. data << uint32(4903) << uint32(0); // 9 WORLDSTATE_SHOW_TIMER (Blood Quickening weekly)
  9635. data << uint32(4904) << uint32(30); // 10 WORLDSTATE_EXECUTION_TIME
  9636. data << uint32(4940) << uint32(0); // 11 WORLDSTATE_SHOW_ATTEMPTS
  9637. data << uint32(4941) << uint32(50); // 12 WORLDSTATE_ATTEMPTS_REMAINING
  9638. data << uint32(4942) << uint32(50); // 13 WORLDSTATE_ATTEMPTS_MAX
  9639. }
  9640. break;
  9641. // The Culling of Stratholme
  9642. case 4100:
  9643. if (instance && mapid == 595)
  9644. instance->FillInitialWorldStates(data);
  9645. else
  9646. {
  9647. data << uint32(3479) << uint32(0); // 9 WORLDSTATE_SHOW_CRATES
  9648. data << uint32(3480) << uint32(0); // 10 WORLDSTATE_CRATES_REVEALED
  9649. data << uint32(3504) << uint32(0); // 11 WORLDSTATE_WAVE_COUNT
  9650. data << uint32(3931) << uint32(25); // 12 WORLDSTATE_TIME_GUARDIAN
  9651. data << uint32(3932) << uint32(0); // 13 WORLDSTATE_TIME_GUARDIAN_SHOW
  9652. }
  9653. break;
  9654. // Ulduar
  9655. case 4273:
  9656. if (instance && mapid == 603)
  9657. instance->FillInitialWorldStates(data);
  9658. else
  9659. {
  9660. data << uint32(4132) << uint32(0); // 9 WORLDSTATE_SHOW_CRATES
  9661. data << uint32(4131) << uint32(0); // 10 WORLDSTATE_CRATES_REVEALED
  9662. }
  9663. break;
  9664. default:
  9665. data << uint32(0x914) << uint32(0x0); // 7
  9666. data << uint32(0x913) << uint32(0x0); // 8
  9667. data << uint32(0x912) << uint32(0x0); // 9
  9668. data << uint32(0x915) << uint32(0x0); // 10
  9669. break;
  9670. }
  9671. GetSession()->SendPacket(&data);
  9672. SendBGWeekendWorldStates();
  9673. }
  9674.  
  9675. void Player::SendBGWeekendWorldStates()
  9676. {
  9677. for (uint32 i = 1; i < sBattlemasterListStore.GetNumRows(); ++i)
  9678. {
  9679. BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(i);
  9680. if (bl && bl->HolidayWorldStateId)
  9681. {
  9682. if (BattlegroundMgr::IsBGWeekend((BattlegroundTypeId)bl->id))
  9683. SendUpdateWorldState(bl->HolidayWorldStateId, 1);
  9684. else
  9685. SendUpdateWorldState(bl->HolidayWorldStateId, 0);
  9686. }
  9687. }
  9688. }
  9689.  
  9690. uint32 Player::GetXPRestBonus(uint32 xp)
  9691. {
  9692. uint32 rested_bonus = (uint32)GetRestBonus(); // xp for each rested bonus
  9693.  
  9694. if (rested_bonus > xp) // max rested_bonus == xp or (r+x) = 200% xp
  9695. rested_bonus = xp;
  9696.  
  9697. SetRestBonus(GetRestBonus() - rested_bonus);
  9698.  
  9699. sLog->outInfo(LOG_FILTER_PLAYER, "Player gain %u xp (+ %u Rested Bonus). Rested points=%f", xp+rested_bonus, rested_bonus, GetRestBonus());
  9700. return rested_bonus;
  9701. }
  9702.  
  9703. void Player::SetBindPoint(uint64 guid)
  9704. {
  9705. WorldPacket data(SMSG_BINDER_CONFIRM, 8);
  9706. data << uint64(guid);
  9707. GetSession()->SendPacket(&data);
  9708. }
  9709.  
  9710. void Player::SendTalentWipeConfirm(uint64 guid)
  9711. {
  9712. WorldPacket data(MSG_TALENT_WIPE_CONFIRM, (8+4));
  9713. data << uint64(guid);
  9714. uint32 cost = sWorld->getBoolConfig(CONFIG_NO_RESET_TALENT_COST) ? 0 : resetTalentsCost();
  9715. data << cost;
  9716. GetSession()->SendPacket(&data);
  9717. }
  9718.  
  9719. void Player::ResetPetTalents()
  9720. {
  9721. // This needs another gossip option + NPC text as a confirmation.
  9722. // The confirmation gossip listid has the text: "Yes, please do."
  9723. Pet* pet = GetPet();
  9724.  
  9725. if (!pet || pet->getPetType() != HUNTER_PET || pet->m_usedTalentCount == 0)
  9726. return;
  9727.  
  9728. CharmInfo* charmInfo = pet->GetCharmInfo();
  9729. if (!charmInfo)
  9730. {
  9731. sLog->outError(LOG_FILTER_PLAYER, "Object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId());
  9732. return;
  9733. }
  9734. pet->resetTalents();
  9735. SendTalentsInfoData(true);
  9736. }
  9737.  
  9738. /*********************************************************/
  9739. /*** STORAGE SYSTEM ***/
  9740. /*********************************************************/
  9741.  
  9742. void Player::SetVirtualItemSlot(uint8 i, Item* item)
  9743. {
  9744. ASSERT(i < 3);
  9745. if (i < 2 && item)
  9746. {
  9747. if (!item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT))
  9748. return;
  9749. uint32 charges = item->GetEnchantmentCharges(TEMP_ENCHANTMENT_SLOT);
  9750. if (charges == 0)
  9751. return;
  9752. if (charges > 1)
  9753. item->SetEnchantmentCharges(TEMP_ENCHANTMENT_SLOT, charges-1);
  9754. else if (charges <= 1)
  9755. {
  9756. ApplyEnchantment(item, TEMP_ENCHANTMENT_SLOT, false);
  9757. item->ClearEnchantment(TEMP_ENCHANTMENT_SLOT);
  9758. }
  9759. }
  9760. }
  9761.  
  9762. void Player::SetSheath(SheathState sheathed)
  9763. {
  9764. switch (sheathed)
  9765. {
  9766. case SHEATH_STATE_UNARMED: // no prepared weapon
  9767. SetVirtualItemSlot(0, NULL);
  9768. SetVirtualItemSlot(1, NULL);
  9769. SetVirtualItemSlot(2, NULL);
  9770. break;
  9771. case SHEATH_STATE_MELEE: // prepared melee weapon
  9772. {
  9773. SetVirtualItemSlot(0, GetWeaponForAttack(BASE_ATTACK, true));
  9774. SetVirtualItemSlot(1, GetWeaponForAttack(OFF_ATTACK, true));
  9775. SetVirtualItemSlot(2, NULL);
  9776. }; break;
  9777. case SHEATH_STATE_RANGED: // prepared ranged weapon
  9778. SetVirtualItemSlot(0, NULL);
  9779. SetVirtualItemSlot(1, NULL);
  9780. SetVirtualItemSlot(2, GetWeaponForAttack(RANGED_ATTACK, true));
  9781. break;
  9782. default:
  9783. SetVirtualItemSlot(0, NULL);
  9784. SetVirtualItemSlot(1, NULL);
  9785. SetVirtualItemSlot(2, NULL);
  9786. break;
  9787. }
  9788. Unit::SetSheath(sheathed); // this must visualize Sheath changing for other players...
  9789. }
  9790.  
  9791. uint8 Player::FindEquipSlot(ItemTemplate const* proto, uint32 slot, bool swap) const
  9792. {
  9793. uint8 playerClass = getClass();
  9794.  
  9795. uint8 slots[4];
  9796. slots[0] = NULL_SLOT;
  9797. slots[1] = NULL_SLOT;
  9798. slots[2] = NULL_SLOT;
  9799. slots[3] = NULL_SLOT;
  9800. switch (proto->InventoryType)
  9801. {
  9802. case INVTYPE_HEAD:
  9803. slots[0] = EQUIPMENT_SLOT_HEAD;
  9804. break;
  9805. case INVTYPE_NECK:
  9806. slots[0] = EQUIPMENT_SLOT_NECK;
  9807. break;
  9808. case INVTYPE_SHOULDERS:
  9809. slots[0] = EQUIPMENT_SLOT_SHOULDERS;
  9810. break;
  9811. case INVTYPE_BODY:
  9812. slots[0] = EQUIPMENT_SLOT_BODY;
  9813. break;
  9814. case INVTYPE_CHEST:
  9815. slots[0] = EQUIPMENT_SLOT_CHEST;
  9816. break;
  9817. case INVTYPE_ROBE:
  9818. slots[0] = EQUIPMENT_SLOT_CHEST;
  9819. break;
  9820. case INVTYPE_WAIST:
  9821. slots[0] = EQUIPMENT_SLOT_WAIST;
  9822. break;
  9823. case INVTYPE_LEGS:
  9824. slots[0] = EQUIPMENT_SLOT_LEGS;
  9825. break;
  9826. case INVTYPE_FEET:
  9827. slots[0] = EQUIPMENT_SLOT_FEET;
  9828. break;
  9829. case INVTYPE_WRISTS:
  9830. slots[0] = EQUIPMENT_SLOT_WRISTS;
  9831. break;
  9832. case INVTYPE_HANDS:
  9833. slots[0] = EQUIPMENT_SLOT_HANDS;
  9834. break;
  9835. case INVTYPE_FINGER:
  9836. slots[0] = EQUIPMENT_SLOT_FINGER1;
  9837. slots[1] = EQUIPMENT_SLOT_FINGER2;
  9838. break;
  9839. case INVTYPE_TRINKET:
  9840. slots[0] = EQUIPMENT_SLOT_TRINKET1;
  9841. slots[1] = EQUIPMENT_SLOT_TRINKET2;
  9842. break;
  9843. case INVTYPE_CLOAK:
  9844. slots[0] = EQUIPMENT_SLOT_BACK;
  9845. break;
  9846. case INVTYPE_WEAPON:
  9847. {
  9848. slots[0] = EQUIPMENT_SLOT_MAINHAND;
  9849.  
  9850. // suggest offhand slot only if know dual wielding
  9851. // (this will be replace mainhand weapon at auto equip instead unwonted "you don't known dual wielding" ...
  9852. if (CanDualWield())
  9853. slots[1] = EQUIPMENT_SLOT_OFFHAND;
  9854. break;
  9855. }
  9856. case INVTYPE_SHIELD:
  9857. slots[0] = EQUIPMENT_SLOT_OFFHAND;
  9858. break;
  9859. case INVTYPE_RANGED:
  9860. slots[0] = EQUIPMENT_SLOT_RANGED;
  9861. break;
  9862. case INVTYPE_2HWEAPON:
  9863. slots[0] = EQUIPMENT_SLOT_MAINHAND;
  9864. if (Item* mhWeapon = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND))
  9865. {
  9866. if (ItemTemplate const* mhWeaponProto = mhWeapon->GetTemplate())
  9867. {
  9868. if (mhWeaponProto->SubClass == ITEM_SUBCLASS_WEAPON_POLEARM || mhWeaponProto->SubClass == ITEM_SUBCLASS_WEAPON_STAFF)
  9869. {
  9870. const_cast<Player*>(this)->AutoUnequipOffhandIfNeed(true);
  9871. break;
  9872. }
  9873. }
  9874. }
  9875.  
  9876. if (GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND))
  9877. {
  9878. if (proto->SubClass == ITEM_SUBCLASS_WEAPON_POLEARM || proto->SubClass == ITEM_SUBCLASS_WEAPON_STAFF)
  9879. {
  9880. const_cast<Player*>(this)->AutoUnequipOffhandIfNeed(true);
  9881. break;
  9882. }
  9883. }
  9884. if (CanDualWield() && CanTitanGrip() && proto->SubClass != ITEM_SUBCLASS_WEAPON_POLEARM && proto->SubClass != ITEM_SUBCLASS_WEAPON_STAFF)
  9885. slots[1] = EQUIPMENT_SLOT_OFFHAND;
  9886. break;
  9887. case INVTYPE_TABARD:
  9888. slots[0] = EQUIPMENT_SLOT_TABARD;
  9889. break;
  9890. case INVTYPE_WEAPONMAINHAND:
  9891. slots[0] = EQUIPMENT_SLOT_MAINHAND;
  9892. break;
  9893. case INVTYPE_WEAPONOFFHAND:
  9894. slots[0] = EQUIPMENT_SLOT_OFFHAND;
  9895. break;
  9896. case INVTYPE_HOLDABLE:
  9897. slots[0] = EQUIPMENT_SLOT_OFFHAND;
  9898. break;
  9899. case INVTYPE_THROWN:
  9900. slots[0] = EQUIPMENT_SLOT_RANGED;
  9901. break;
  9902. case INVTYPE_RANGEDRIGHT:
  9903. slots[0] = EQUIPMENT_SLOT_RANGED;
  9904. break;
  9905. case INVTYPE_BAG:
  9906. slots[0] = INVENTORY_SLOT_BAG_START + 0;
  9907. slots[1] = INVENTORY_SLOT_BAG_START + 1;
  9908. slots[2] = INVENTORY_SLOT_BAG_START + 2;
  9909. slots[3] = INVENTORY_SLOT_BAG_START + 3;
  9910. break;
  9911. case INVTYPE_RELIC:
  9912. {
  9913. switch (proto->SubClass)
  9914. {
  9915. case ITEM_SUBCLASS_ARMOR_LIBRAM:
  9916. if (playerClass == CLASS_PALADIN)
  9917. slots[0] = EQUIPMENT_SLOT_RANGED;
  9918. break;
  9919. case ITEM_SUBCLASS_ARMOR_IDOL:
  9920. if (playerClass == CLASS_DRUID)
  9921. slots[0] = EQUIPMENT_SLOT_RANGED;
  9922. break;
  9923. case ITEM_SUBCLASS_ARMOR_TOTEM:
  9924. if (playerClass == CLASS_SHAMAN)
  9925. slots[0] = EQUIPMENT_SLOT_RANGED;
  9926. break;
  9927. case ITEM_SUBCLASS_ARMOR_MISC:
  9928. if (playerClass == CLASS_WARLOCK)
  9929. slots[0] = EQUIPMENT_SLOT_RANGED;
  9930. break;
  9931. case ITEM_SUBCLASS_ARMOR_SIGIL:
  9932. if (playerClass == CLASS_DEATH_KNIGHT)
  9933. slots[0] = EQUIPMENT_SLOT_RANGED;
  9934. break;
  9935. }
  9936. break;
  9937. }
  9938. default:
  9939. return NULL_SLOT;
  9940. }
  9941.  
  9942. if (slot != NULL_SLOT)
  9943. {
  9944. if (swap || !GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
  9945. for (uint8 i = 0; i < 4; ++i)
  9946. if (slots[i] == slot)
  9947. return slot;
  9948. }
  9949. else
  9950. {
  9951. // search free slot at first
  9952. for (uint8 i = 0; i < 4; ++i)
  9953. if (slots[i] != NULL_SLOT && !GetItemByPos(INVENTORY_SLOT_BAG_0, slots[i]))
  9954. // in case 2hand equipped weapon (without titan grip) offhand slot empty but not free
  9955. if (slots[i] != EQUIPMENT_SLOT_OFFHAND || !IsTwoHandUsed())
  9956. return slots[i];
  9957.  
  9958. // if not found free and can swap return first appropriate from used
  9959. for (uint8 i = 0; i < 4; ++i)
  9960. if (slots[i] != NULL_SLOT && swap)
  9961. return slots[i];
  9962. }
  9963.  
  9964. // no free position
  9965. return NULL_SLOT;
  9966. }
  9967.  
  9968. InventoryResult Player::CanUnequipItems(uint32 item, uint32 count) const
  9969. {
  9970. uint32 tempcount = 0;
  9971.  
  9972. InventoryResult res = EQUIP_ERR_OK;
  9973.  
  9974. for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; ++i)
  9975. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  9976. if (pItem->GetEntry() == item)
  9977. {
  9978. InventoryResult ires = CanUnequipItem(INVENTORY_SLOT_BAG_0 << 8 | i, false);
  9979. if (ires == EQUIP_ERR_OK)
  9980. {
  9981. tempcount += pItem->GetCount();
  9982. if (tempcount >= count)
  9983. return EQUIP_ERR_OK;
  9984. }
  9985. else
  9986. res = ires;
  9987. }
  9988.  
  9989. for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i)
  9990. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  9991. if (pItem->GetEntry() == item)
  9992. {
  9993. tempcount += pItem->GetCount();
  9994. if (tempcount >= count)
  9995. return EQUIP_ERR_OK;
  9996. }
  9997.  
  9998. for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i)
  9999. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  10000. if (pItem->GetEntry() == item)
  10001. {
  10002. tempcount += pItem->GetCount();
  10003. if (tempcount >= count)
  10004. return EQUIP_ERR_OK;
  10005. }
  10006.  
  10007. for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
  10008. if (Bag* pBag = GetBagByPos(i))
  10009. for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
  10010. if (Item* pItem = GetItemByPos(i, j))
  10011. if (pItem->GetEntry() == item)
  10012. {
  10013. tempcount += pItem->GetCount();
  10014. if (tempcount >= count)
  10015. return EQUIP_ERR_OK;
  10016. }
  10017.  
  10018. // not found req. item count and have unequippable items
  10019. return res;
  10020. }
  10021.  
  10022. uint32 Player::GetItemCount(uint32 item, bool inBankAlso, Item* skipItem) const
  10023. {
  10024. uint32 count = 0;
  10025. for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++)
  10026. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  10027. if (pItem != skipItem && pItem->GetEntry() == item)
  10028. count += pItem->GetCount();
  10029.  
  10030. for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i)
  10031. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  10032. if (pItem != skipItem && pItem->GetEntry() == item)
  10033. count += pItem->GetCount();
  10034.  
  10035. for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
  10036. if (Bag* pBag = GetBagByPos(i))
  10037. count += pBag->GetItemCount(item, skipItem);
  10038.  
  10039. if (skipItem && skipItem->GetTemplate()->GemProperties)
  10040. for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
  10041. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  10042. if (pItem != skipItem && pItem->GetTemplate()->Socket[0].Color)
  10043. count += pItem->GetGemCountWithID(item);
  10044.  
  10045. if (inBankAlso)
  10046. {
  10047. // checking every item from 39 to 74 (including bank bags)
  10048. for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i)
  10049. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  10050. if (pItem != skipItem && pItem->GetEntry() == item)
  10051. count += pItem->GetCount();
  10052.  
  10053. for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
  10054. if (Bag* pBag = GetBagByPos(i))
  10055. count += pBag->GetItemCount(item, skipItem);
  10056.  
  10057. if (skipItem && skipItem->GetTemplate()->GemProperties)
  10058. for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; ++i)
  10059. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  10060. if (pItem != skipItem && pItem->GetTemplate()->Socket[0].Color)
  10061. count += pItem->GetGemCountWithID(item);
  10062. }
  10063.  
  10064. return count;
  10065. }
  10066.  
  10067. uint32 Player::GetItemCountWithLimitCategory(uint32 limitCategory, Item* skipItem) const
  10068. {
  10069. uint32 count = 0;
  10070. for (int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
  10071. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  10072. if (pItem != skipItem)
  10073. if (ItemTemplate const* pProto = pItem->GetTemplate())
  10074. if (pProto->ItemLimitCategory == limitCategory)
  10075. count += pItem->GetCount();
  10076.  
  10077. for (int i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i)
  10078. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  10079. if (pItem != skipItem)
  10080. if (ItemTemplate const* pProto = pItem->GetTemplate())
  10081. if (pProto->ItemLimitCategory == limitCategory)
  10082. count += pItem->GetCount();
  10083.  
  10084. for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
  10085. if (Bag* pBag = GetBagByPos(i))
  10086. count += pBag->GetItemCountWithLimitCategory(limitCategory, skipItem);
  10087.  
  10088. for (int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i)
  10089. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  10090. if (pItem != skipItem)
  10091. if (ItemTemplate const* pProto = pItem->GetTemplate())
  10092. if (pProto->ItemLimitCategory == limitCategory)
  10093. count += pItem->GetCount();
  10094.  
  10095. for (int i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
  10096. if (Bag* pBag = GetBagByPos(i))
  10097. count += pBag->GetItemCountWithLimitCategory(limitCategory, skipItem);
  10098.  
  10099. return count;
  10100. }
  10101.  
  10102. Item* Player::GetItemByGuid(uint64 guid) const
  10103. {
  10104. for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
  10105. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  10106. if (pItem->GetGUID() == guid)
  10107. return pItem;
  10108.  
  10109. for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i)
  10110. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  10111. if (pItem->GetGUID() == guid)
  10112. return pItem;
  10113.  
  10114. for (int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i)
  10115. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  10116. if (pItem->GetGUID() == guid)
  10117. return pItem;
  10118.  
  10119. for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
  10120. if (Bag* pBag = GetBagByPos(i))
  10121. for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
  10122. if (Item* pItem = pBag->GetItemByPos(j))
  10123. if (pItem->GetGUID() == guid)
  10124. return pItem;
  10125.  
  10126. for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
  10127. if (Bag* pBag = GetBagByPos(i))
  10128. for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
  10129. if (Item* pItem = pBag->GetItemByPos(j))
  10130. if (pItem->GetGUID() == guid)
  10131. return pItem;
  10132.  
  10133. return NULL;
  10134. }
  10135.  
  10136. Item* Player::GetItemByPos(uint16 pos) const
  10137. {
  10138. uint8 bag = pos >> 8;
  10139. uint8 slot = pos & 255;
  10140. return GetItemByPos(bag, slot);
  10141. }
  10142.  
  10143. Item* Player::GetItemByPos(uint8 bag, uint8 slot) const
  10144. {
  10145. if (bag == INVENTORY_SLOT_BAG_0 && (slot < BANK_SLOT_BAG_END || (slot >= KEYRING_SLOT_START && slot < CURRENCYTOKEN_SLOT_END)))
  10146. return m_items[slot];
  10147. else if (Bag* pBag = GetBagByPos(bag))
  10148. return pBag->GetItemByPos(slot);
  10149. return NULL;
  10150. }
  10151.  
  10152. Bag* Player::GetBagByPos(uint8 bag) const
  10153. {
  10154. if ((bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END)
  10155. || (bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END))
  10156. if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, bag))
  10157. return item->ToBag();
  10158. return NULL;
  10159. }
  10160.  
  10161. Item* Player::GetWeaponForAttack(WeaponAttackType attackType, bool useable /*= false*/) const
  10162. {
  10163. uint8 slot;
  10164. switch (attackType)
  10165. {
  10166. case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
  10167. case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
  10168. case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break;
  10169. default: return NULL;
  10170. }
  10171.  
  10172. Item* item = NULL;
  10173. if (useable)
  10174. item = GetUseableItemByPos(INVENTORY_SLOT_BAG_0, slot);
  10175. else
  10176. item = GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
  10177. if (!item || item->GetTemplate()->Class != ITEM_CLASS_WEAPON)
  10178. return NULL;
  10179.  
  10180. if (!useable)
  10181. return item;
  10182.  
  10183. if (item->IsBroken() || IsInFeralForm())
  10184. return NULL;
  10185.  
  10186. return item;
  10187. }
  10188.  
  10189. Item* Player::GetShield(bool useable) const
  10190. {
  10191. Item* item = NULL;
  10192. if (useable)
  10193. item = GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
  10194. else
  10195. item = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
  10196. if (!item || item->GetTemplate()->Class != ITEM_CLASS_ARMOR)
  10197. return NULL;
  10198.  
  10199. if (!useable)
  10200. return item;
  10201.  
  10202. if (item->IsBroken())
  10203. return NULL;
  10204.  
  10205. return item;
  10206. }
  10207.  
  10208. uint8 Player::GetAttackBySlot(uint8 slot)
  10209. {
  10210. switch (slot)
  10211. {
  10212. case EQUIPMENT_SLOT_MAINHAND: return BASE_ATTACK;
  10213. case EQUIPMENT_SLOT_OFFHAND: return OFF_ATTACK;
  10214. case EQUIPMENT_SLOT_RANGED: return RANGED_ATTACK;
  10215. default: return MAX_ATTACK;
  10216. }
  10217. }
  10218.  
  10219. bool Player::IsInventoryPos(uint8 bag, uint8 slot)
  10220. {
  10221. if (bag == INVENTORY_SLOT_BAG_0 && slot == NULL_SLOT)
  10222. return true;
  10223. if (bag == INVENTORY_SLOT_BAG_0 && (slot >= INVENTORY_SLOT_ITEM_START && slot < INVENTORY_SLOT_ITEM_END))
  10224. return true;
  10225. if (bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END)
  10226. return true;
  10227. if (bag == INVENTORY_SLOT_BAG_0 && (slot >= KEYRING_SLOT_START && slot < CURRENCYTOKEN_SLOT_END))
  10228. return true;
  10229. return false;
  10230. }
  10231.  
  10232. bool Player::IsEquipmentPos(uint8 bag, uint8 slot)
  10233. {
  10234. if (bag == INVENTORY_SLOT_BAG_0 && (slot < EQUIPMENT_SLOT_END))
  10235. return true;
  10236. if (bag == INVENTORY_SLOT_BAG_0 && (slot >= INVENTORY_SLOT_BAG_START && slot < INVENTORY_SLOT_BAG_END))
  10237. return true;
  10238. return false;
  10239. }
  10240.  
  10241. bool Player::IsBankPos(uint8 bag, uint8 slot)
  10242. {
  10243. if (bag == INVENTORY_SLOT_BAG_0 && (slot >= BANK_SLOT_ITEM_START && slot < BANK_SLOT_ITEM_END))
  10244. return true;
  10245. if (bag == INVENTORY_SLOT_BAG_0 && (slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END))
  10246. return true;
  10247. if (bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END)
  10248. return true;
  10249. return false;
  10250. }
  10251.  
  10252. bool Player::IsBagPos(uint16 pos)
  10253. {
  10254. uint8 bag = pos >> 8;
  10255. uint8 slot = pos & 255;
  10256. if (bag == INVENTORY_SLOT_BAG_0 && (slot >= INVENTORY_SLOT_BAG_START && slot < INVENTORY_SLOT_BAG_END))
  10257. return true;
  10258. if (bag == INVENTORY_SLOT_BAG_0 && (slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END))
  10259. return true;
  10260. return false;
  10261. }
  10262.  
  10263. bool Player::IsValidPos(uint8 bag, uint8 slot, bool explicit_pos)
  10264. {
  10265. // post selected
  10266. if (bag == NULL_BAG && !explicit_pos)
  10267. return true;
  10268.  
  10269. if (bag == INVENTORY_SLOT_BAG_0)
  10270. {
  10271. // any post selected
  10272. if (slot == NULL_SLOT && !explicit_pos)
  10273. return true;
  10274.  
  10275. // equipment
  10276. if (slot < EQUIPMENT_SLOT_END)
  10277. return true;
  10278.  
  10279. // bag equip slots
  10280. if (slot >= INVENTORY_SLOT_BAG_START && slot < INVENTORY_SLOT_BAG_END)
  10281. return true;
  10282.  
  10283. // backpack slots
  10284. if (slot >= INVENTORY_SLOT_ITEM_START && slot < INVENTORY_SLOT_ITEM_END)
  10285. return true;
  10286.  
  10287. // keyring slots
  10288. if (slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_END)
  10289. return true;
  10290.  
  10291. // bank main slots
  10292. if (slot >= BANK_SLOT_ITEM_START && slot < BANK_SLOT_ITEM_END)
  10293. return true;
  10294.  
  10295. // bank bag slots
  10296. if (slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END)
  10297. return true;
  10298.  
  10299. return false;
  10300. }
  10301.  
  10302. // bag content slots
  10303. // bank bag content slots
  10304. if (Bag* pBag = GetBagByPos(bag))
  10305. {
  10306. // any post selected
  10307. if (slot == NULL_SLOT && !explicit_pos)
  10308. return true;
  10309.  
  10310. return slot < pBag->GetBagSize();
  10311. }
  10312.  
  10313. // where this?
  10314. return false;
  10315. }
  10316.  
  10317. bool Player::HasItemCount(uint32 item, uint32 count, bool inBankAlso) const
  10318. {
  10319. uint32 tempcount = 0;
  10320. for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++)
  10321. {
  10322. Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
  10323. if (pItem && pItem->GetEntry() == item && !pItem->IsInTrade())
  10324. {
  10325. tempcount += pItem->GetCount();
  10326. if (tempcount >= count)
  10327. return true;
  10328. }
  10329. }
  10330. for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i)
  10331. {
  10332. Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
  10333. if (pItem && pItem->GetEntry() == item && !pItem->IsInTrade())
  10334. {
  10335. tempcount += pItem->GetCount();
  10336. if (tempcount >= count)
  10337. return true;
  10338. }
  10339. }
  10340. for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
  10341. {
  10342. if (Bag* pBag = GetBagByPos(i))
  10343. {
  10344. for (uint32 j = 0; j < pBag->GetBagSize(); j++)
  10345. {
  10346. Item* pItem = GetItemByPos(i, j);
  10347. if (pItem && pItem->GetEntry() == item && !pItem->IsInTrade())
  10348. {
  10349. tempcount += pItem->GetCount();
  10350. if (tempcount >= count)
  10351. return true;
  10352. }
  10353. }
  10354. }
  10355. }
  10356.  
  10357. if (inBankAlso)
  10358. {
  10359. for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++)
  10360. {
  10361. Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
  10362. if (pItem && pItem->GetEntry() == item && !pItem->IsInTrade())
  10363. {
  10364. tempcount += pItem->GetCount();
  10365. if (tempcount >= count)
  10366. return true;
  10367. }
  10368. }
  10369. for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
  10370. {
  10371. if (Bag* pBag = GetBagByPos(i))
  10372. {
  10373. for (uint32 j = 0; j < pBag->GetBagSize(); j++)
  10374. {
  10375. Item* pItem = GetItemByPos(i, j);
  10376. if (pItem && pItem->GetEntry() == item && !pItem->IsInTrade())
  10377. {
  10378. tempcount += pItem->GetCount();
  10379. if (tempcount >= count)
  10380. return true;
  10381. }
  10382. }
  10383. }
  10384. }
  10385. }
  10386.  
  10387. return false;
  10388. }
  10389.  
  10390. bool Player::HasItemOrGemWithIdEquipped(uint32 item, uint32 count, uint8 except_slot) const
  10391. {
  10392. uint32 tempcount = 0;
  10393. for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)
  10394. {
  10395. if (i == except_slot)
  10396. continue;
  10397.  
  10398. Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
  10399. if (pItem && pItem->GetEntry() == item)
  10400. {
  10401. tempcount += pItem->GetCount();
  10402. if (tempcount >= count)
  10403. return true;
  10404. }
  10405. }
  10406.  
  10407. ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item);
  10408. if (pProto && pProto->GemProperties)
  10409. {
  10410. for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)
  10411. {
  10412. if (i == except_slot)
  10413. continue;
  10414.  
  10415. Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
  10416. if (pItem && pItem->GetTemplate()->Socket[0].Color)
  10417. {
  10418. tempcount += pItem->GetGemCountWithID(item);
  10419. if (tempcount >= count)
  10420. return true;
  10421. }
  10422. }
  10423. }
  10424.  
  10425. return false;
  10426. }
  10427.  
  10428. bool Player::HasItemOrGemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count, uint8 except_slot) const
  10429. {
  10430. uint32 tempcount = 0;
  10431. for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)
  10432. {
  10433. if (i == except_slot)
  10434. continue;
  10435.  
  10436. Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
  10437. if (!pItem)
  10438. continue;
  10439.  
  10440. ItemTemplate const* pProto = pItem->GetTemplate();
  10441. if (!pProto)
  10442. continue;
  10443.  
  10444. if (pProto->ItemLimitCategory == limitCategory)
  10445. {
  10446. tempcount += pItem->GetCount();
  10447. if (tempcount >= count)
  10448. return true;
  10449. }
  10450.  
  10451. if (pProto->Socket[0].Color || pItem->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT))
  10452. {
  10453. tempcount += pItem->GetGemCountWithLimitCategory(limitCategory);
  10454. if (tempcount >= count)
  10455. return true;
  10456. }
  10457. }
  10458.  
  10459. return false;
  10460. }
  10461.  
  10462. InventoryResult Player::CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count) const
  10463. {
  10464. ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(entry);
  10465. if (!pProto)
  10466. {
  10467. if (no_space_count)
  10468. *no_space_count = count;
  10469. return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
  10470. }
  10471.  
  10472. if (pItem && pItem->m_lootGenerated)
  10473. return EQUIP_ERR_ALREADY_LOOTED;
  10474.  
  10475. // no maximum
  10476. if ((pProto->MaxCount <= 0 && pProto->ItemLimitCategory == 0) || pProto->MaxCount == 2147483647)
  10477. return EQUIP_ERR_OK;
  10478.  
  10479. if (pProto->MaxCount > 0)
  10480. {
  10481. uint32 curcount = GetItemCount(pProto->ItemId, true, pItem);
  10482. if (curcount + count > uint32(pProto->MaxCount))
  10483. {
  10484. if (no_space_count)
  10485. *no_space_count = count + curcount - pProto->MaxCount;
  10486. return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
  10487. }
  10488. }
  10489.  
  10490. // check unique-equipped limit
  10491. if (pProto->ItemLimitCategory)
  10492. {
  10493. ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(pProto->ItemLimitCategory);
  10494. if (!limitEntry)
  10495. {
  10496. if (no_space_count)
  10497. *no_space_count = count;
  10498. return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
  10499. }
  10500.  
  10501. if (limitEntry->mode == ITEM_LIMIT_CATEGORY_MODE_HAVE)
  10502. {
  10503. uint32 curcount = GetItemCountWithLimitCategory(pProto->ItemLimitCategory, pItem);
  10504. if (curcount + count > uint32(limitEntry->maxCount))
  10505. {
  10506. if (no_space_count)
  10507. *no_space_count = count + curcount - limitEntry->maxCount;
  10508. return EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_COUNT_EXCEEDED;
  10509. }
  10510. }
  10511. }
  10512.  
  10513. return EQUIP_ERR_OK;
  10514. }
  10515.  
  10516. bool Player::HasItemTotemCategory(uint32 TotemCategory) const
  10517. {
  10518. Item* pItem;
  10519. for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
  10520. {
  10521. pItem = GetUseableItemByPos(INVENTORY_SLOT_BAG_0, i);
  10522. if (pItem && IsTotemCategoryCompatiableWith(pItem->GetTemplate()->TotemCategory, TotemCategory))
  10523. return true;
  10524. }
  10525. for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i)
  10526. {
  10527. pItem = GetUseableItemByPos(INVENTORY_SLOT_BAG_0, i);
  10528. if (pItem && IsTotemCategoryCompatiableWith(pItem->GetTemplate()->TotemCategory, TotemCategory))
  10529. return true;
  10530. }
  10531. for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
  10532. {
  10533. if (Bag* pBag = GetBagByPos(i))
  10534. {
  10535. for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
  10536. {
  10537. pItem = GetUseableItemByPos(i, j);
  10538. if (pItem && IsTotemCategoryCompatiableWith(pItem->GetTemplate()->TotemCategory, TotemCategory))
  10539. return true;
  10540. }
  10541. }
  10542. }
  10543. return false;
  10544. }
  10545.  
  10546. InventoryResult Player::CanStoreItem_InSpecificSlot(uint8 bag, uint8 slot, ItemPosCountVec &dest, ItemTemplate const* pProto, uint32& count, bool swap, Item* pSrcItem) const
  10547. {
  10548. Item* pItem2 = GetItemByPos(bag, slot);
  10549.  
  10550. // ignore move item (this slot will be empty at move)
  10551. if (pItem2 == pSrcItem)
  10552. pItem2 = NULL;
  10553.  
  10554. uint32 need_space;
  10555.  
  10556. if (pSrcItem && pSrcItem->IsNotEmptyBag() && !IsBagPos(uint16(bag) << 8 | slot))
  10557. return EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS;
  10558.  
  10559. // empty specific slot - check item fit to slot
  10560. if (!pItem2 || swap)
  10561. {
  10562. if (bag == INVENTORY_SLOT_BAG_0)
  10563. {
  10564. // keyring case
  10565. if (slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_START+GetMaxKeyringSize() && !(pProto->BagFamily & BAG_FAMILY_MASK_KEYS))
  10566. return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
  10567.  
  10568. // currencytoken case
  10569. if (slot >= CURRENCYTOKEN_SLOT_START && slot < CURRENCYTOKEN_SLOT_END && !(pProto->IsCurrencyToken()))
  10570. return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
  10571.  
  10572. // prevent cheating
  10573. if ((slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END) || slot >= PLAYER_SLOT_END)
  10574. return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
  10575. }
  10576. else
  10577. {
  10578. Bag* pBag = GetBagByPos(bag);
  10579. if (!pBag)
  10580. return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
  10581.  
  10582. ItemTemplate const* pBagProto = pBag->GetTemplate();
  10583. if (!pBagProto)
  10584. return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
  10585.  
  10586. if (slot >= pBagProto->ContainerSlots)
  10587. return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
  10588.  
  10589. if (!ItemCanGoIntoBag(pProto, pBagProto))
  10590. return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
  10591. }
  10592.  
  10593. // non empty stack with space
  10594. need_space = pProto->GetMaxStackSize();
  10595. }
  10596. // non empty slot, check item type
  10597. else
  10598. {
  10599. // can be merged at least partly
  10600. InventoryResult res = pItem2->CanBeMergedPartlyWith(pProto);
  10601. if (res != EQUIP_ERR_OK)
  10602. return res;
  10603.  
  10604. // free stack space or infinity
  10605. need_space = pProto->GetMaxStackSize() - pItem2->GetCount();
  10606. }
  10607.  
  10608. if (need_space > count)
  10609. need_space = count;
  10610.  
  10611. ItemPosCount newPosition = ItemPosCount((bag << 8) | slot, need_space);
  10612. if (!newPosition.isContainedIn(dest))
  10613. {
  10614. dest.push_back(newPosition);
  10615. count -= need_space;
  10616. }
  10617. return EQUIP_ERR_OK;
  10618. }
  10619.  
  10620. InventoryResult Player::CanStoreItem_InBag(uint8 bag, ItemPosCountVec &dest, ItemTemplate const* pProto, uint32& count, bool merge, bool non_specialized, Item* pSrcItem, uint8 skip_bag, uint8 skip_slot) const
  10621. {
  10622. // skip specific bag already processed in first called CanStoreItem_InBag
  10623. if (bag == skip_bag)
  10624. return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
  10625.  
  10626. // skip not existed bag or self targeted bag
  10627. Bag* pBag = GetBagByPos(bag);
  10628. if (!pBag || pBag == pSrcItem)
  10629. return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
  10630.  
  10631. if (pSrcItem && pSrcItem->IsNotEmptyBag())
  10632. return EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS;
  10633.  
  10634. ItemTemplate const* pBagProto = pBag->GetTemplate();
  10635. if (!pBagProto)
  10636. return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
  10637.  
  10638. // specialized bag mode or non-specilized
  10639. if (non_specialized != (pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass == ITEM_SUBCLASS_CONTAINER))
  10640. return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
  10641.  
  10642. if (!ItemCanGoIntoBag(pProto, pBagProto))
  10643. return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
  10644.  
  10645. for (uint32 j = 0; j < pBag->GetBagSize(); j++)
  10646. {
  10647. // skip specific slot already processed in first called CanStoreItem_InSpecificSlot
  10648. if (j == skip_slot)
  10649. continue;
  10650.  
  10651. Item* pItem2 = GetItemByPos(bag, j);
  10652.  
  10653. // ignore move item (this slot will be empty at move)
  10654. if (pItem2 == pSrcItem)
  10655. pItem2 = NULL;
  10656.  
  10657. // if merge skip empty, if !merge skip non-empty
  10658. if ((pItem2 != NULL) != merge)
  10659. continue;
  10660.  
  10661. uint32 need_space = pProto->GetMaxStackSize();
  10662.  
  10663. if (pItem2)
  10664. {
  10665. // can be merged at least partly
  10666. uint8 res = pItem2->CanBeMergedPartlyWith(pProto);
  10667. if (res != EQUIP_ERR_OK)
  10668. continue;
  10669.  
  10670. // descrease at current stacksize
  10671. need_space -= pItem2->GetCount();
  10672. }
  10673.  
  10674. if (need_space > count)
  10675. need_space = count;
  10676.  
  10677. ItemPosCount newPosition = ItemPosCount((bag << 8) | j, need_space);
  10678. if (!newPosition.isContainedIn(dest))
  10679. {
  10680. dest.push_back(newPosition);
  10681. count -= need_space;
  10682.  
  10683. if (count==0)
  10684. return EQUIP_ERR_OK;
  10685. }
  10686. }
  10687. return EQUIP_ERR_OK;
  10688. }
  10689.  
  10690. InventoryResult Player::CanStoreItem_InInventorySlots(uint8 slot_begin, uint8 slot_end, ItemPosCountVec &dest, ItemTemplate const* pProto, uint32& count, bool merge, Item* pSrcItem, uint8 skip_bag, uint8 skip_slot) const
  10691. {
  10692. //this is never called for non-bag slots so we can do this
  10693. if (pSrcItem && pSrcItem->IsNotEmptyBag())
  10694. return EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS;
  10695.  
  10696. for (uint32 j = slot_begin; j < slot_end; j++)
  10697. {
  10698. // skip specific slot already processed in first called CanStoreItem_InSpecificSlot
  10699. if (INVENTORY_SLOT_BAG_0 == skip_bag && j == skip_slot)
  10700. continue;
  10701.  
  10702. Item* pItem2 = GetItemByPos(INVENTORY_SLOT_BAG_0, j);
  10703.  
  10704. // ignore move item (this slot will be empty at move)
  10705. if (pItem2 == pSrcItem)
  10706. pItem2 = NULL;
  10707.  
  10708. // if merge skip empty, if !merge skip non-empty
  10709. if ((pItem2 != NULL) != merge)
  10710. continue;
  10711.  
  10712. uint32 need_space = pProto->GetMaxStackSize();
  10713.  
  10714. if (pItem2)
  10715. {
  10716. // can be merged at least partly
  10717. uint8 res = pItem2->CanBeMergedPartlyWith(pProto);
  10718. if (res != EQUIP_ERR_OK)
  10719. continue;
  10720.  
  10721. // descrease at current stacksize
  10722. need_space -= pItem2->GetCount();
  10723. }
  10724.  
  10725. if (need_space > count)
  10726. need_space = count;
  10727.  
  10728. ItemPosCount newPosition = ItemPosCount((INVENTORY_SLOT_BAG_0 << 8) | j, need_space);
  10729. if (!newPosition.isContainedIn(dest))
  10730. {
  10731. dest.push_back(newPosition);
  10732. count -= need_space;
  10733.  
  10734. if (count==0)
  10735. return EQUIP_ERR_OK;
  10736. }
  10737. }
  10738. return EQUIP_ERR_OK;
  10739. }
  10740.  
  10741. InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, uint32 entry, uint32 count, Item* pItem, bool swap, uint32* no_space_count) const
  10742. {
  10743. sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "STORAGE: CanStoreItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, entry, count);
  10744.  
  10745. ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(entry);
  10746. if (!pProto)
  10747. {
  10748. if (no_space_count)
  10749. *no_space_count = count;
  10750. return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED :EQUIP_ERR_ITEM_NOT_FOUND;
  10751. }
  10752.  
  10753. if (pItem)
  10754. {
  10755. // item used
  10756. if (pItem->m_lootGenerated)
  10757. {
  10758. if (no_space_count)
  10759. *no_space_count = count;
  10760. return EQUIP_ERR_ALREADY_LOOTED;
  10761. }
  10762.  
  10763. if (pItem->IsBindedNotWith(this))
  10764. {
  10765. if (no_space_count)
  10766. *no_space_count = count;
  10767. return EQUIP_ERR_DONT_OWN_THAT_ITEM;
  10768. }
  10769. }
  10770.  
  10771. // check count of items (skip for auto move for same player from bank)
  10772. uint32 no_similar_count = 0; // can't store this amount similar items
  10773. InventoryResult res = CanTakeMoreSimilarItems(entry, count, pItem, &no_similar_count);
  10774. if (res != EQUIP_ERR_OK)
  10775. {
  10776. if (count == no_similar_count)
  10777. {
  10778. if (no_space_count)
  10779. *no_space_count = no_similar_count;
  10780. return res;
  10781. }
  10782. count -= no_similar_count;
  10783. }
  10784.  
  10785. // in specific slot
  10786. if (bag != NULL_BAG && slot != NULL_SLOT)
  10787. {
  10788. res = CanStoreItem_InSpecificSlot(bag, slot, dest, pProto, count, swap, pItem);
  10789. if (res != EQUIP_ERR_OK)
  10790. {
  10791. if (no_space_count)
  10792. *no_space_count = count + no_similar_count;
  10793. return res;
  10794. }
  10795.  
  10796. if (count == 0)
  10797. {
  10798. if (no_similar_count == 0)
  10799. return EQUIP_ERR_OK;
  10800.  
  10801. if (no_space_count)
  10802. *no_space_count = count + no_similar_count;
  10803. return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
  10804. }
  10805. }
  10806.  
  10807. // not specific slot or have space for partly store only in specific slot
  10808.  
  10809. // in specific bag
  10810. if (bag != NULL_BAG)
  10811. {
  10812. // search stack in bag for merge to
  10813. if (pProto->Stackable != 1)
  10814. {
  10815. if (bag == INVENTORY_SLOT_BAG_0) // inventory
  10816. {
  10817. res = CanStoreItem_InInventorySlots(KEYRING_SLOT_START, CURRENCYTOKEN_SLOT_END, dest, pProto, count, true, pItem, bag, slot);
  10818. if (res != EQUIP_ERR_OK)
  10819. {
  10820. if (no_space_count)
  10821. *no_space_count = count + no_similar_count;
  10822. return res;
  10823. }
  10824.  
  10825. if (count == 0)
  10826. {
  10827. if (no_similar_count == 0)
  10828. return EQUIP_ERR_OK;
  10829.  
  10830. if (no_space_count)
  10831. *no_space_count = count + no_similar_count;
  10832. return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
  10833. }
  10834.  
  10835. res = CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START, INVENTORY_SLOT_ITEM_END, dest, pProto, count, true, pItem, bag, slot);
  10836. if (res != EQUIP_ERR_OK)
  10837. {
  10838. if (no_space_count)
  10839. *no_space_count = count + no_similar_count;
  10840. return res;
  10841. }
  10842.  
  10843. if (count == 0)
  10844. {
  10845. if (no_similar_count == 0)
  10846. return EQUIP_ERR_OK;
  10847.  
  10848. if (no_space_count)
  10849. *no_space_count = count + no_similar_count;
  10850. return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
  10851. }
  10852. }
  10853. else // equipped bag
  10854. {
  10855. // we need check 2 time (specialized/non_specialized), use NULL_BAG to prevent skipping bag
  10856. res = CanStoreItem_InBag(bag, dest, pProto, count, true, false, pItem, NULL_BAG, slot);
  10857. if (res != EQUIP_ERR_OK)
  10858. res = CanStoreItem_InBag(bag, dest, pProto, count, true, true, pItem, NULL_BAG, slot);
  10859.  
  10860. if (res != EQUIP_ERR_OK)
  10861. {
  10862. if (no_space_count)
  10863. *no_space_count = count + no_similar_count;
  10864. return res;
  10865. }
  10866.  
  10867. if (count == 0)
  10868. {
  10869. if (no_similar_count == 0)
  10870. return EQUIP_ERR_OK;
  10871.  
  10872. if (no_space_count)
  10873. *no_space_count = count + no_similar_count;
  10874. return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
  10875. }
  10876. }
  10877. }
  10878.  
  10879. // search free slot in bag for place to
  10880. if (bag == INVENTORY_SLOT_BAG_0) // inventory
  10881. {
  10882. // search free slot - keyring case
  10883. if (pProto->BagFamily & BAG_FAMILY_MASK_KEYS)
  10884. {
  10885. uint32 keyringSize = GetMaxKeyringSize();
  10886. res = CanStoreItem_InInventorySlots(KEYRING_SLOT_START, KEYRING_SLOT_START+keyringSize, dest, pProto, count, false, pItem, bag, slot);
  10887. if (res != EQUIP_ERR_OK)
  10888. {
  10889. if (no_space_count)
  10890. *no_space_count = count + no_similar_count;
  10891. return res;
  10892. }
  10893.  
  10894. if (count == 0)
  10895. {
  10896. if (no_similar_count == 0)
  10897. return EQUIP_ERR_OK;
  10898.  
  10899. if (no_space_count)
  10900. *no_space_count = count + no_similar_count;
  10901. return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
  10902. }
  10903.  
  10904. res = CanStoreItem_InInventorySlots(CURRENCYTOKEN_SLOT_START, CURRENCYTOKEN_SLOT_END, dest, pProto, count, false, pItem, bag, slot);
  10905. if (res != EQUIP_ERR_OK)
  10906. {
  10907. if (no_space_count)
  10908. *no_space_count = count + no_similar_count;
  10909. return res;
  10910. }
  10911.  
  10912. if (count == 0)
  10913. {
  10914. if (no_similar_count == 0)
  10915. return EQUIP_ERR_OK;
  10916.  
  10917. if (no_space_count)
  10918. *no_space_count = count + no_similar_count;
  10919. return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
  10920. }
  10921. }
  10922. else if (pProto->IsCurrencyToken())
  10923. {
  10924. res = CanStoreItem_InInventorySlots(CURRENCYTOKEN_SLOT_START, CURRENCYTOKEN_SLOT_END, dest, pProto, count, false, pItem, bag, slot);
  10925. if (res != EQUIP_ERR_OK)
  10926. {
  10927. if (no_space_count)
  10928. *no_space_count = count + no_similar_count;
  10929. return res;
  10930. }
  10931.  
  10932. if (count == 0)
  10933. {
  10934. if (no_similar_count == 0)
  10935. return EQUIP_ERR_OK;
  10936.  
  10937. if (no_space_count)
  10938. *no_space_count = count + no_similar_count;
  10939. return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
  10940. }
  10941. }
  10942.  
  10943. res = CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START, INVENTORY_SLOT_ITEM_END, dest, pProto, count, false, pItem, bag, slot);
  10944. if (res != EQUIP_ERR_OK)
  10945. {
  10946. if (no_space_count)
  10947. *no_space_count = count + no_similar_count;
  10948. return res;
  10949. }
  10950.  
  10951. if (count == 0)
  10952. {
  10953. if (no_similar_count == 0)
  10954. return EQUIP_ERR_OK;
  10955.  
  10956. if (no_space_count)
  10957. *no_space_count = count + no_similar_count;
  10958. return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
  10959. }
  10960. }
  10961. else // equipped bag
  10962. {
  10963. res = CanStoreItem_InBag(bag, dest, pProto, count, false, false, pItem, NULL_BAG, slot);
  10964. if (res != EQUIP_ERR_OK)
  10965. res = CanStoreItem_InBag(bag, dest, pProto, count, false, true, pItem, NULL_BAG, slot);
  10966.  
  10967. if (res != EQUIP_ERR_OK)
  10968. {
  10969. if (no_space_count)
  10970. *no_space_count = count + no_similar_count;
  10971. return res;
  10972. }
  10973.  
  10974. if (count == 0)
  10975. {
  10976. if (no_similar_count == 0)
  10977. return EQUIP_ERR_OK;
  10978.  
  10979. if (no_space_count)
  10980. *no_space_count = count + no_similar_count;
  10981. return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
  10982. }
  10983. }
  10984. }
  10985.  
  10986. // not specific bag or have space for partly store only in specific bag
  10987.  
  10988. // search stack for merge to
  10989. if (pProto->Stackable != 1)
  10990. {
  10991. res = CanStoreItem_InInventorySlots(KEYRING_SLOT_START, CURRENCYTOKEN_SLOT_END, dest, pProto, count, true, pItem, bag, slot);
  10992. if (res != EQUIP_ERR_OK)
  10993. {
  10994. if (no_space_count)
  10995. *no_space_count = count + no_similar_count;
  10996. return res;
  10997. }
  10998.  
  10999. if (count == 0)
  11000. {
  11001. if (no_similar_count == 0)
  11002. return EQUIP_ERR_OK;
  11003.  
  11004. if (no_space_count)
  11005. *no_space_count = count + no_similar_count;
  11006. return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
  11007. }
  11008.  
  11009. res = CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START, INVENTORY_SLOT_ITEM_END, dest, pProto, count, true, pItem, bag, slot);
  11010. if (res != EQUIP_ERR_OK)
  11011. {
  11012. if (no_space_count)
  11013. *no_space_count = count + no_similar_count;
  11014. return res;
  11015. }
  11016.  
  11017. if (count == 0)
  11018. {
  11019. if (no_similar_count == 0)
  11020. return EQUIP_ERR_OK;
  11021.  
  11022. if (no_space_count)
  11023. *no_space_count = count + no_similar_count;
  11024. return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
  11025. }
  11026.  
  11027. if (pProto->BagFamily)
  11028. {
  11029. for (uint32 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
  11030. {
  11031. res = CanStoreItem_InBag(i, dest, pProto, count, true, false, pItem, bag, slot);
  11032. if (res != EQUIP_ERR_OK)
  11033. continue;
  11034.  
  11035. if (count == 0)
  11036. {
  11037. if (no_similar_count == 0)
  11038. return EQUIP_ERR_OK;
  11039.  
  11040. if (no_space_count)
  11041. *no_space_count = count + no_similar_count;
  11042. return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
  11043. }
  11044. }
  11045. }
  11046.  
  11047. for (uint32 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
  11048. {
  11049. res = CanStoreItem_InBag(i, dest, pProto, count, true, true, pItem, bag, slot);
  11050. if (res != EQUIP_ERR_OK)
  11051. continue;
  11052.  
  11053. if (count == 0)
  11054. {
  11055. if (no_similar_count == 0)
  11056. return EQUIP_ERR_OK;
  11057.  
  11058. if (no_space_count)
  11059. *no_space_count = count + no_similar_count;
  11060. return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
  11061. }
  11062. }
  11063. }
  11064.  
  11065. // search free slot - special bag case
  11066. if (pProto->BagFamily)
  11067. {
  11068. if (pProto->BagFamily & BAG_FAMILY_MASK_KEYS)
  11069. {
  11070. uint32 keyringSize = GetMaxKeyringSize();
  11071. res = CanStoreItem_InInventorySlots(KEYRING_SLOT_START, KEYRING_SLOT_START+keyringSize, dest, pProto, count, false, pItem, bag, slot);
  11072. if (res != EQUIP_ERR_OK)
  11073. {
  11074. if (no_space_count)
  11075. *no_space_count = count + no_similar_count;
  11076. return res;
  11077. }
  11078.  
  11079. if (count == 0)
  11080. {
  11081. if (no_similar_count == 0)
  11082. return EQUIP_ERR_OK;
  11083.  
  11084. if (no_space_count)
  11085. *no_space_count = count + no_similar_count;
  11086. return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
  11087. }
  11088. }
  11089. else if (pProto->IsCurrencyToken())
  11090. {
  11091. res = CanStoreItem_InInventorySlots(CURRENCYTOKEN_SLOT_START, CURRENCYTOKEN_SLOT_END, dest, pProto, count, false, pItem, bag, slot);
  11092. if (res != EQUIP_ERR_OK)
  11093. {
  11094. if (no_space_count)
  11095. *no_space_count = count + no_similar_count;
  11096. return res;
  11097. }
  11098.  
  11099. if (count == 0)
  11100. {
  11101. if (no_similar_count == 0)
  11102. return EQUIP_ERR_OK;
  11103.  
  11104. if (no_space_count)
  11105. *no_space_count = count + no_similar_count;
  11106. return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
  11107. }
  11108. }
  11109.  
  11110. for (uint32 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
  11111. {
  11112. res = CanStoreItem_InBag(i, dest, pProto, count, false, false, pItem, bag, slot);
  11113. if (res != EQUIP_ERR_OK)
  11114. continue;
  11115.  
  11116. if (count == 0)
  11117. {
  11118. if (no_similar_count == 0)
  11119. return EQUIP_ERR_OK;
  11120.  
  11121. if (no_space_count)
  11122. *no_space_count = count + no_similar_count;
  11123. return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
  11124. }
  11125. }
  11126. }
  11127.  
  11128. if (pItem && pItem->IsNotEmptyBag())
  11129. return EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG;
  11130.  
  11131. // search free slot
  11132. res = CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START, INVENTORY_SLOT_ITEM_END, dest, pProto, count, false, pItem, bag, slot);
  11133. if (res != EQUIP_ERR_OK)
  11134. {
  11135. if (no_space_count)
  11136. *no_space_count = count + no_similar_count;
  11137. return res;
  11138. }
  11139.  
  11140. if (count == 0)
  11141. {
  11142. if (no_similar_count == 0)
  11143. return EQUIP_ERR_OK;
  11144.  
  11145. if (no_space_count)
  11146. *no_space_count = count + no_similar_count;
  11147. return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
  11148. }
  11149.  
  11150. for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
  11151. {
  11152. res = CanStoreItem_InBag(i, dest, pProto, count, false, true, pItem, bag, slot);
  11153. if (res != EQUIP_ERR_OK)
  11154. continue;
  11155.  
  11156. if (count == 0)
  11157. {
  11158. if (no_similar_count == 0)
  11159. return EQUIP_ERR_OK;
  11160.  
  11161. if (no_space_count)
  11162. *no_space_count = count + no_similar_count;
  11163. return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS;
  11164. }
  11165. }
  11166.  
  11167. if (no_space_count)
  11168. *no_space_count = count + no_similar_count;
  11169.  
  11170. return EQUIP_ERR_INVENTORY_FULL;
  11171. }
  11172.  
  11173. //////////////////////////////////////////////////////////////////////////
  11174. InventoryResult Player::CanStoreItems(Item** pItems, int count) const
  11175. {
  11176. Item* pItem2;
  11177.  
  11178. // fill space table
  11179. int inv_slot_items[INVENTORY_SLOT_ITEM_END - INVENTORY_SLOT_ITEM_START];
  11180. int inv_bags[INVENTORY_SLOT_BAG_END - INVENTORY_SLOT_BAG_START][MAX_BAG_SIZE];
  11181. int inv_keys[KEYRING_SLOT_END - KEYRING_SLOT_START];
  11182. int inv_tokens[CURRENCYTOKEN_SLOT_END - CURRENCYTOKEN_SLOT_START];
  11183.  
  11184. memset(inv_slot_items, 0, sizeof(int) * (INVENTORY_SLOT_ITEM_END - INVENTORY_SLOT_ITEM_START));
  11185. memset(inv_bags, 0, sizeof(int) * (INVENTORY_SLOT_BAG_END - INVENTORY_SLOT_BAG_START) * MAX_BAG_SIZE);
  11186. memset(inv_keys, 0, sizeof(int) * (KEYRING_SLOT_END - KEYRING_SLOT_START));
  11187. memset(inv_tokens, 0, sizeof(int) * (CURRENCYTOKEN_SLOT_END - CURRENCYTOKEN_SLOT_START));
  11188.  
  11189. for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
  11190. {
  11191. pItem2 = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
  11192. if (pItem2 && !pItem2->IsInTrade())
  11193. inv_slot_items[i - INVENTORY_SLOT_ITEM_START] = pItem2->GetCount();
  11194. }
  11195.  
  11196. for (uint8 i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; i++)
  11197. {
  11198. pItem2 = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
  11199. if (pItem2 && !pItem2->IsInTrade())
  11200. inv_keys[i - KEYRING_SLOT_START] = pItem2->GetCount();
  11201. }
  11202.  
  11203. for (uint8 i = CURRENCYTOKEN_SLOT_START; i < CURRENCYTOKEN_SLOT_END; i++)
  11204. {
  11205. pItem2 = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
  11206. if (pItem2 && !pItem2->IsInTrade())
  11207. inv_tokens[i - CURRENCYTOKEN_SLOT_START] = pItem2->GetCount();
  11208. }
  11209.  
  11210. for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
  11211. if (Bag* pBag = GetBagByPos(i))
  11212. for (uint32 j = 0; j < pBag->GetBagSize(); j++)
  11213. {
  11214. pItem2 = GetItemByPos(i, j);
  11215. if (pItem2 && !pItem2->IsInTrade())
  11216. inv_bags[i - INVENTORY_SLOT_BAG_START][j] = pItem2->GetCount();
  11217. }
  11218.  
  11219. // check free space for all items
  11220. for (int k = 0; k < count; ++k)
  11221. {
  11222. Item* pItem = pItems[k];
  11223.  
  11224. // no item
  11225. if (!pItem)
  11226. continue;
  11227.  
  11228. sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "STORAGE: CanStoreItems %i. item = %u, count = %u", k + 1, pItem->GetEntry(), pItem->GetCount());
  11229. ItemTemplate const* pProto = pItem->GetTemplate();
  11230.  
  11231. // strange item
  11232. if (!pProto)
  11233. return EQUIP_ERR_ITEM_NOT_FOUND;
  11234.  
  11235. // item used
  11236. if (pItem->m_lootGenerated)
  11237. return EQUIP_ERR_ALREADY_LOOTED;
  11238.  
  11239. // item it 'bind'
  11240. if (pItem->IsBindedNotWith(this))
  11241. return EQUIP_ERR_DONT_OWN_THAT_ITEM;
  11242.  
  11243. ItemTemplate const* pBagProto;
  11244.  
  11245. // item is 'one item only'
  11246. InventoryResult res = CanTakeMoreSimilarItems(pItem);
  11247. if (res != EQUIP_ERR_OK)
  11248. return res;
  11249.  
  11250. // search stack for merge to
  11251. if (pProto->Stackable != 1)
  11252. {
  11253. bool b_found = false;
  11254.  
  11255. for (uint8 t = KEYRING_SLOT_START; t < KEYRING_SLOT_END; ++t)
  11256. {
  11257. pItem2 = GetItemByPos(INVENTORY_SLOT_BAG_0, t);
  11258. if (pItem2 && pItem2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && inv_keys[t-KEYRING_SLOT_START] + pItem->GetCount() <= pProto->GetMaxStackSize())
  11259. {
  11260. inv_keys[t-KEYRING_SLOT_START] += pItem->GetCount();
  11261. b_found = true;
  11262. break;
  11263. }
  11264. }
  11265. if (b_found)
  11266. continue;
  11267.  
  11268. for (int t = CURRENCYTOKEN_SLOT_START; t < CURRENCYTOKEN_SLOT_END; ++t)
  11269. {
  11270. pItem2 = GetItemByPos(INVENTORY_SLOT_BAG_0, t);
  11271. if (pItem2 && pItem2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && inv_tokens[t-CURRENCYTOKEN_SLOT_START] + pItem->GetCount() <= pProto->GetMaxStackSize())
  11272. {
  11273. inv_tokens[t-CURRENCYTOKEN_SLOT_START] += pItem->GetCount();
  11274. b_found = true;
  11275. break;
  11276. }
  11277. }
  11278. if (b_found)
  11279. continue;
  11280.  
  11281. for (int t = INVENTORY_SLOT_ITEM_START; t < INVENTORY_SLOT_ITEM_END; ++t)
  11282. {
  11283. pItem2 = GetItemByPos(INVENTORY_SLOT_BAG_0, t);
  11284. if (pItem2 && pItem2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && inv_slot_items[t-INVENTORY_SLOT_ITEM_START] + pItem->GetCount() <= pProto->GetMaxStackSize())
  11285. {
  11286. inv_slot_items[t-INVENTORY_SLOT_ITEM_START] += pItem->GetCount();
  11287. b_found = true;
  11288. break;
  11289. }
  11290. }
  11291. if (b_found)
  11292. continue;
  11293.  
  11294. for (int t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; ++t)
  11295. {
  11296. if (Bag* bag = GetBagByPos(t))
  11297. {
  11298. if (ItemCanGoIntoBag(pItem->GetTemplate(), bag->GetTemplate()))
  11299. {
  11300. for (uint32 j = 0; j < bag->GetBagSize(); j++)
  11301. {
  11302. pItem2 = GetItemByPos(t, j);
  11303. if (pItem2 && pItem2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && inv_bags[t-INVENTORY_SLOT_BAG_START][j] + pItem->GetCount() <= pProto->GetMaxStackSize())
  11304. {
  11305. inv_bags[t-INVENTORY_SLOT_BAG_START][j] += pItem->GetCount();
  11306. b_found = true;
  11307. break;
  11308. }
  11309. }
  11310. }
  11311. }
  11312. }
  11313. if (b_found)
  11314. continue;
  11315. }
  11316.  
  11317. // special bag case
  11318. if (pProto->BagFamily)
  11319. {
  11320. bool b_found = false;
  11321. if (pProto->BagFamily & BAG_FAMILY_MASK_KEYS)
  11322. {
  11323. uint32 keyringSize = GetMaxKeyringSize();
  11324. for (uint32 t = KEYRING_SLOT_START; t < KEYRING_SLOT_START+keyringSize; ++t)
  11325. {
  11326. if (inv_keys[t-KEYRING_SLOT_START] == 0)
  11327. {
  11328. inv_keys[t-KEYRING_SLOT_START] = 1;
  11329. b_found = true;
  11330. break;
  11331. }
  11332. }
  11333. }
  11334.  
  11335. if (b_found)
  11336. continue;
  11337.  
  11338. if (pProto->IsCurrencyToken())
  11339. {
  11340. for (uint32 t = CURRENCYTOKEN_SLOT_START; t < CURRENCYTOKEN_SLOT_END; ++t)
  11341. {
  11342. if (inv_tokens[t-CURRENCYTOKEN_SLOT_START] == 0)
  11343. {
  11344. inv_tokens[t-CURRENCYTOKEN_SLOT_START] = 1;
  11345. b_found = true;
  11346. break;
  11347. }
  11348. }
  11349. }
  11350.  
  11351. if (b_found)
  11352. continue;
  11353.  
  11354. for (int t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; ++t)
  11355. {
  11356. if (Bag* bag = GetBagByPos(t))
  11357. {
  11358. pBagProto = bag->GetTemplate();
  11359.  
  11360. // not plain container check
  11361. if (pBagProto && (pBagProto->Class != ITEM_CLASS_CONTAINER || pBagProto->SubClass != ITEM_SUBCLASS_CONTAINER) &&
  11362. ItemCanGoIntoBag(pProto, pBagProto))
  11363. {
  11364. for (uint32 j = 0; j < bag->GetBagSize(); j++)
  11365. {
  11366. if (inv_bags[t-INVENTORY_SLOT_BAG_START][j] == 0)
  11367. {
  11368. inv_bags[t-INVENTORY_SLOT_BAG_START][j] = 1;
  11369. b_found = true;
  11370. break;
  11371. }
  11372. }
  11373. }
  11374. }
  11375. }
  11376. if (b_found)
  11377. continue;
  11378. }
  11379.  
  11380. // search free slot
  11381. bool b_found = false;
  11382. for (int t = INVENTORY_SLOT_ITEM_START; t < INVENTORY_SLOT_ITEM_END; ++t)
  11383. {
  11384. if (inv_slot_items[t-INVENTORY_SLOT_ITEM_START] == 0)
  11385. {
  11386. inv_slot_items[t-INVENTORY_SLOT_ITEM_START] = 1;
  11387. b_found = true;
  11388. break;
  11389. }
  11390. }
  11391. if (b_found)
  11392. continue;
  11393.  
  11394. // search free slot in bags
  11395. for (int t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; ++t)
  11396. {
  11397. if (Bag* bag = GetBagByPos(t))
  11398. {
  11399. pBagProto = bag->GetTemplate();
  11400.  
  11401. // special bag already checked
  11402. if (pBagProto && (pBagProto->Class != ITEM_CLASS_CONTAINER || pBagProto->SubClass != ITEM_SUBCLASS_CONTAINER))
  11403. continue;
  11404.  
  11405. for (uint32 j = 0; j < bag->GetBagSize(); j++)
  11406. {
  11407. if (inv_bags[t-INVENTORY_SLOT_BAG_START][j] == 0)
  11408. {
  11409. inv_bags[t-INVENTORY_SLOT_BAG_START][j] = 1;
  11410. b_found = true;
  11411. break;
  11412. }
  11413. }
  11414. }
  11415. }
  11416.  
  11417. // no free slot found?
  11418. if (!b_found)
  11419. return EQUIP_ERR_INVENTORY_FULL;
  11420. }
  11421.  
  11422. return EQUIP_ERR_OK;
  11423. }
  11424.  
  11425. //////////////////////////////////////////////////////////////////////////
  11426. InventoryResult Player::CanEquipNewItem(uint8 slot, uint16 &dest, uint32 item, bool swap) const
  11427. {
  11428. dest = 0;
  11429. Item* pItem = Item::CreateItem(item, 1, this);
  11430. if (pItem)
  11431. {
  11432. InventoryResult result = CanEquipItem(slot, dest, pItem, swap);
  11433. delete pItem;
  11434. return result;
  11435. }
  11436.  
  11437. return EQUIP_ERR_ITEM_NOT_FOUND;
  11438. }
  11439.  
  11440. InventoryResult Player::CanEquipItem(uint8 slot, uint16 &dest, Item* pItem, bool swap, bool not_loading) const
  11441. {
  11442. dest = 0;
  11443. if (pItem)
  11444. {
  11445. sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "STORAGE: CanEquipItem slot = %u, item = %u, count = %u", slot, pItem->GetEntry(), pItem->GetCount());
  11446. ItemTemplate const* pProto = pItem->GetTemplate();
  11447. if (pProto)
  11448. {
  11449. // item used
  11450. if (pItem->m_lootGenerated)
  11451. return EQUIP_ERR_ALREADY_LOOTED;
  11452.  
  11453. if (pItem->IsBindedNotWith(this))
  11454. return EQUIP_ERR_DONT_OWN_THAT_ITEM;
  11455.  
  11456. // check count of items (skip for auto move for same player from bank)
  11457. InventoryResult res = CanTakeMoreSimilarItems(pItem);
  11458. if (res != EQUIP_ERR_OK)
  11459. return res;
  11460.  
  11461. // check this only in game
  11462. if (not_loading)
  11463. {
  11464. // May be here should be more stronger checks; STUNNED checked
  11465. // ROOT, CONFUSED, DISTRACTED, FLEEING this needs to be checked.
  11466. if (HasUnitState(UNIT_STATE_STUNNED))
  11467. return EQUIP_ERR_YOU_ARE_STUNNED;
  11468.  
  11469. // do not allow equipping gear except weapons, offhands, projectiles, relics in
  11470. // - combat
  11471. // - in-progress arenas
  11472. if (!pProto->CanChangeEquipStateInCombat())
  11473. {
  11474. if (isInCombat())
  11475. return EQUIP_ERR_NOT_IN_COMBAT;
  11476.  
  11477. if (Battleground* bg = GetBattleground())
  11478. if (bg->isArena() && bg->GetStatus() == STATUS_IN_PROGRESS)
  11479. return EQUIP_ERR_NOT_DURING_ARENA_MATCH;
  11480. }
  11481.  
  11482. if (isInCombat()&& (pProto->Class == ITEM_CLASS_WEAPON || pProto->InventoryType == INVTYPE_RELIC) && m_weaponChangeTimer != 0)
  11483. return EQUIP_ERR_CANT_DO_RIGHT_NOW; // maybe exist better err
  11484.  
  11485. if (IsNonMeleeSpellCasted(false))
  11486. return EQUIP_ERR_CANT_DO_RIGHT_NOW;
  11487. }
  11488.  
  11489. ScalingStatDistributionEntry const* ssd = pProto->ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(pProto->ScalingStatDistribution) : 0;
  11490. // check allowed level (extend range to upper values if MaxLevel more or equal max player level, this let GM set high level with 1...max range items)
  11491. if (ssd && ssd->MaxLevel < DEFAULT_MAX_LEVEL && ssd->MaxLevel < getLevel())
  11492. return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
  11493.  
  11494. uint8 eslot = FindEquipSlot(pProto, slot, swap);
  11495. if (eslot == NULL_SLOT)
  11496. return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
  11497.  
  11498. res = CanUseItem(pItem, not_loading);
  11499. if (res != EQUIP_ERR_OK)
  11500. return res;
  11501.  
  11502. if (!swap && GetItemByPos(INVENTORY_SLOT_BAG_0, eslot))
  11503. return EQUIP_ERR_NO_EQUIPMENT_SLOT_AVAILABLE;
  11504.  
  11505. // if swap ignore item (equipped also)
  11506. InventoryResult res2 = CanEquipUniqueItem(pItem, swap ? eslot : uint8(NULL_SLOT));
  11507. if (res2 != EQUIP_ERR_OK)
  11508. return res2;
  11509.  
  11510. // check unique-equipped special item classes
  11511. if (pProto->Class == ITEM_CLASS_QUIVER)
  11512. for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
  11513. if (Item* pBag = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  11514. if (pBag != pItem)
  11515. if (ItemTemplate const* pBagProto = pBag->GetTemplate())
  11516. if (pBagProto->Class == pProto->Class && (!swap || pBag->GetSlot() != eslot))
  11517. return (pBagProto->SubClass == ITEM_SUBCLASS_AMMO_POUCH)
  11518. ? EQUIP_ERR_CAN_EQUIP_ONLY1_AMMOPOUCH
  11519. : EQUIP_ERR_CAN_EQUIP_ONLY1_QUIVER;
  11520.  
  11521. uint32 type = pProto->InventoryType;
  11522.  
  11523. if (eslot == EQUIPMENT_SLOT_OFFHAND)
  11524. {
  11525. if (type == INVTYPE_WEAPON || type == INVTYPE_WEAPONOFFHAND)
  11526. {
  11527. if (!CanDualWield())
  11528. return EQUIP_ERR_CANT_DUAL_WIELD;
  11529. }
  11530. else if (type == INVTYPE_2HWEAPON)
  11531. {
  11532. if (!CanDualWield() || !CanTitanGrip())
  11533. return EQUIP_ERR_CANT_DUAL_WIELD;
  11534. }
  11535.  
  11536. if (IsTwoHandUsed())
  11537. return EQUIP_ERR_CANT_EQUIP_WITH_TWOHANDED;
  11538. }
  11539.  
  11540. // equip two-hand weapon case (with possible unequip 2 items)
  11541. if (type == INVTYPE_2HWEAPON)
  11542. {
  11543. if (eslot == EQUIPMENT_SLOT_OFFHAND)
  11544. {
  11545. if (!CanTitanGrip())
  11546. return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
  11547. }
  11548. else if (eslot != EQUIPMENT_SLOT_MAINHAND)
  11549. return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
  11550.  
  11551. if (!CanTitanGrip())
  11552. {
  11553. // offhand item must can be stored in inventory for offhand item and it also must be unequipped
  11554. Item* offItem = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
  11555. ItemPosCountVec off_dest;
  11556. if (offItem && (!not_loading ||
  11557. CanUnequipItem(uint16(INVENTORY_SLOT_BAG_0) << 8 | EQUIPMENT_SLOT_OFFHAND, false) != EQUIP_ERR_OK ||
  11558. CanStoreItem(NULL_BAG, NULL_SLOT, off_dest, offItem, false) != EQUIP_ERR_OK))
  11559. return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_INVENTORY_FULL;
  11560. }
  11561. }
  11562. dest = ((INVENTORY_SLOT_BAG_0 << 8) | eslot);
  11563. return EQUIP_ERR_OK;
  11564. }
  11565. }
  11566.  
  11567. return !swap ? EQUIP_ERR_ITEM_NOT_FOUND : EQUIP_ERR_ITEMS_CANT_BE_SWAPPED;
  11568. }
  11569.  
  11570. InventoryResult Player::CanUnequipItem(uint16 pos, bool swap) const
  11571. {
  11572. // Applied only to equipped items and bank bags
  11573. if (!IsEquipmentPos(pos) && !IsBagPos(pos))
  11574. return EQUIP_ERR_OK;
  11575.  
  11576. Item* pItem = GetItemByPos(pos);
  11577.  
  11578. // Applied only to existed equipped item
  11579. if (!pItem)
  11580. return EQUIP_ERR_OK;
  11581.  
  11582. sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "STORAGE: CanUnequipItem slot = %u, item = %u, count = %u", pos, pItem->GetEntry(), pItem->GetCount());
  11583.  
  11584. ItemTemplate const* pProto = pItem->GetTemplate();
  11585. if (!pProto)
  11586. return EQUIP_ERR_ITEM_NOT_FOUND;
  11587.  
  11588. // item used
  11589. if (pItem->m_lootGenerated)
  11590. return EQUIP_ERR_ALREADY_LOOTED;
  11591.  
  11592. // do not allow unequipping gear except weapons, offhands, projectiles, relics in
  11593. // - combat
  11594. // - in-progress arenas
  11595. if (!pProto->CanChangeEquipStateInCombat())
  11596. {
  11597. if (isInCombat())
  11598. return EQUIP_ERR_NOT_IN_COMBAT;
  11599.  
  11600. if (Battleground* bg = GetBattleground())
  11601. if (bg->isArena() && bg->GetStatus() == STATUS_IN_PROGRESS)
  11602. return EQUIP_ERR_NOT_DURING_ARENA_MATCH;
  11603. }
  11604.  
  11605. if (!swap && pItem->IsNotEmptyBag())
  11606. return EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS;
  11607.  
  11608. return EQUIP_ERR_OK;
  11609. }
  11610.  
  11611. InventoryResult Player::CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, Item* pItem, bool swap, bool not_loading) const
  11612. {
  11613. if (!pItem)
  11614. return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_ITEM_NOT_FOUND;
  11615.  
  11616. uint32 count = pItem->GetCount();
  11617.  
  11618. sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "STORAGE: CanBankItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, pItem->GetEntry(), pItem->GetCount());
  11619. ItemTemplate const* pProto = pItem->GetTemplate();
  11620. if (!pProto)
  11621. return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_ITEM_NOT_FOUND;
  11622.  
  11623. // item used
  11624. if (pItem->m_lootGenerated)
  11625. return EQUIP_ERR_ALREADY_LOOTED;
  11626.  
  11627. if (pItem->IsBindedNotWith(this))
  11628. return EQUIP_ERR_DONT_OWN_THAT_ITEM;
  11629.  
  11630. // Currency tokens are not supposed to be swapped out of their hidden bag
  11631. uint8 pItemslot = pItem->GetSlot();
  11632. if (pItemslot >= CURRENCYTOKEN_SLOT_START && pItemslot < CURRENCYTOKEN_SLOT_END)
  11633. {
  11634. sLog->outError(LOG_FILTER_PLAYER, "Possible hacking attempt: Player %s [guid: %u] tried to move token [guid: %u, entry: %u] out of the currency bag!",
  11635. GetName(), GetGUIDLow(), pItem->GetGUIDLow(), pProto->ItemId);
  11636. return EQUIP_ERR_ITEMS_CANT_BE_SWAPPED;
  11637. }
  11638.  
  11639. // check count of items (skip for auto move for same player from bank)
  11640. InventoryResult res = CanTakeMoreSimilarItems(pItem);
  11641. if (res != EQUIP_ERR_OK)
  11642. return res;
  11643.  
  11644. // in specific slot
  11645. if (bag != NULL_BAG && slot != NULL_SLOT)
  11646. {
  11647. if (slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END)
  11648. {
  11649. if (!pItem->IsBag())
  11650. return EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT;
  11651.  
  11652. if (slot - BANK_SLOT_BAG_START >= GetBankBagSlotCount())
  11653. return EQUIP_ERR_MUST_PURCHASE_THAT_BAG_SLOT;
  11654.  
  11655. res = CanUseItem(pItem, not_loading);
  11656. if (res != EQUIP_ERR_OK)
  11657. return res;
  11658. }
  11659.  
  11660. res = CanStoreItem_InSpecificSlot(bag, slot, dest, pProto, count, swap, pItem);
  11661. if (res != EQUIP_ERR_OK)
  11662. return res;
  11663.  
  11664. if (count == 0)
  11665. return EQUIP_ERR_OK;
  11666. }
  11667.  
  11668. // not specific slot or have space for partly store only in specific slot
  11669.  
  11670. // in specific bag
  11671. if (bag != NULL_BAG)
  11672. {
  11673. if (pItem->IsNotEmptyBag())
  11674. return EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG;
  11675.  
  11676. // search stack in bag for merge to
  11677. if (pProto->Stackable != 1)
  11678. {
  11679. if (bag == INVENTORY_SLOT_BAG_0)
  11680. {
  11681. res = CanStoreItem_InInventorySlots(BANK_SLOT_ITEM_START, BANK_SLOT_ITEM_END, dest, pProto, count, true, pItem, bag, slot);
  11682. if (res != EQUIP_ERR_OK)
  11683. return res;
  11684.  
  11685. if (count == 0)
  11686. return EQUIP_ERR_OK;
  11687. }
  11688. else
  11689. {
  11690. res = CanStoreItem_InBag(bag, dest, pProto, count, true, false, pItem, NULL_BAG, slot);
  11691. if (res != EQUIP_ERR_OK)
  11692. res = CanStoreItem_InBag(bag, dest, pProto, count, true, true, pItem, NULL_BAG, slot);
  11693.  
  11694. if (res != EQUIP_ERR_OK)
  11695. return res;
  11696.  
  11697. if (count == 0)
  11698. return EQUIP_ERR_OK;
  11699. }
  11700. }
  11701.  
  11702. // search free slot in bag
  11703. if (bag == INVENTORY_SLOT_BAG_0)
  11704. {
  11705. res = CanStoreItem_InInventorySlots(BANK_SLOT_ITEM_START, BANK_SLOT_ITEM_END, dest, pProto, count, false, pItem, bag, slot);
  11706. if (res != EQUIP_ERR_OK)
  11707. return res;
  11708.  
  11709. if (count == 0)
  11710. return EQUIP_ERR_OK;
  11711. }
  11712. else
  11713. {
  11714. res = CanStoreItem_InBag(bag, dest, pProto, count, false, false, pItem, NULL_BAG, slot);
  11715. if (res != EQUIP_ERR_OK)
  11716. res = CanStoreItem_InBag(bag, dest, pProto, count, false, true, pItem, NULL_BAG, slot);
  11717.  
  11718. if (res != EQUIP_ERR_OK)
  11719. return res;
  11720.  
  11721. if (count == 0)
  11722. return EQUIP_ERR_OK;
  11723. }
  11724. }
  11725.  
  11726. // not specific bag or have space for partly store only in specific bag
  11727.  
  11728. // search stack for merge to
  11729. if (pProto->Stackable != 1)
  11730. {
  11731. // in slots
  11732. res = CanStoreItem_InInventorySlots(BANK_SLOT_ITEM_START, BANK_SLOT_ITEM_END, dest, pProto, count, true, pItem, bag, slot);
  11733. if (res != EQUIP_ERR_OK)
  11734. return res;
  11735.  
  11736. if (count == 0)
  11737. return EQUIP_ERR_OK;
  11738.  
  11739. // in special bags
  11740. if (pProto->BagFamily)
  11741. {
  11742. for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
  11743. {
  11744. res = CanStoreItem_InBag(i, dest, pProto, count, true, false, pItem, bag, slot);
  11745. if (res != EQUIP_ERR_OK)
  11746. continue;
  11747.  
  11748. if (count == 0)
  11749. return EQUIP_ERR_OK;
  11750. }
  11751. }
  11752.  
  11753. for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
  11754. {
  11755. res = CanStoreItem_InBag(i, dest, pProto, count, true, true, pItem, bag, slot);
  11756. if (res != EQUIP_ERR_OK)
  11757. continue;
  11758.  
  11759. if (count == 0)
  11760. return EQUIP_ERR_OK;
  11761. }
  11762. }
  11763.  
  11764. // search free place in special bag
  11765. if (pProto->BagFamily)
  11766. {
  11767. for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
  11768. {
  11769. res = CanStoreItem_InBag(i, dest, pProto, count, false, false, pItem, bag, slot);
  11770. if (res != EQUIP_ERR_OK)
  11771. continue;
  11772.  
  11773. if (count == 0)
  11774. return EQUIP_ERR_OK;
  11775. }
  11776. }
  11777.  
  11778. // search free space
  11779. res = CanStoreItem_InInventorySlots(BANK_SLOT_ITEM_START, BANK_SLOT_ITEM_END, dest, pProto, count, false, pItem, bag, slot);
  11780. if (res != EQUIP_ERR_OK)
  11781. return res;
  11782.  
  11783. if (count == 0)
  11784. return EQUIP_ERR_OK;
  11785.  
  11786. for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
  11787. {
  11788. res = CanStoreItem_InBag(i, dest, pProto, count, false, true, pItem, bag, slot);
  11789. if (res != EQUIP_ERR_OK)
  11790. continue;
  11791.  
  11792. if (count == 0)
  11793. return EQUIP_ERR_OK;
  11794. }
  11795. return EQUIP_ERR_BANK_FULL;
  11796. }
  11797.  
  11798. InventoryResult Player::CanUseItem(Item* pItem, bool not_loading) const
  11799. {
  11800. if (pItem)
  11801. {
  11802. sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "STORAGE: CanUseItem item = %u", pItem->GetEntry());
  11803.  
  11804. if (!isAlive() && not_loading)
  11805. return EQUIP_ERR_YOU_ARE_DEAD;
  11806.  
  11807. //if (isStunned())
  11808. // return EQUIP_ERR_YOU_ARE_STUNNED;
  11809.  
  11810. ItemTemplate const* pProto = pItem->GetTemplate();
  11811. if (pProto)
  11812. {
  11813. if (pItem->IsBindedNotWith(this))
  11814. return EQUIP_ERR_DONT_OWN_THAT_ITEM;
  11815.  
  11816. InventoryResult res = CanUseItem(pProto);
  11817. if (res != EQUIP_ERR_OK)
  11818. return res;
  11819.  
  11820. if (pItem->GetSkill() != 0)
  11821. {
  11822. bool allowEquip = false;
  11823. uint32 itemSkill = pItem->GetSkill();
  11824. // Armor that is binded to account can "morph" from plate to mail, etc. if skill is not learned yet.
  11825. if (pProto->Quality == ITEM_QUALITY_HEIRLOOM && pProto->Class == ITEM_CLASS_ARMOR && !HasSkill(itemSkill))
  11826. {
  11827. // TODO: when you right-click already equipped item it throws EQUIP_ERR_NO_REQUIRED_PROFICIENCY.
  11828.  
  11829. // In fact it's a visual bug, everything works properly... I need sniffs of operations with
  11830. // binded to account items from off server.
  11831.  
  11832. switch (getClass())
  11833. {
  11834. case CLASS_HUNTER:
  11835. case CLASS_SHAMAN:
  11836. allowEquip = (itemSkill == SKILL_MAIL);
  11837. break;
  11838. case CLASS_PALADIN:
  11839. case CLASS_WARRIOR:
  11840. allowEquip = (itemSkill == SKILL_PLATE_MAIL);
  11841. break;
  11842. }
  11843. }
  11844. if (!allowEquip && GetSkillValue(itemSkill) == 0)
  11845. return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
  11846. }
  11847.  
  11848. if (pProto->RequiredReputationFaction && uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank)
  11849. return EQUIP_ERR_CANT_EQUIP_REPUTATION;
  11850.  
  11851. return EQUIP_ERR_OK;
  11852. }
  11853. }
  11854. return EQUIP_ERR_ITEM_NOT_FOUND;
  11855. }
  11856.  
  11857. InventoryResult Player::CanUseItem(ItemTemplate const* proto) const
  11858. {
  11859. // Used by group, function NeedBeforeGreed, to know if a prototype can be used by a player
  11860.  
  11861. if (proto)
  11862. {
  11863. if ((proto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY) && GetTeam() != HORDE)
  11864. return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
  11865.  
  11866. if ((proto->Flags2 & ITEM_FLAGS_EXTRA_ALLIANCE_ONLY) && GetTeam() != ALLIANCE)
  11867. return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
  11868.  
  11869. if ((proto->AllowableClass & getClassMask()) == 0 || (proto->AllowableRace & getRaceMask()) == 0)
  11870. return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
  11871.  
  11872. if (proto->RequiredSkill != 0)
  11873. {
  11874. if (GetSkillValue(proto->RequiredSkill) == 0)
  11875. return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
  11876. else if (GetSkillValue(proto->RequiredSkill) < proto->RequiredSkillRank)
  11877. return EQUIP_ERR_CANT_EQUIP_SKILL;
  11878. }
  11879.  
  11880. if (proto->RequiredSpell != 0 && !HasSpell(proto->RequiredSpell))
  11881. return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
  11882.  
  11883. if (getLevel() < proto->RequiredLevel)
  11884. return EQUIP_ERR_CANT_EQUIP_LEVEL_I;
  11885.  
  11886. // If World Event is not active, prevent using event dependant items
  11887. if (proto->HolidayId && !IsHolidayActive((HolidayIds)proto->HolidayId))
  11888. return EQUIP_ERR_CANT_DO_RIGHT_NOW;
  11889.  
  11890. return EQUIP_ERR_OK;
  11891. }
  11892.  
  11893. return EQUIP_ERR_ITEM_NOT_FOUND;
  11894. }
  11895.  
  11896. InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObject const* lootedObject) const
  11897. {
  11898. LfgDungeonSet const& dungeons = sLFGMgr->GetSelectedDungeons(GetGUID());
  11899. if (dungeons.empty())
  11900. return EQUIP_ERR_OK; // not using LFG
  11901.  
  11902. if (!GetGroup() || !GetGroup()->isLFGGroup())
  11903. return EQUIP_ERR_OK; // not in LFG group
  11904.  
  11905. // check if looted object is inside the lfg dungeon
  11906. bool lootedObjectInDungeon = false;
  11907. Map const* map = lootedObject->GetMap();
  11908. if (uint32 dungeonId = sLFGMgr->GetDungeon(GetGroup()->GetGUID(), true))
  11909. if (LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(dungeonId))
  11910. if (uint32(dungeon->map) == map->GetId() && dungeon->difficulty == uint32(map->GetDifficulty()))
  11911. lootedObjectInDungeon = true;
  11912.  
  11913. if (!lootedObjectInDungeon)
  11914. return EQUIP_ERR_OK;
  11915.  
  11916. if (!proto)
  11917. return EQUIP_ERR_ITEM_NOT_FOUND;
  11918. // Used by group, function NeedBeforeGreed, to know if a prototype can be used by a player
  11919.  
  11920. const static uint32 item_weapon_skills[MAX_ITEM_SUBCLASS_WEAPON] =
  11921. {
  11922. SKILL_AXES, SKILL_2H_AXES, SKILL_BOWS, SKILL_GUNS, SKILL_MACES,
  11923. SKILL_2H_MACES, SKILL_POLEARMS, SKILL_SWORDS, SKILL_2H_SWORDS, 0,
  11924. SKILL_STAVES, 0, 0, SKILL_FIST_WEAPONS, 0,
  11925. SKILL_DAGGERS, SKILL_THROWN, SKILL_ASSASSINATION, SKILL_CROSSBOWS, SKILL_WANDS,
  11926. SKILL_FISHING
  11927. }; //Copy from function Item::GetSkill()
  11928.  
  11929. if ((proto->AllowableClass & getClassMask()) == 0 || (proto->AllowableRace & getRaceMask()) == 0)
  11930. return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
  11931.  
  11932. if (proto->RequiredSpell != 0 && !HasSpell(proto->RequiredSpell))
  11933. return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
  11934.  
  11935. if (proto->RequiredSkill != 0)
  11936. {
  11937. if (!GetSkillValue(proto->RequiredSkill))
  11938. return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
  11939. else if (GetSkillValue(proto->RequiredSkill) < proto->RequiredSkillRank)
  11940. return EQUIP_ERR_CANT_EQUIP_SKILL;
  11941. }
  11942.  
  11943. uint8 _class = getClass();
  11944.  
  11945. if (proto->Class == ITEM_CLASS_WEAPON && GetSkillValue(item_weapon_skills[proto->SubClass]) == 0)
  11946. return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
  11947.  
  11948. if (proto->Class == ITEM_CLASS_ARMOR && proto->SubClass > ITEM_SUBCLASS_ARMOR_MISC && proto->SubClass < ITEM_SUBCLASS_ARMOR_BUCKLER && proto->InventoryType != INVTYPE_CLOAK)
  11949. {
  11950. if (_class == CLASS_WARRIOR || _class == CLASS_PALADIN || _class == CLASS_DEATH_KNIGHT)
  11951. {
  11952. if (getLevel() < 40)
  11953. {
  11954. if (proto->SubClass != ITEM_SUBCLASS_ARMOR_MAIL)
  11955. return EQUIP_ERR_CANT_DO_RIGHT_NOW;
  11956. }
  11957. else if (proto->SubClass != ITEM_SUBCLASS_ARMOR_PLATE)
  11958. return EQUIP_ERR_CANT_DO_RIGHT_NOW;
  11959. }
  11960. else if (_class == CLASS_HUNTER || _class == CLASS_SHAMAN)
  11961. {
  11962. if (getLevel() < 40)
  11963. {
  11964. if (proto->SubClass != ITEM_SUBCLASS_ARMOR_LEATHER)
  11965. return EQUIP_ERR_CANT_DO_RIGHT_NOW;
  11966. }
  11967. else if (proto->SubClass != ITEM_SUBCLASS_ARMOR_MAIL)
  11968. return EQUIP_ERR_CANT_DO_RIGHT_NOW;
  11969. }
  11970.  
  11971. if (_class == CLASS_ROGUE || _class == CLASS_DRUID)
  11972. if (proto->SubClass != ITEM_SUBCLASS_ARMOR_LEATHER)
  11973. return EQUIP_ERR_CANT_DO_RIGHT_NOW;
  11974.  
  11975. if (_class == CLASS_MAGE || _class == CLASS_PRIEST || _class == CLASS_WARLOCK)
  11976. if (proto->SubClass != ITEM_SUBCLASS_ARMOR_CLOTH)
  11977. return EQUIP_ERR_CANT_DO_RIGHT_NOW;
  11978. }
  11979.  
  11980. return EQUIP_ERR_OK;
  11981. }
  11982.  
  11983. InventoryResult Player::CanUseAmmo(uint32 item) const
  11984. {
  11985. sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "STORAGE: CanUseAmmo item = %u", item);
  11986. if (!isAlive())
  11987. return EQUIP_ERR_YOU_ARE_DEAD;
  11988. //if (isStunned())
  11989. // return EQUIP_ERR_YOU_ARE_STUNNED;
  11990. ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item);
  11991. if (pProto)
  11992. {
  11993. if (pProto->InventoryType!= INVTYPE_AMMO)
  11994. return EQUIP_ERR_ONLY_AMMO_CAN_GO_HERE;
  11995.  
  11996. InventoryResult res = CanUseItem(pProto);
  11997. if (res != EQUIP_ERR_OK)
  11998. return res;
  11999.  
  12000. /*if (GetReputationMgr().GetReputation() < pProto->RequiredReputation)
  12001. return EQUIP_ERR_CANT_EQUIP_REPUTATION;
  12002. */
  12003.  
  12004. // Requires No Ammo
  12005. if (HasAura(46699))
  12006. return EQUIP_ERR_BAG_FULL6;
  12007.  
  12008. return EQUIP_ERR_OK;
  12009. }
  12010. return EQUIP_ERR_ITEM_NOT_FOUND;
  12011. }
  12012.  
  12013. void Player::SetAmmo(uint32 item)
  12014. {
  12015. if (!item)
  12016. return;
  12017.  
  12018. // already set
  12019. if (GetUInt32Value(PLAYER_AMMO_ID) == item)
  12020. return;
  12021.  
  12022. // check ammo
  12023. if (item)
  12024. {
  12025. InventoryResult msg = CanUseAmmo(item);
  12026. if (msg != EQUIP_ERR_OK)
  12027. {
  12028. SendEquipError(msg, NULL, NULL, item);
  12029. return;
  12030. }
  12031. }
  12032.  
  12033. SetUInt32Value(PLAYER_AMMO_ID, item);
  12034.  
  12035. _ApplyAmmoBonuses();
  12036. }
  12037.  
  12038. void Player::RemoveAmmo()
  12039. {
  12040. SetUInt32Value(PLAYER_AMMO_ID, 0);
  12041.  
  12042. m_ammoDPS = 0.0f;
  12043.  
  12044. if (CanModifyStats())
  12045. UpdateDamagePhysical(RANGED_ATTACK);
  12046. }
  12047.  
  12048. Item* Player::StoreNewItem(ItemPosCountVec const& dest, uint32 item, bool update, int32 randomPropertyId)
  12049. {
  12050. AllowedLooterSet allowedLooters;
  12051. return StoreNewItem(dest, item, update, randomPropertyId, allowedLooters);
  12052. }
  12053.  
  12054. // Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
  12055. Item* Player::StoreNewItem(ItemPosCountVec const& dest, uint32 item, bool update, int32 randomPropertyId, AllowedLooterSet& allowedLooters)
  12056. {
  12057. uint32 count = 0;
  12058. for (ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); ++itr)
  12059. count += itr->count;
  12060.  
  12061. Item* pItem = Item::CreateItem(item, count, this);
  12062. if (pItem)
  12063. {
  12064. ItemAddedQuestCheck(item, count);
  12065. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM, item, count);
  12066. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM, item, 1);
  12067. if (randomPropertyId)
  12068. pItem->SetItemRandomProperties(randomPropertyId);
  12069. pItem = StoreItem(dest, pItem, update);
  12070.  
  12071. if (allowedLooters.size() > 1 && pItem->GetTemplate()->GetMaxStackSize() == 1 && pItem->IsSoulBound())
  12072. {
  12073. pItem->SetSoulboundTradeable(allowedLooters);
  12074. pItem->SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, GetTotalPlayedTime());
  12075. AddTradeableItem(pItem);
  12076.  
  12077. // save data
  12078. std::ostringstream ss;
  12079. AllowedLooterSet::const_iterator itr = allowedLooters.begin();
  12080. ss << *itr;
  12081. for (++itr; itr != allowedLooters.end(); ++itr)
  12082. ss << ' ' << *itr;
  12083.  
  12084. PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_BOP_TRADE);
  12085. stmt->setUInt32(0, pItem->GetGUIDLow());
  12086. stmt->setString(1, ss.str());
  12087. CharacterDatabase.Execute(stmt);
  12088. }
  12089. }
  12090. return pItem;
  12091. }
  12092.  
  12093. Item* Player::StoreItem(ItemPosCountVec const& dest, Item* pItem, bool update)
  12094. {
  12095. if (!pItem)
  12096. return NULL;
  12097.  
  12098. Item* lastItem = pItem;
  12099. for (ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end();)
  12100. {
  12101. uint16 pos = itr->pos;
  12102. uint32 count = itr->count;
  12103.  
  12104. ++itr;
  12105.  
  12106. if (itr == dest.end())
  12107. {
  12108. lastItem = _StoreItem(pos, pItem, count, false, update);
  12109. break;
  12110. }
  12111.  
  12112. lastItem = _StoreItem(pos, pItem, count, true, update);
  12113. }
  12114. return lastItem;
  12115. }
  12116.  
  12117. // Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
  12118. Item* Player::_StoreItem(uint16 pos, Item* pItem, uint32 count, bool clone, bool update)
  12119. {
  12120. if (!pItem)
  12121. return NULL;
  12122.  
  12123. uint8 bag = pos >> 8;
  12124. uint8 slot = pos & 255;
  12125.  
  12126. sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "STORAGE: StoreItem bag = %u, slot = %u, item = %u, count = %u, guid = %u", bag, slot, pItem->GetEntry(), count, pItem->GetGUIDLow());
  12127.  
  12128. Item* pItem2 = GetItemByPos(bag, slot);
  12129.  
  12130. if (!pItem2)
  12131. {
  12132. if (clone)
  12133. pItem = pItem->CloneItem(count, this);
  12134. else
  12135. pItem->SetCount(count);
  12136.  
  12137. if (!pItem)
  12138. return NULL;
  12139.  
  12140. if (pItem->GetTemplate()->Bonding == BIND_WHEN_PICKED_UP ||
  12141. pItem->GetTemplate()->Bonding == BIND_QUEST_ITEM ||
  12142. (pItem->GetTemplate()->Bonding == BIND_WHEN_EQUIPED && IsBagPos(pos)))
  12143. pItem->SetBinding(true);
  12144.  
  12145. Bag* pBag = (bag == INVENTORY_SLOT_BAG_0) ? NULL : GetBagByPos(bag);
  12146. if (!pBag)
  12147. {
  12148. m_items[slot] = pItem;
  12149. SetUInt64Value(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2), pItem->GetGUID());
  12150. pItem->SetUInt64Value(ITEM_FIELD_CONTAINED, GetGUID());
  12151. pItem->SetUInt64Value(ITEM_FIELD_OWNER, GetGUID());
  12152.  
  12153. pItem->SetSlot(slot);
  12154. pItem->SetContainer(NULL);
  12155.  
  12156. // need update known currency
  12157. if (slot >= CURRENCYTOKEN_SLOT_START && slot < CURRENCYTOKEN_SLOT_END)
  12158. AddKnownCurrency(pItem->GetEntry());
  12159. }
  12160. else
  12161. pBag->StoreItem(slot, pItem, update);
  12162.  
  12163. if (IsInWorld() && update)
  12164. {
  12165. pItem->AddToWorld();
  12166. pItem->SendUpdateToPlayer(this);
  12167. }
  12168.  
  12169. pItem->SetState(ITEM_CHANGED, this);
  12170. if (pBag)
  12171. pBag->SetState(ITEM_CHANGED, this);
  12172.  
  12173. AddEnchantmentDurations(pItem);
  12174. AddItemDurations(pItem);
  12175.  
  12176.  
  12177. const ItemTemplate* proto = pItem->GetTemplate();
  12178. for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
  12179. if (proto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_NO_DELAY_USE && proto->Spells[i].SpellId > 0) // On obtain trigger
  12180. if (bag == INVENTORY_SLOT_BAG_0 || (bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END))
  12181. if (!HasAura(proto->Spells[i].SpellId))
  12182. CastSpell(this, proto->Spells[i].SpellId, true, pItem);
  12183.  
  12184. return pItem;
  12185. }
  12186. else
  12187. {
  12188. if (pItem2->GetTemplate()->Bonding == BIND_WHEN_PICKED_UP ||
  12189. pItem2->GetTemplate()->Bonding == BIND_QUEST_ITEM ||
  12190. (pItem2->GetTemplate()->Bonding == BIND_WHEN_EQUIPED && IsBagPos(pos)))
  12191. pItem2->SetBinding(true);
  12192.  
  12193. pItem2->SetCount(pItem2->GetCount() + count);
  12194. if (IsInWorld() && update)
  12195. pItem2->SendUpdateToPlayer(this);
  12196.  
  12197. if (!clone)
  12198. {
  12199. // delete item (it not in any slot currently)
  12200. if (IsInWorld() && update)
  12201. {
  12202. pItem->RemoveFromWorld();
  12203. pItem->DestroyForPlayer(this);
  12204. }
  12205.  
  12206. RemoveEnchantmentDurations(pItem);
  12207. RemoveItemDurations(pItem);
  12208.  
  12209. pItem->SetOwnerGUID(GetGUID()); // prevent error at next SetState in case trade/mail/buy from vendor
  12210. pItem->SetNotRefundable(this);
  12211. pItem->ClearSoulboundTradeable(this);
  12212. RemoveTradeableItem(pItem);
  12213. pItem->SetState(ITEM_REMOVED, this);
  12214. }
  12215.  
  12216. AddEnchantmentDurations(pItem2);
  12217.  
  12218. pItem2->SetState(ITEM_CHANGED, this);
  12219.  
  12220. const ItemTemplate* proto = pItem2->GetTemplate();
  12221. for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
  12222. if (proto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_NO_DELAY_USE && proto->Spells[i].SpellId > 0) // On obtain trigger
  12223. if (bag == INVENTORY_SLOT_BAG_0 || (bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END))
  12224. if (!HasAura(proto->Spells[i].SpellId))
  12225. CastSpell(this, proto->Spells[i].SpellId, true, pItem2);
  12226.  
  12227. return pItem2;
  12228. }
  12229. }
  12230.  
  12231. Item* Player::EquipNewItem(uint16 pos, uint32 item, bool update)
  12232. {
  12233. if (Item* pItem = Item::CreateItem(item, 1, this))
  12234. {
  12235. ItemAddedQuestCheck(item, 1);
  12236. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM, item, 1);
  12237. return EquipItem(pos, pItem, update);
  12238. }
  12239.  
  12240. return NULL;
  12241. }
  12242.  
  12243. Item* Player::EquipItem(uint16 pos, Item* pItem, bool update)
  12244. {
  12245. AddEnchantmentDurations(pItem);
  12246. AddItemDurations(pItem);
  12247.  
  12248. uint8 bag = pos >> 8;
  12249. uint8 slot = pos & 255;
  12250.  
  12251. Item* pItem2 = GetItemByPos(bag, slot);
  12252.  
  12253. if (!pItem2)
  12254. {
  12255. VisualizeItem(slot, pItem);
  12256.  
  12257. if (isAlive())
  12258. {
  12259. ItemTemplate const* pProto = pItem->GetTemplate();
  12260.  
  12261. // item set bonuses applied only at equip and removed at unequip, and still active for broken items
  12262. if (pProto && pProto->ItemSet)
  12263. AddItemsSetItem(this, pItem);
  12264.  
  12265. _ApplyItemMods(pItem, slot, true);
  12266.  
  12267. if (pProto && isInCombat() && (pProto->Class == ITEM_CLASS_WEAPON || pProto->InventoryType == INVTYPE_RELIC) && m_weaponChangeTimer == 0)
  12268. {
  12269. uint32 cooldownSpell = getClass() == CLASS_ROGUE ? 6123 : 6119;
  12270. SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cooldownSpell);
  12271.  
  12272. if (!spellProto)
  12273. sLog->outError(LOG_FILTER_PLAYER, "Weapon switch cooldown spell %u couldn't be found in Spell.dbc", cooldownSpell);
  12274. else
  12275. {
  12276. m_weaponChangeTimer = spellProto->StartRecoveryTime;
  12277.  
  12278. GetGlobalCooldownMgr().AddGlobalCooldown(spellProto, m_weaponChangeTimer);
  12279.  
  12280. WorldPacket data(SMSG_SPELL_COOLDOWN, 8+1+4);
  12281. data << uint64(GetGUID());
  12282. data << uint8(1);
  12283. data << uint32(cooldownSpell);
  12284. data << uint32(0);
  12285. GetSession()->SendPacket(&data);
  12286. }
  12287. }
  12288. }
  12289.  
  12290. if (IsInWorld() && update)
  12291. {
  12292. pItem->AddToWorld();
  12293. pItem->SendUpdateToPlayer(this);
  12294. }
  12295.  
  12296. ApplyEquipCooldown(pItem);
  12297.  
  12298. // update expertise and armor penetration - passive auras may need it
  12299.  
  12300. if (slot == EQUIPMENT_SLOT_MAINHAND)
  12301. UpdateExpertise(BASE_ATTACK);
  12302.  
  12303. else if (slot == EQUIPMENT_SLOT_OFFHAND)
  12304. UpdateExpertise(OFF_ATTACK);
  12305.  
  12306. switch (slot)
  12307. {
  12308. case EQUIPMENT_SLOT_MAINHAND:
  12309. case EQUIPMENT_SLOT_OFFHAND:
  12310. case EQUIPMENT_SLOT_RANGED:
  12311. RecalculateRating(CR_ARMOR_PENETRATION);
  12312. default:
  12313. break;
  12314. }
  12315. }
  12316. else
  12317. {
  12318. pItem2->SetCount(pItem2->GetCount() + pItem->GetCount());
  12319. if (IsInWorld() && update)
  12320. pItem2->SendUpdateToPlayer(this);
  12321.  
  12322. // delete item (it not in any slot currently)
  12323. //pItem->DeleteFromDB();
  12324. if (IsInWorld() && update)
  12325. {
  12326. pItem->RemoveFromWorld();
  12327. pItem->DestroyForPlayer(this);
  12328. }
  12329.  
  12330. RemoveEnchantmentDurations(pItem);
  12331. RemoveItemDurations(pItem);
  12332.  
  12333. pItem->SetOwnerGUID(GetGUID()); // prevent error at next SetState in case trade/mail/buy from vendor
  12334. pItem->SetNotRefundable(this);
  12335. pItem->ClearSoulboundTradeable(this);
  12336. RemoveTradeableItem(pItem);
  12337. pItem->SetState(ITEM_REMOVED, this);
  12338. pItem2->SetState(ITEM_CHANGED, this);
  12339.  
  12340. ApplyEquipCooldown(pItem2);
  12341.  
  12342. return pItem2;
  12343. }
  12344.  
  12345. // only for full equip instead adding to stack
  12346. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM, pItem->GetEntry());
  12347. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM, pItem->GetEntry(), slot);
  12348.  
  12349. TransmogEngine::SetTransmogDisplay(this, slot);
  12350. return pItem;
  12351. }
  12352.  
  12353. void Player::QuickEquipItem(uint16 pos, Item* pItem)
  12354. {
  12355. if (pItem)
  12356. {
  12357. AddEnchantmentDurations(pItem);
  12358. AddItemDurations(pItem);
  12359.  
  12360. uint8 slot = pos & 255;
  12361. VisualizeItem(slot, pItem);
  12362.  
  12363. if (IsInWorld())
  12364. {
  12365. pItem->AddToWorld();
  12366. pItem->SendUpdateToPlayer(this);
  12367. }
  12368.  
  12369. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM, pItem->GetEntry());
  12370. GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM, pItem->GetEntry(), slot);
  12371. }
  12372. }
  12373.  
  12374. void Player::SetVisibleItemSlot(uint8 slot, Item* pItem)
  12375. {
  12376. if (pItem)
  12377. {
  12378. SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENTRYID + (slot * 2), pItem->GetEntry());
  12379. SetUInt16Value(PLAYER_VISIBLE_ITEM_1_ENCHANTMENT + (slot * 2), 0, pItem->GetEnchantmentId(PERM_ENCHANTMENT_SLOT));
  12380. SetUInt16Value(PLAYER_VISIBLE_ITEM_1_ENCHANTMENT + (slot * 2), 1, pItem->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT));
  12381. }
  12382. else
  12383. {
  12384. SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENTRYID + (slot * 2), 0);
  12385. SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENCHANTMENT + (slot * 2), 0);
  12386. }
  12387. }
  12388.  
  12389. void Player::VisualizeItem(uint8 slot, Item* pItem)
  12390. {
  12391. if (!pItem)
  12392. return;
  12393.  
  12394. // check also BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory)
  12395. if (pItem->GetTemplate()->Bonding == BIND_WHEN_EQUIPED || pItem->GetTemplate()->Bonding == BIND_WHEN_PICKED_UP || pItem->GetTemplate()->Bonding == BIND_QUEST_ITEM)
  12396. pItem->SetBinding(true);
  12397.  
  12398. sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "STORAGE: EquipItem slot = %u, item = %u", slot, pItem->GetEntry());
  12399.  
  12400. m_items[slot] = pItem;
  12401. SetUInt64Value(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2), pItem->GetGUID());
  12402. pItem->SetUInt64Value(ITEM_FIELD_CONTAINED, GetGUID());
  12403. pItem->SetUInt64Value(ITEM_FIELD_OWNER, GetGUID());
  12404. pItem->SetSlot(slot);
  12405. pItem->SetContainer(NULL);
  12406.  
  12407. if (slot < EQUIPMENT_SLOT_END)
  12408. SetVisibleItemSlot(slot, pItem);
  12409.  
  12410. pItem->SetState(ITEM_CHANGED, this);
  12411. }
  12412.  
  12413. void Player::RemoveItem(uint8 bag, uint8 slot, bool update)
  12414. {
  12415. // note: removeitem does not actually change the item
  12416. // it only takes the item out of storage temporarily
  12417. // note2: if removeitem is to be used for delinking
  12418. // the item must be removed from the player's updatequeue
  12419.  
  12420. Item* pItem = GetItemByPos(bag, slot);
  12421. if (pItem)
  12422. {
  12423. TransmogEngine::RemoveTransmogDB(slot);
  12424. sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "STORAGE: RemoveItem bag = %u, slot = %u, item = %u", bag, slot, pItem->GetEntry());
  12425.  
  12426. RemoveEnchantmentDurations(pItem);
  12427. RemoveItemDurations(pItem);
  12428. RemoveTradeableItem(pItem);
  12429.  
  12430. if (bag == INVENTORY_SLOT_BAG_0)
  12431. {
  12432. if (slot < INVENTORY_SLOT_BAG_END)
  12433. {
  12434. ItemTemplate const* pProto = pItem->GetTemplate();
  12435. // item set bonuses applied only at equip and removed at unequip, and still active for broken items
  12436.  
  12437. if (pProto && pProto->ItemSet)
  12438. RemoveItemsSetItem(this, pProto);
  12439.  
  12440. _ApplyItemMods(pItem, slot, false);
  12441.  
  12442. // remove item dependent auras and casts (only weapon and armor slots)
  12443. if (slot < EQUIPMENT_SLOT_END)
  12444. {
  12445. RemoveItemDependentAurasAndCasts(pItem);
  12446.  
  12447. // remove held enchantments, update expertise
  12448. if (slot == EQUIPMENT_SLOT_MAINHAND)
  12449. {
  12450. if (pItem->GetItemSuffixFactor())
  12451. {
  12452. pItem->ClearEnchantment(PROP_ENCHANTMENT_SLOT_3);
  12453. pItem->ClearEnchantment(PROP_ENCHANTMENT_SLOT_4);
  12454. }
  12455. else
  12456. {
  12457. pItem->ClearEnchantment(PROP_ENCHANTMENT_SLOT_0);
  12458. pItem->ClearEnchantment(PROP_ENCHANTMENT_SLOT_1);
  12459. }
  12460.  
  12461. UpdateExpertise(BASE_ATTACK);
  12462. }
  12463. else if (slot == EQUIPMENT_SLOT_OFFHAND)
  12464. UpdateExpertise(OFF_ATTACK);
  12465. // update armor penetration - passive auras may need it
  12466. switch (slot)
  12467. {
  12468. case EQUIPMENT_SLOT_MAINHAND:
  12469. case EQUIPMENT_SLOT_OFFHAND:
  12470. case EQUIPMENT_SLOT_RANGED:
  12471. RecalculateRating(CR_ARMOR_PENETRATION);
  12472. default:
  12473. break;
  12474. }
  12475. }
  12476. }
  12477.  
  12478. m_items[slot] = NULL;
  12479. SetUInt64Value(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2), 0);
  12480.  
  12481. if (slot < EQUIPMENT_SLOT_END)
  12482. SetVisibleItemSlot(slot, NULL);
  12483. }
  12484. else if (Bag* pBag = GetBagByPos(bag))
  12485. pBag->RemoveItem(slot, update);
  12486.  
  12487. pItem->SetUInt64Value(ITEM_FIELD_CONTAINED, 0);
  12488. // pItem->SetUInt64Value(ITEM_FIELD_OWNER, 0); not clear owner at remove (it will be set at store). This used in mail and auction code
  12489. pItem->SetSlot(NULL_SLOT);
  12490. if (IsInWorld() && update)
  12491. pItem->SendUpdateToPlayer(this);
  12492. }
  12493. }
  12494.  
  12495. // Common operation need to remove item from inventory without delete in trade, auction, guild bank, mail....
  12496. void Player::MoveItemFromInventory(uint8 bag, uint8 slot, bool update)
  12497. {
  12498. if (Item* it = GetItemByPos(bag, slot))
  12499. {
  12500. ItemRemovedQuestCheck(it->GetEntry(), it->GetCount());
  12501. RemoveItem(bag, slot, update);
  12502. it->SetNotRefundable(this, false);
  12503. it->RemoveFromUpdateQueueOf(this);
  12504. if (it->IsInWorld())
  12505. {
  12506. it->RemoveFromWorld();
  12507. it->DestroyForPlayer(this);
  12508. }
  12509. }
  12510. }
Add Comment
Please, Sign In to add comment