PageRenderTime 67ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 3ms

/src/server/game/Entities/Player/Player.cpp

https://gitlab.com/IlluminatiCore/IlluminatiCore
C++ | 13435 lines | 10334 code | 2050 blank | 1051 comment | 3369 complexity | 52a59747d8ad70a97d9fdd1dc2962043 MD5 | raw file
Possible License(s): GPL-2.0, BSD-2-Clause

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (C) 2008-2014 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. #include "Player.h"
  19. #include "AccountMgr.h"
  20. #include "AchievementMgr.h"
  21. #include "ArenaTeam.h"
  22. #include "ArenaTeamMgr.h"
  23. #include "Battlefield.h"
  24. #include "BattlefieldMgr.h"
  25. #include "BattlefieldWG.h"
  26. #include "Battleground.h"
  27. #include "BattlegroundMgr.h"
  28. #include "BattlegroundScore.h"
  29. #include "CellImpl.h"
  30. #include "Channel.h"
  31. #include "ChannelMgr.h"
  32. #include "CharacterDatabaseCleaner.h"
  33. #include "Chat.h"
  34. #include "Common.h"
  35. #include "ConditionMgr.h"
  36. #include "CreatureAI.h"
  37. #include "DatabaseEnv.h"
  38. #include "DB2Stores.h"
  39. #include "DisableMgr.h"
  40. #include "Formulas.h"
  41. #include "GameEventMgr.h"
  42. #include "GossipDef.h"
  43. #include "GridNotifiers.h"
  44. #include "GridNotifiersImpl.h"
  45. #include "Group.h"
  46. #include "GroupMgr.h"
  47. #include "Guild.h"
  48. #include "GuildMgr.h"
  49. #include "InstanceSaveMgr.h"
  50. #include "InstanceScript.h"
  51. #include "LFGMgr.h"
  52. #include "Language.h"
  53. #include "Log.h"
  54. #include "MapInstanced.h"
  55. #include "MapManager.h"
  56. #include "ObjectAccessor.h"
  57. #include "ObjectMgr.h"
  58. #include "Opcodes.h"
  59. #include "OutdoorPvP.h"
  60. #include "OutdoorPvPMgr.h"
  61. #include "Pet.h"
  62. #include "QuestDef.h"
  63. #include "ReputationMgr.h"
  64. #include "revision.h"
  65. #include "SkillDiscovery.h"
  66. #include "SocialMgr.h"
  67. #include "Spell.h"
  68. #include "SpellAuraEffects.h"
  69. #include "SpellAuras.h"
  70. #include "SpellMgr.h"
  71. #include "Transport.h"
  72. #include "UpdateData.h"
  73. #include "UpdateFieldFlags.h"
  74. #include "UpdateMask.h"
  75. #include "Util.h"
  76. #include "Vehicle.h"
  77. #include "Weather.h"
  78. #include "WeatherMgr.h"
  79. #include "World.h"
  80. #include "WorldPacket.h"
  81. #include "WorldSession.h"
  82. #include "MovementStructures.h"
  83. #include "GameObjectAI.h"
  84. #define ZONE_UPDATE_INTERVAL (1*IN_MILLISECONDS)
  85. enum CharacterFlags
  86. {
  87. CHARACTER_FLAG_NONE = 0x00000000,
  88. CHARACTER_FLAG_UNK1 = 0x00000001,
  89. CHARACTER_FLAG_UNK2 = 0x00000002,
  90. CHARACTER_LOCKED_FOR_TRANSFER = 0x00000004,
  91. CHARACTER_FLAG_UNK4 = 0x00000008,
  92. CHARACTER_FLAG_UNK5 = 0x00000010,
  93. CHARACTER_FLAG_UNK6 = 0x00000020,
  94. CHARACTER_FLAG_UNK7 = 0x00000040,
  95. CHARACTER_FLAG_UNK8 = 0x00000080,
  96. CHARACTER_FLAG_UNK9 = 0x00000100,
  97. CHARACTER_FLAG_UNK10 = 0x00000200,
  98. CHARACTER_FLAG_HIDE_HELM = 0x00000400,
  99. CHARACTER_FLAG_HIDE_CLOAK = 0x00000800,
  100. CHARACTER_FLAG_UNK13 = 0x00001000,
  101. CHARACTER_FLAG_GHOST = 0x00002000,
  102. CHARACTER_FLAG_RENAME = 0x00004000,
  103. CHARACTER_FLAG_UNK16 = 0x00008000,
  104. CHARACTER_FLAG_UNK17 = 0x00010000,
  105. CHARACTER_FLAG_UNK18 = 0x00020000,
  106. CHARACTER_FLAG_UNK19 = 0x00040000,
  107. CHARACTER_FLAG_UNK20 = 0x00080000,
  108. CHARACTER_FLAG_UNK21 = 0x00100000,
  109. CHARACTER_FLAG_UNK22 = 0x00200000,
  110. CHARACTER_FLAG_UNK23 = 0x00400000,
  111. CHARACTER_FLAG_UNK24 = 0x00800000,
  112. CHARACTER_FLAG_LOCKED_BY_BILLING = 0x01000000,
  113. CHARACTER_FLAG_DECLINED = 0x02000000,
  114. CHARACTER_FLAG_UNK27 = 0x04000000,
  115. CHARACTER_FLAG_UNK28 = 0x08000000,
  116. CHARACTER_FLAG_UNK29 = 0x10000000,
  117. CHARACTER_FLAG_UNK30 = 0x20000000,
  118. CHARACTER_FLAG_UNK31 = 0x40000000,
  119. CHARACTER_FLAG_UNK32 = 0x80000000
  120. };
  121. enum CharacterCustomizeFlags
  122. {
  123. CHAR_CUSTOMIZE_FLAG_NONE = 0x00000000,
  124. CHAR_CUSTOMIZE_FLAG_CUSTOMIZE = 0x00000001, // name, gender, etc...
  125. CHAR_CUSTOMIZE_FLAG_FACTION = 0x00010000, // name, gender, faction, etc...
  126. CHAR_CUSTOMIZE_FLAG_RACE = 0x00100000 // name, gender, race, etc...
  127. };
  128. // corpse reclaim times
  129. #define DEATH_EXPIRE_STEP (5*MINUTE)
  130. #define MAX_DEATH_COUNT 3
  131. static uint32 copseReclaimDelay[MAX_DEATH_COUNT] = { 30, 60, 120 };
  132. uint32 const MasterySpells[MAX_CLASSES] =
  133. {
  134. 0,
  135. 87500, // Warrior
  136. 87494, // Paladin
  137. 87493, // Hunter
  138. 87496, // Rogue
  139. 87495, // Priest
  140. 87492, // Death Knight
  141. 87497, // Shaman
  142. 86467, // Mage
  143. 87498, // Warlock
  144. 0,
  145. 87491, // Druid
  146. };
  147. uint64 const MAX_MONEY_AMOUNT = 9999999999ULL;
  148. // == PlayerTaxi ================================================
  149. PlayerTaxi::PlayerTaxi()
  150. {
  151. memset(m_taximask, 0, sizeof(m_taximask));
  152. }
  153. void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level)
  154. {
  155. // class specific initial known nodes
  156. switch (chrClass)
  157. {
  158. case CLASS_DEATH_KNIGHT:
  159. {
  160. for (uint8 i = 0; i < TaxiMaskSize; ++i)
  161. m_taximask[i] |= sOldContinentsNodesMask[i];
  162. break;
  163. }
  164. }
  165. // race specific initial known nodes: capital and taxi hub masks
  166. switch (race)
  167. {
  168. case RACE_HUMAN: SetTaximaskNode(2); break; // Human
  169. case RACE_ORC: SetTaximaskNode(23); break; // Orc
  170. case RACE_DWARF: SetTaximaskNode(6); break; // Dwarf
  171. case RACE_NIGHTELF: SetTaximaskNode(26);
  172. SetTaximaskNode(27); break; // Night Elf
  173. case RACE_UNDEAD_PLAYER: SetTaximaskNode(11); break;// Undead
  174. case RACE_TAUREN: SetTaximaskNode(22); break; // Tauren
  175. case RACE_GNOME: SetTaximaskNode(6); break; // Gnome
  176. case RACE_TROLL: SetTaximaskNode(23); break; // Troll
  177. case RACE_BLOODELF: SetTaximaskNode(82); break; // Blood Elf
  178. case RACE_DRAENEI: SetTaximaskNode(94); break; // Draenei
  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. void PlayerTaxi::LoadTaxiMask(std::string const &data)
  191. {
  192. Tokenizer tokens(data, ' ');
  193. uint8 index = 0;
  194. for (Tokenizer::const_iterator iter = tokens.begin(); index < TaxiMaskSize && iter != tokens.end(); ++iter, ++index)
  195. {
  196. // load and set bits only for existing taxi nodes
  197. m_taximask[index] = sTaxiNodesMask[index] & uint32(atol(*iter));
  198. }
  199. }
  200. void PlayerTaxi::AppendTaximaskTo(ByteBuffer& data, bool all)
  201. {
  202. data << uint32(TaxiMaskSize);
  203. if (all)
  204. {
  205. for (uint8 i = 0; i < TaxiMaskSize; ++i)
  206. data << uint8(sTaxiNodesMask[i]); // all existed nodes
  207. }
  208. else
  209. {
  210. for (uint8 i = 0; i < TaxiMaskSize; ++i)
  211. data << uint8(m_taximask[i]); // known nodes
  212. }
  213. }
  214. bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, uint32 team)
  215. {
  216. ClearTaxiDestinations();
  217. Tokenizer Tokenizer(values, ' ');
  218. for (Tokenizer::const_iterator iter = Tokenizer.begin(); iter != Tokenizer.end(); ++iter)
  219. {
  220. uint32 node = uint32(atol(*iter));
  221. AddTaxiDestination(node);
  222. }
  223. if (m_TaxiDestinations.empty())
  224. return true;
  225. // Check integrity
  226. if (m_TaxiDestinations.size() < 2)
  227. return false;
  228. for (size_t i = 1; i < m_TaxiDestinations.size(); ++i)
  229. {
  230. uint32 cost;
  231. uint32 path;
  232. sObjectMgr->GetTaxiPath(m_TaxiDestinations[i-1], m_TaxiDestinations[i], path, cost);
  233. if (!path)
  234. return false;
  235. }
  236. // can't load taxi path without mount set (quest taxi path?)
  237. if (!sObjectMgr->GetTaxiMountDisplayId(GetTaxiSource(), team, true))
  238. return false;
  239. return true;
  240. }
  241. std::string PlayerTaxi::SaveTaxiDestinationsToString()
  242. {
  243. if (m_TaxiDestinations.empty())
  244. return "";
  245. std::ostringstream ss;
  246. for (size_t i=0; i < m_TaxiDestinations.size(); ++i)
  247. ss << m_TaxiDestinations[i] << ' ';
  248. return ss.str();
  249. }
  250. uint32 PlayerTaxi::GetCurrentTaxiPath() const
  251. {
  252. if (m_TaxiDestinations.size() < 2)
  253. return 0;
  254. uint32 path;
  255. uint32 cost;
  256. sObjectMgr->GetTaxiPath(m_TaxiDestinations[0], m_TaxiDestinations[1], path, cost);
  257. return path;
  258. }
  259. std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi)
  260. {
  261. for (uint8 i = 0; i < TaxiMaskSize; ++i)
  262. ss << uint32(taxi.m_taximask[i]) << ' ';
  263. return ss;
  264. }
  265. //== TradeData =================================================
  266. TradeData* TradeData::GetTraderData() const
  267. {
  268. return m_trader->GetTradeData();
  269. }
  270. Item* TradeData::GetItem(TradeSlots slot) const
  271. {
  272. return m_items[slot] ? m_player->GetItemByGuid(m_items[slot]) : NULL;
  273. }
  274. bool TradeData::HasItem(ObjectGuid itemGuid) const
  275. {
  276. for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i)
  277. if (m_items[i] == itemGuid)
  278. return true;
  279. return false;
  280. }
  281. TradeSlots TradeData::GetTradeSlotForItem(ObjectGuid itemGuid) const
  282. {
  283. for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i)
  284. if (m_items[i] == itemGuid)
  285. return TradeSlots(i);
  286. return TRADE_SLOT_INVALID;
  287. }
  288. Item* TradeData::GetSpellCastItem() const
  289. {
  290. return m_spellCastItem ? m_player->GetItemByGuid(m_spellCastItem) : NULL;
  291. }
  292. void TradeData::SetItem(TradeSlots slot, Item* item)
  293. {
  294. ObjectGuid itemGuid;
  295. if (item)
  296. itemGuid = item->GetGUID();
  297. if (m_items[slot] == itemGuid)
  298. return;
  299. m_items[slot] = itemGuid;
  300. SetAccepted(false);
  301. GetTraderData()->SetAccepted(false);
  302. Update();
  303. // need remove possible trader spell applied to changed item
  304. if (slot == TRADE_SLOT_NONTRADED)
  305. GetTraderData()->SetSpell(0);
  306. // need remove possible player spell applied (possible move reagent)
  307. SetSpell(0);
  308. }
  309. void TradeData::SetSpell(uint32 spell_id, Item* castItem /*= NULL*/)
  310. {
  311. ObjectGuid itemGuid = castItem ? castItem->GetGUID() : ObjectGuid::Empty;
  312. if (m_spell == spell_id && m_spellCastItem == itemGuid)
  313. return;
  314. m_spell = spell_id;
  315. m_spellCastItem = itemGuid;
  316. SetAccepted(false);
  317. GetTraderData()->SetAccepted(false);
  318. Update(true); // send spell info to item owner
  319. Update(false); // send spell info to caster self
  320. }
  321. void TradeData::SetMoney(uint64 money)
  322. {
  323. if (m_money == money)
  324. return;
  325. if (!m_player->HasEnoughMoney(money))
  326. {
  327. TradeStatusInfo info;
  328. info.Status = TRADE_STATUS_CLOSE_WINDOW;
  329. info.Result = EQUIP_ERR_NOT_ENOUGH_MONEY;
  330. m_player->GetSession()->SendTradeStatus(info);
  331. return;
  332. }
  333. m_money = money;
  334. SetAccepted(false);
  335. GetTraderData()->SetAccepted(false);
  336. Update(true);
  337. }
  338. void TradeData::Update(bool forTarget /*= true*/)
  339. {
  340. if (forTarget)
  341. m_trader->GetSession()->SendUpdateTrade(true); // player state for trader
  342. else
  343. m_player->GetSession()->SendUpdateTrade(false); // player state for player
  344. }
  345. void TradeData::SetAccepted(bool state, bool crosssend /*= false*/)
  346. {
  347. m_accepted = state;
  348. if (!state)
  349. {
  350. TradeStatusInfo info;
  351. info.Status = TRADE_STATUS_BACK_TO_TRADE;
  352. if (crosssend)
  353. m_trader->GetSession()->SendTradeStatus(info);
  354. else
  355. m_player->GetSession()->SendTradeStatus(info);
  356. }
  357. }
  358. // == KillRewarder ====================================================
  359. // KillRewarder incapsulates logic of rewarding player upon kill with:
  360. // * XP;
  361. // * honor;
  362. // * reputation;
  363. // * kill credit (for quest objectives).
  364. // Rewarding is initiated in two cases: when player kills unit in Unit::Kill()
  365. // and on battlegrounds in Battleground::RewardXPAtKill().
  366. //
  367. // Rewarding algorithm is:
  368. // 1. Initialize internal variables to default values.
  369. // 2. In case when player is in group, initialize variables necessary for group calculations:
  370. // 2.1. _count - number of alive group members within reward distance;
  371. // 2.2. _sumLevel - sum of levels of alive group members within reward distance;
  372. // 2.3. _maxLevel - maximum level of alive group member within reward distance;
  373. // 2.4. _maxNotGrayMember - maximum level of alive group member within reward distance,
  374. // for whom victim is not gray;
  375. // 2.5. _isFullXP - flag identifying that for all group members victim is not gray,
  376. // so 100% XP will be rewarded (50% otherwise).
  377. // 3. Reward killer (and group, if necessary).
  378. // 3.1. If killer is in group, reward group.
  379. // 3.1.1. Initialize initial XP amount based on maximum level of group member,
  380. // for whom victim is not gray.
  381. // 3.1.2. Alter group rate if group is in raid (not for battlegrounds).
  382. // 3.1.3. Reward each group member (even dead) within reward distance (see 4. for more details).
  383. // 3.2. Reward single killer (not group case).
  384. // 3.2.1. Initialize initial XP amount based on killer's level.
  385. // 3.2.2. Reward killer (see 4. for more details).
  386. // 4. Reward player.
  387. // 4.1. Give honor (player must be alive and not on BG).
  388. // 4.2. Give XP.
  389. // 4.2.1. If player is in group, adjust XP:
  390. // * set to 0 if player's level is more than maximum level of not gray member;
  391. // * cut XP in half if _isFullXP is false.
  392. // 4.2.2. Apply auras modifying rewarded XP.
  393. // 4.2.3. Give XP to player.
  394. // 4.2.4. If player has pet, reward pet with XP (100% for single player, 50% for group case).
  395. // 4.3. Give reputation (player must not be on BG).
  396. // 4.4. Give kill credit (player must not be in group, or he must be alive or without corpse).
  397. // 5. Credit instance encounter.
  398. // 6. Update guild achievements.
  399. KillRewarder::KillRewarder(Player* killer, Unit* victim, bool isBattleGround) :
  400. // 1. Initialize internal variables to default values.
  401. _killer(killer), _victim(victim), _group(killer->GetGroup()),
  402. _groupRate(1.0f), _maxNotGrayMember(NULL), _count(0), _sumLevel(0), _xp(0),
  403. _isFullXP(false), _maxLevel(0), _isBattleGround(isBattleGround), _isPvP(false)
  404. {
  405. // mark the credit as pvp if victim is player
  406. if (victim->GetTypeId() == TYPEID_PLAYER)
  407. _isPvP = true;
  408. // or if its owned by player and its not a vehicle
  409. else if (victim->GetCharmerOrOwnerGUID().IsPlayer())
  410. _isPvP = !victim->IsVehicle();
  411. _InitGroupData();
  412. }
  413. inline void KillRewarder::_InitGroupData()
  414. {
  415. if (_group)
  416. {
  417. // 2. In case when player is in group, initialize variables necessary for group calculations:
  418. for (GroupReference* itr = _group->GetFirstMember(); itr != NULL; itr = itr->next())
  419. if (Player* member = itr->GetSource())
  420. if (member->IsAlive() && member->IsAtGroupRewardDistance(_victim))
  421. {
  422. const uint8 lvl = member->getLevel();
  423. // 2.1. _count - number of alive group members within reward distance;
  424. ++_count;
  425. // 2.2. _sumLevel - sum of levels of alive group members within reward distance;
  426. _sumLevel += lvl;
  427. // 2.3. _maxLevel - maximum level of alive group member within reward distance;
  428. if (_maxLevel < lvl)
  429. _maxLevel = lvl;
  430. // 2.4. _maxNotGrayMember - maximum level of alive group member within reward distance,
  431. // for whom victim is not gray;
  432. uint32 grayLevel = Trinity::XP::GetGrayLevel(lvl);
  433. if (_victim->getLevel() > grayLevel && (!_maxNotGrayMember || _maxNotGrayMember->getLevel() < lvl))
  434. _maxNotGrayMember = member;
  435. }
  436. // 2.5. _isFullXP - flag identifying that for all group members victim is not gray,
  437. // so 100% XP will be rewarded (50% otherwise).
  438. _isFullXP = _maxNotGrayMember && (_maxLevel == _maxNotGrayMember->getLevel());
  439. }
  440. else
  441. _count = 1;
  442. }
  443. inline void KillRewarder::_InitXP(Player* player)
  444. {
  445. // Get initial value of XP for kill.
  446. // XP is given:
  447. // * on battlegrounds;
  448. // * otherwise, not in PvP;
  449. // * not if killer is on vehicle.
  450. if (_isBattleGround || (!_isPvP && !_killer->GetVehicle()))
  451. _xp = Trinity::XP::Gain(player, _victim);
  452. }
  453. inline void KillRewarder::_RewardHonor(Player* player)
  454. {
  455. // Rewarded player must be alive.
  456. if (player->IsAlive())
  457. player->RewardHonor(_victim, _count, -1, true);
  458. }
  459. inline void KillRewarder::_RewardXP(Player* player, float rate)
  460. {
  461. uint32 xp(_xp);
  462. if (_group)
  463. {
  464. // 4.2.1. If player is in group, adjust XP:
  465. // * set to 0 if player's level is more than maximum level of not gray member;
  466. // * cut XP in half if _isFullXP is false.
  467. if (_maxNotGrayMember && player->IsAlive() &&
  468. _maxNotGrayMember->getLevel() >= player->getLevel())
  469. xp = _isFullXP ?
  470. uint32(xp * rate) : // Reward FULL XP if all group members are not gray.
  471. uint32(xp * rate / 2) + 1; // Reward only HALF of XP if some of group members are gray.
  472. else
  473. xp = 0;
  474. }
  475. if (xp)
  476. {
  477. // 4.2.2. Apply auras modifying rewarded XP (SPELL_AURA_MOD_XP_PCT).
  478. Unit::AuraEffectList const& auras = player->GetAuraEffectsByType(SPELL_AURA_MOD_XP_PCT);
  479. for (Unit::AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
  480. AddPct(xp, (*i)->GetAmount());
  481. // 4.2.3. Calculate expansion penalty
  482. if (_victim->GetTypeId() == TYPEID_UNIT && player->getLevel() >= GetMaxLevelForExpansion(_victim->ToCreature()->GetCreatureTemplate()->expansion))
  483. xp = CalculatePct(xp, 10); // Players get only 10% xp for killing creatures of lower expansion levels than himself
  484. // 4.2.4. Give XP to player.
  485. player->GiveXP(xp, _victim, _groupRate);
  486. if (Pet* pet = player->GetPet())
  487. // 4.2.5. If player has pet, reward pet with XP (100% for single player, 50% for group case).
  488. pet->GivePetXP(_group ? xp / 2 : xp);
  489. }
  490. }
  491. inline void KillRewarder::_RewardReputation(Player* player, float rate)
  492. {
  493. // 4.3. Give reputation (player must not be on BG).
  494. // Even dead players and corpses are rewarded.
  495. player->RewardReputation(_victim, rate);
  496. }
  497. inline void KillRewarder::_RewardKillCredit(Player* player)
  498. {
  499. // 4.4. Give kill credit (player must not be in group, or he must be alive or without corpse).
  500. if (!_group || player->IsAlive() || !player->GetCorpse())
  501. if (Creature* target = _victim->ToCreature())
  502. {
  503. player->KilledMonster(target->GetCreatureTemplate(), target->GetGUID());
  504. player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE, target->GetCreatureType(), 1, 0, target);
  505. }
  506. }
  507. void KillRewarder::_RewardPlayer(Player* player, bool isDungeon)
  508. {
  509. // 4. Reward player.
  510. if (!_isBattleGround)
  511. {
  512. // 4.1. Give honor (player must be alive and not on BG).
  513. _RewardHonor(player);
  514. // 4.1.1 Send player killcredit for quests with PlayerSlain
  515. if (_victim->GetTypeId() == TYPEID_PLAYER)
  516. player->KilledPlayerCredit();
  517. }
  518. // Give XP only in PvE or in battlegrounds.
  519. // Give reputation and kill credit only in PvE.
  520. if (!_isPvP || _isBattleGround)
  521. {
  522. const float rate = _group ?
  523. _groupRate * float(player->getLevel()) / _sumLevel : // Group rate depends on summary level.
  524. 1.0f; // Personal rate is 100%.
  525. if (_xp)
  526. // 4.2. Give XP.
  527. _RewardXP(player, rate);
  528. if (!_isBattleGround)
  529. {
  530. // If killer is in dungeon then all members receive full reputation at kill.
  531. _RewardReputation(player, isDungeon ? 1.0f : rate);
  532. _RewardKillCredit(player);
  533. }
  534. }
  535. }
  536. void KillRewarder::_RewardGroup()
  537. {
  538. if (_maxLevel)
  539. {
  540. if (_maxNotGrayMember)
  541. // 3.1.1. Initialize initial XP amount based on maximum level of group member,
  542. // for whom victim is not gray.
  543. _InitXP(_maxNotGrayMember);
  544. // To avoid unnecessary calculations and calls,
  545. // proceed only if XP is not ZERO or player is not on battleground
  546. // (battleground rewards only XP, that's why).
  547. if (!_isBattleGround || _xp)
  548. {
  549. const bool isDungeon = !_isPvP && sMapStore.LookupEntry(_killer->GetMapId())->IsDungeon();
  550. if (!_isBattleGround)
  551. {
  552. // 3.1.2. Alter group rate if group is in raid (not for battlegrounds).
  553. const bool isRaid = !_isPvP && sMapStore.LookupEntry(_killer->GetMapId())->IsRaid() && _group->isRaidGroup();
  554. _groupRate = Trinity::XP::xp_in_group_rate(_count, isRaid);
  555. }
  556. // 3.1.3. Reward each group member (even dead or corpse) within reward distance.
  557. for (GroupReference* itr = _group->GetFirstMember(); itr != NULL; itr = itr->next())
  558. {
  559. if (Player* member = itr->GetSource())
  560. {
  561. if (member->IsAtGroupRewardDistance(_victim))
  562. {
  563. _RewardPlayer(member, isDungeon);
  564. member->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL, 1, 0, 0, _victim);
  565. }
  566. }
  567. }
  568. }
  569. }
  570. }
  571. void KillRewarder::Reward()
  572. {
  573. // 3. Reward killer (and group, if necessary).
  574. if (_group)
  575. // 3.1. If killer is in group, reward group.
  576. _RewardGroup();
  577. else
  578. {
  579. // 3.2. Reward single killer (not group case).
  580. // 3.2.1. Initialize initial XP amount based on killer's level.
  581. _InitXP(_killer);
  582. // To avoid unnecessary calculations and calls,
  583. // proceed only if XP is not ZERO or player is not on battleground
  584. // (battleground rewards only XP, that's why).
  585. if (!_isBattleGround || _xp)
  586. // 3.2.2. Reward killer.
  587. _RewardPlayer(_killer, false);
  588. }
  589. // 5. Credit instance encounter.
  590. // 6. Update guild achievements.
  591. if (Creature* victim = _victim->ToCreature())
  592. {
  593. if (victim->IsDungeonBoss())
  594. if (InstanceScript* instance = _victim->GetInstanceScript())
  595. instance->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, _victim->GetEntry(), _victim);
  596. if (uint32 guildId = victim->GetMap()->GetOwnerGuildId())
  597. if (Guild* guild = sGuildMgr->GetGuildById(guildId))
  598. guild->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, victim->GetEntry(), 1, 0, victim, _killer);
  599. }
  600. }
  601. Player::Player(WorldSession* session): Unit(true)
  602. {
  603. m_speakTime = 0;
  604. m_speakCount = 0;
  605. m_objectType |= TYPEMASK_PLAYER;
  606. m_objectTypeId = TYPEID_PLAYER;
  607. m_valuesCount = PLAYER_END;
  608. m_session = session;
  609. m_ingametime = 0;
  610. m_ExtraFlags = 0;
  611. m_spellModTakingSpell = NULL;
  612. //m_pad = 0;
  613. // players always accept
  614. if (!GetSession()->HasPermission(rbac::RBAC_PERM_CAN_FILTER_WHISPERS))
  615. SetAcceptWhispers(true);
  616. m_comboPoints = 0;
  617. m_regenTimer = 0;
  618. m_regenTimerCount = 0;
  619. m_holyPowerRegenTimerCount = 0;
  620. m_focusRegenTimerCount = 0;
  621. m_weaponChangeTimer = 0;
  622. m_zoneUpdateId = uint32(-1);
  623. m_zoneUpdateTimer = 0;
  624. m_areaUpdateId = 0;
  625. m_team = 0;
  626. m_needsZoneUpdate = false;
  627. m_nextSave = sWorld->getIntConfig(CONFIG_INTERVAL_SAVE);
  628. _resurrectionData = NULL;
  629. memset(m_items, 0, sizeof(Item*)*PLAYER_SLOTS_COUNT);
  630. m_social = NULL;
  631. // group is initialized in the reference constructor
  632. SetGroupInvite(NULL);
  633. m_groupUpdateMask = 0;
  634. m_auraRaidUpdateMask = 0;
  635. m_bPassOnGroupLoot = false;
  636. duel = NULL;
  637. m_GuildIdInvited = 0;
  638. m_ArenaTeamIdInvited = 0;
  639. m_atLoginFlags = AT_LOGIN_NONE;
  640. mSemaphoreTeleport_Near = false;
  641. mSemaphoreTeleport_Far = false;
  642. m_DelayedOperations = 0;
  643. m_bCanDelayTeleport = false;
  644. m_bHasDelayedTeleport = false;
  645. m_teleport_options = 0;
  646. m_trade = NULL;
  647. m_cinematic = 0;
  648. PlayerTalkClass = new PlayerMenu(GetSession());
  649. m_currentBuybackSlot = BUYBACK_SLOT_START;
  650. m_DailyQuestChanged = false;
  651. m_lastDailyQuestTime = 0;
  652. // Init rune flags
  653. for (uint8 i = 0; i < MAX_RUNES; ++i)
  654. {
  655. SetRuneTimer(i, 0xFFFFFFFF);
  656. SetLastRuneGraceTimer(i, 0);
  657. }
  658. for (uint8 i=0; i < MAX_TIMERS; i++)
  659. m_MirrorTimer[i] = DISABLED_MIRROR_TIMER;
  660. m_MirrorTimerFlags = UNDERWATER_NONE;
  661. m_MirrorTimerFlagsLast = UNDERWATER_NONE;
  662. m_isInWater = false;
  663. m_drunkTimer = 0;
  664. m_restTime = 0;
  665. m_deathTimer = 0;
  666. m_deathExpireTime = 0;
  667. m_swingErrorMsg = 0;
  668. for (uint8 j = 0; j < PLAYER_MAX_BATTLEGROUND_QUEUES; ++j)
  669. {
  670. m_bgBattlegroundQueueID[j].bgQueueTypeId = BATTLEGROUND_QUEUE_NONE;
  671. m_bgBattlegroundQueueID[j].invitedToInstance = 0;
  672. }
  673. m_logintime = time(NULL);
  674. m_Last_tick = m_logintime;
  675. m_Played_time[PLAYED_TIME_TOTAL] = 0;
  676. m_Played_time[PLAYED_TIME_LEVEL] = 0;
  677. m_WeaponProficiency = 0;
  678. m_ArmorProficiency = 0;
  679. m_canParry = false;
  680. m_canBlock = false;
  681. m_canTitanGrip = false;
  682. m_temporaryUnsummonedPetNumber = 0;
  683. //cache for UNIT_CREATED_BY_SPELL to allow
  684. //returning reagents for temporarily removed pets
  685. //when dying/logging out
  686. m_oldpetspell = 0;
  687. m_lastpetnumber = 0;
  688. ////////////////////Rest System/////////////////////
  689. time_inn_enter = 0;
  690. inn_pos_mapid = 0;
  691. inn_pos_x = 0.0f;
  692. inn_pos_y = 0.0f;
  693. inn_pos_z = 0.0f;
  694. m_rest_bonus = 0;
  695. rest_type = REST_TYPE_NO;
  696. ////////////////////Rest System/////////////////////
  697. m_mailsLoaded = false;
  698. m_mailsUpdated = false;
  699. unReadMails = 0;
  700. m_nextMailDelivereTime = 0;
  701. m_itemUpdateQueueBlocked = false;
  702. for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
  703. m_forced_speed_changes[i] = 0;
  704. m_stableSlots = 0;
  705. /////////////////// Instance System /////////////////////
  706. m_HomebindTimer = 0;
  707. m_InstanceValid = true;
  708. m_dungeonDifficulty = DUNGEON_DIFFICULTY_NORMAL;
  709. m_raidDifficulty = RAID_DIFFICULTY_10MAN_NORMAL;
  710. m_raidMapDifficulty = RAID_DIFFICULTY_10MAN_NORMAL;
  711. m_lastPotionId = 0;
  712. _talentMgr = new PlayerTalentInfo();
  713. for (uint8 i = 0; i < BASEMOD_END; ++i)
  714. {
  715. m_auraBaseMod[i][FLAT_MOD] = 0.0f;
  716. m_auraBaseMod[i][PCT_MOD] = 1.0f;
  717. }
  718. for (uint8 i = 0; i < MAX_COMBAT_RATING; i++)
  719. m_baseRatingValue[i] = 0;
  720. m_baseSpellPower = 0;
  721. m_baseManaRegen = 0;
  722. m_baseHealthRegen = 0;
  723. m_spellPenetrationItemMod = 0;
  724. // Honor System
  725. m_lastHonorUpdateTime = time(NULL);
  726. m_IsBGRandomWinner = false;
  727. // Player summoning
  728. m_summon_expire = 0;
  729. m_summon_mapid = 0;
  730. m_summon_x = 0.0f;
  731. m_summon_y = 0.0f;
  732. m_summon_z = 0.0f;
  733. m_mover = this;
  734. m_movedPlayer = this;
  735. m_seer = this;
  736. m_recallMap = 0;
  737. m_recallX = 0;
  738. m_recallY = 0;
  739. m_recallZ = 0;
  740. m_recallO = 0;
  741. m_homebindMapId = 0;
  742. m_homebindAreaId = 0;
  743. m_homebindX = 0;
  744. m_homebindY = 0;
  745. m_homebindZ = 0;
  746. m_contestedPvPTimer = 0;
  747. m_declinedname = NULL;
  748. m_isActive = true;
  749. m_runes = NULL;
  750. m_lastFallTime = 0;
  751. m_lastFallZ = 0;
  752. m_grantableLevels = 0;
  753. m_ControlledByPlayer = true;
  754. sWorld->IncreasePlayerCount();
  755. m_ChampioningFaction = 0;
  756. m_timeSyncTimer = 0;
  757. m_timeSyncClient = 0;
  758. m_timeSyncServer = 0;
  759. for (uint8 i = 0; i < MAX_POWERS_PER_CLASS; ++i)
  760. m_powerFraction[i] = 0;
  761. isDebugAreaTriggers = false;
  762. m_WeeklyQuestChanged = false;
  763. m_MonthlyQuestChanged = false;
  764. m_SeasonalQuestChanged = false;
  765. SetPendingBind(0, 0);
  766. _activeCheats = CHEAT_NONE;
  767. _maxPersonalArenaRate = 0;
  768. memset(_voidStorageItems, 0, VOID_STORAGE_MAX_SLOT * sizeof(VoidStorageItem*));
  769. memset(_CUFProfiles, 0, MAX_CUF_PROFILES * sizeof(CUFProfile*));
  770. m_achievementMgr = new AchievementMgr<Player>(this);
  771. m_reputationMgr = new ReputationMgr(this);
  772. }
  773. Player::~Player()
  774. {
  775. // it must be unloaded already in PlayerLogout and accessed only for loggined player
  776. //m_social = NULL;
  777. // Note: buy back item already deleted from DB when player was saved
  778. for (uint8 i = 0; i < PLAYER_SLOTS_COUNT; ++i)
  779. delete m_items[i];
  780. for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
  781. delete itr->second;
  782. delete _talentMgr;
  783. //all mailed items should be deleted, also all mail should be deallocated
  784. for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr)
  785. delete *itr;
  786. for (ItemMap::iterator iter = mMitems.begin(); iter != mMitems.end(); ++iter)
  787. delete iter->second; //if item is duplicated... then server may crash ... but that item should be deallocated
  788. delete PlayerTalkClass;
  789. for (size_t x = 0; x < ItemSetEff.size(); x++)
  790. delete ItemSetEff[x];
  791. delete m_declinedname;
  792. delete m_runes;
  793. delete m_achievementMgr;
  794. delete m_reputationMgr;
  795. for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i)
  796. delete _voidStorageItems[i];
  797. for (uint8 i = 0; i < MAX_CUF_PROFILES; ++i)
  798. delete _CUFProfiles[i];
  799. ClearResurrectRequestData();
  800. sWorld->DecreasePlayerCount();
  801. }
  802. void Player::CleanupsBeforeDelete(bool finalCleanup)
  803. {
  804. TradeCancel(false);
  805. DuelComplete(DUEL_INTERRUPTED);
  806. Unit::CleanupsBeforeDelete(finalCleanup);
  807. // clean up player-instance binds, may unload some instance saves
  808. for (uint8 i = 0; i < MAX_DIFFICULTY; ++i)
  809. for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
  810. itr->second.save->RemovePlayer(this);
  811. }
  812. bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo)
  813. {
  814. //FIXME: outfitId not used in player creating
  815. /// @todo need more checks against packet modifications
  816. // should check that skin, face, hair* are valid via DBC per race/class
  817. // also do it in Player::BuildEnumData, Player::LoadFromDB
  818. Object::_Create(guidlow, 0, HIGHGUID_PLAYER);
  819. m_name = createInfo->Name;
  820. PlayerInfo const* info = sObjectMgr->GetPlayerInfo(createInfo->Race, createInfo->Class);
  821. if (!info)
  822. {
  823. TC_LOG_ERROR("entities.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.",
  824. GetSession()->GetAccountId(), m_name.c_str(), createInfo->Race, createInfo->Class);
  825. return false;
  826. }
  827. for (uint8 i = 0; i < PLAYER_SLOTS_COUNT; i++)
  828. m_items[i] = NULL;
  829. Relocate(info->positionX, info->positionY, info->positionZ, info->orientation);
  830. ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(createInfo->Class);
  831. if (!cEntry)
  832. {
  833. TC_LOG_ERROR("entities.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?)",
  834. GetSession()->GetAccountId(), m_name.c_str(), createInfo->Class);
  835. return false;
  836. }
  837. SetMap(sMapMgr->CreateMap(info->mapId, this));
  838. uint8 powertype = cEntry->powerType;
  839. SetObjectScale(1.0f);
  840. setFactionForRace(createInfo->Race);
  841. if (!IsValidGender(createInfo->Gender))
  842. {
  843. TC_LOG_ERROR("entities.player", "Player::Create: Possible hacking-attempt: Account %u tried creating a character named '%s' with an invalid gender (%u) - refusing to do so",
  844. GetSession()->GetAccountId(), m_name.c_str(), createInfo->Gender);
  845. return false;
  846. }
  847. uint32 RaceClassGender = (createInfo->Race) | (createInfo->Class << 8) | (createInfo->Gender << 16);
  848. SetUInt32Value(UNIT_FIELD_BYTES_0, (RaceClassGender | (powertype << 24)));
  849. InitDisplayIds();
  850. if (sWorld->getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_PVP || sWorld->getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_RPPVP)
  851. {
  852. SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP);
  853. SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
  854. }
  855. SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER);
  856. SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 1.0f); // default for players in 3.0.3
  857. SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, uint32(-1)); // -1 is default value
  858. SetUInt32Value(PLAYER_BYTES, (createInfo->Skin | (createInfo->Face << 8) | (createInfo->HairStyle << 16) | (createInfo->HairColor << 24)));
  859. SetUInt32Value(PLAYER_BYTES_2, (createInfo->FacialHair |
  860. (0x00 << 8) |
  861. (0x00 << 16) |
  862. (((GetSession()->IsARecruiter() || GetSession()->GetRecruiterId() != 0) ? REST_STATE_RAF_LINKED : REST_STATE_NOT_RAF_LINKED) << 24)));
  863. SetByteValue(PLAYER_BYTES_3, 0, createInfo->Gender);
  864. SetByteValue(PLAYER_BYTES_3, 3, 0); // BattlefieldArenaFaction (0 or 1)
  865. SetUInt64Value(OBJECT_FIELD_DATA, 0);
  866. SetUInt32Value(PLAYER_GUILDRANK, 0);
  867. SetGuildLevel(0);
  868. SetUInt32Value(PLAYER_GUILD_TIMESTAMP, 0);
  869. for (int i = 0; i < KNOWN_TITLES_SIZE; ++i)
  870. SetUInt64Value(PLAYER__FIELD_KNOWN_TITLES + i, 0); // 0=disabled
  871. SetUInt32Value(PLAYER_CHOSEN_TITLE, 0);
  872. SetUInt32Value(PLAYER_FIELD_KILLS, 0);
  873. SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, 0);
  874. // set starting level
  875. uint32 start_level = getClass() != CLASS_DEATH_KNIGHT
  876. ? sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL)
  877. : sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL);
  878. if (m_session->HasPermission(rbac::RBAC_PERM_USE_START_GM_LEVEL))
  879. {
  880. uint32 gm_level = sWorld->getIntConfig(CONFIG_START_GM_LEVEL);
  881. if (gm_level > start_level)
  882. start_level = gm_level;
  883. }
  884. SetUInt32Value(UNIT_FIELD_LEVEL, start_level);
  885. InitRunes();
  886. SetUInt32Value(PLAYER_FIELD_COINAGE, sWorld->getIntConfig(CONFIG_START_PLAYER_MONEY));
  887. SetCurrency(CURRENCY_TYPE_HONOR_POINTS, sWorld->getIntConfig(CONFIG_CURRENCY_START_HONOR_POINTS));
  888. SetCurrency(CURRENCY_TYPE_JUSTICE_POINTS, sWorld->getIntConfig(CONFIG_CURRENCY_START_JUSTICE_POINTS));
  889. SetCurrency(CURRENCY_TYPE_CONQUEST_POINTS, sWorld->getIntConfig(CONFIG_CURRENCY_START_CONQUEST_POINTS));
  890. // start with every map explored
  891. if (sWorld->getBoolConfig(CONFIG_START_ALL_EXPLORED))
  892. {
  893. for (uint8 i=0; i<PLAYER_EXPLORED_ZONES_SIZE; i++)
  894. SetFlag(PLAYER_EXPLORED_ZONES_1+i, 0xFFFFFFFF);
  895. }
  896. //Reputations if "StartAllReputation" is enabled, -- @todo Fix this in a better way
  897. if (sWorld->getBoolConfig(CONFIG_START_ALL_REP))
  898. {
  899. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(942), 42999);
  900. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(935), 42999);
  901. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(936), 42999);
  902. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(1011), 42999);
  903. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(970), 42999);
  904. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(967), 42999);
  905. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(989), 42999);
  906. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(932), 42999);
  907. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(934), 42999);
  908. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(1038), 42999);
  909. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(1077), 42999);
  910. // Factions depending on team, like cities and some more stuff
  911. switch (GetTeam())
  912. {
  913. case ALLIANCE:
  914. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(72), 42999);
  915. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(47), 42999);
  916. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(69), 42999);
  917. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(930), 42999);
  918. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(730), 42999);
  919. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(978), 42999);
  920. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(54), 42999);
  921. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(946), 42999);
  922. break;
  923. case HORDE:
  924. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(76), 42999);
  925. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(68), 42999);
  926. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(81), 42999);
  927. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(911), 42999);
  928. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(729), 42999);
  929. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(941), 42999);
  930. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(530), 42999);
  931. GetReputationMgr().SetReputation(sFactionStore.LookupEntry(947), 42999);
  932. break;
  933. default:
  934. break;
  935. }
  936. }
  937. // Played time
  938. m_Last_tick = time(NULL);
  939. m_Played_time[PLAYED_TIME_TOTAL] = 0;
  940. m_Played_time[PLAYED_TIME_LEVEL] = 0;
  941. // base stats and related field values
  942. InitStatsForLevel();
  943. InitTaxiNodesForLevel();
  944. InitGlyphsForLevel();
  945. InitTalentForLevel();
  946. InitPrimaryProfessions(); // to max set before any spell added
  947. // apply original stats mods before spell loading or item equipment that call before equip _RemoveStatsMods()
  948. UpdateMaxHealth(); // Update max Health (for add bonus from stamina)
  949. SetFullHealth();
  950. if (getPowerType() == POWER_MANA)
  951. {
  952. UpdateMaxPower(POWER_MANA); // Update max Mana (for add bonus from intellect)
  953. SetPower(POWER_MANA, GetMaxPower(POWER_MANA));
  954. }
  955. if (getPowerType() == POWER_RUNIC_POWER)
  956. {
  957. SetPower(POWER_RUNES, 8);
  958. SetMaxPower(POWER_RUNES, 8);
  959. SetPower(POWER_RUNIC_POWER, 0);
  960. SetMaxPower(POWER_RUNIC_POWER, 1000);
  961. }
  962. // original spells
  963. LearnDefaultSkills();
  964. LearnCustomSpells();
  965. // original action bar
  966. for (PlayerCreateInfoActions::const_iterator action_itr = info->action.begin(); action_itr != info->action.end(); ++action_itr)
  967. addActionButton(action_itr->button, action_itr->action, action_itr->type);
  968. // original items
  969. if (CharStartOutfitEntry const* oEntry = GetCharStartOutfitEntry(createInfo->Race, createInfo->Class, createInfo->Gender))
  970. {
  971. for (int j = 0; j < MAX_OUTFIT_ITEMS; ++j)
  972. {
  973. if (oEntry->ItemId[j] <= 0)
  974. continue;
  975. uint32 itemId = oEntry->ItemId[j];
  976. // just skip, reported in ObjectMgr::LoadItemTemplates
  977. ItemTemplate const* iProto = sObjectMgr->GetItemTemplate(itemId);
  978. if (!iProto)
  979. continue;
  980. // BuyCount by default
  981. uint32 count = iProto->BuyCount;
  982. // special amount for food/drink
  983. if (iProto->Class == ITEM_CLASS_CONSUMABLE && iProto->SubClass == ITEM_SUBCLASS_FOOD_DRINK)
  984. {
  985. switch (iProto->Spells[0].SpellCategory)
  986. {
  987. case SPELL_CATEGORY_FOOD: // food
  988. count = getClass() == CLASS_DEATH_KNIGHT ? 10 : 4;
  989. break;
  990. case SPELL_CATEGORY_DRINK: // drink
  991. count = 2;
  992. break;
  993. }
  994. if (iProto->GetMaxStackSize() < count)
  995. count = iProto->GetMaxStackSize();
  996. }
  997. StoreNewItemInBestSlots(itemId, count);
  998. }
  999. }
  1000. for (PlayerCreateInfoItems::const_iterator item_id_itr = info->item.begin(); item_id_itr != info->item.end(); ++item_id_itr)
  1001. StoreNewItemInBestSlots(item_id_itr->item_id, item_id_itr->item_amount);
  1002. // bags and main-hand weapon must equipped at this moment
  1003. // now second pass for not equipped (offhand weapon/shield if it attempt equipped before main-hand weapon)
  1004. // or ammo not equipped in special bag
  1005. for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)
  1006. {
  1007. if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  1008. {
  1009. uint16 eDest;
  1010. // equip offhand weapon/shield if it attempt equipped before main-hand weapon
  1011. InventoryResult msg = CanEquipItem(NULL_SLOT, eDest, pItem, false);
  1012. if (msg == EQUIP_ERR_OK)
  1013. {
  1014. RemoveItem(INVENTORY_SLOT_BAG_0, i, true);
  1015. EquipItem(eDest, pItem, true);
  1016. }
  1017. // move other items to more appropriate slots
  1018. else
  1019. {
  1020. ItemPosCountVec sDest;
  1021. msg = CanStoreItem(NULL_BAG, NULL_SLOT, sDest, pItem, false);
  1022. if (msg == EQUIP_ERR_OK)
  1023. {
  1024. RemoveItem(INVENTORY_SLOT_BAG_0, i, true);
  1025. pItem = StoreItem(sDest, pItem, true);
  1026. }
  1027. }
  1028. }
  1029. }
  1030. // all item positions resolved
  1031. return true;
  1032. }
  1033. bool Player::StoreNewItemInBestSlots(uint32 titem_id, uint32 titem_amount)
  1034. {
  1035. TC_LOG_DEBUG("entities.player.items", "STORAGE: Creating initial item, itemId = %u, count = %u", titem_id, titem_amount);
  1036. // attempt equip by one
  1037. while (titem_amount > 0)
  1038. {
  1039. uint16 eDest;
  1040. InventoryResult msg = CanEquipNewItem(NULL_SLOT, eDest, titem_id, false);
  1041. if (msg != EQUIP_ERR_OK)
  1042. break;
  1043. EquipNewItem(eDest, titem_id, true);
  1044. AutoUnequipOffhandIfNeed();
  1045. --titem_amount;
  1046. }
  1047. if (titem_amount == 0)
  1048. return true; // equipped
  1049. // attempt store
  1050. ItemPosCountVec sDest;
  1051. // store in main bag to simplify second pass (special bags can be not equipped yet at this moment)
  1052. InventoryResult msg = CanStoreNewItem(INVENTORY_SLOT_BAG_0, NULL_SLOT, sDest, titem_id, titem_amount);
  1053. if (msg == EQUIP_ERR_OK)
  1054. {
  1055. StoreNewItem(sDest, titem_id, true, Item::GenerateItemRandomPropertyId(titem_id));
  1056. return true; // stored
  1057. }
  1058. // item can't be added
  1059. TC_LOG_ERROR("entities.player.items", "STORAGE: Can't equip or store initial item %u for race %u class %u, error msg = %u", titem_id, getRace(), getClass(), msg);
  1060. return false;
  1061. }
  1062. void Player::SendMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, int32 Regen)
  1063. {
  1064. if (int(MaxValue) == DISABLED_MIRROR_TIMER)
  1065. {
  1066. if (int(CurrentValue) != DISABLED_MIRROR_TIMER)
  1067. StopMirrorTimer(Type);
  1068. return;
  1069. }
  1070. WorldPacket data(SMSG_START_MIRROR_TIMER, (21));
  1071. data << (uint32)Type;
  1072. data << CurrentValue;
  1073. data << MaxValue;
  1074. data << Regen;
  1075. data << (uint8)0;
  1076. data << (uint32)0; // spell id
  1077. GetSession()->SendPacket(&data);
  1078. }
  1079. void Player::StopMirrorTimer(MirrorTimerType Type)
  1080. {
  1081. m_MirrorTimer[Type] = DISABLED_MIRROR_TIMER;
  1082. WorldPacket data(SMSG_STOP_MIRROR_TIMER, 4);
  1083. data << (uint32)Type;
  1084. GetSession()->SendPacket(&data);
  1085. }
  1086. bool Player::IsImmuneToEnvironmentalDamage()
  1087. {
  1088. // check for GM and death state included in isAttackableByAOE
  1089. return (!isTargetableForAttack(false));
  1090. }
  1091. uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage)
  1092. {
  1093. if (IsImmuneToEnvironmentalDamage())
  1094. return 0;
  1095. // Absorb, resist some environmental damage type
  1096. uint32 absorb = 0;
  1097. uint32 resist = 0;
  1098. if (type == DAMAGE_LAVA)
  1099. CalcAbsorbResist(this, SPELL_SCHOOL_MASK_FIRE, DIRECT_DAMAGE, damage, &absorb, &resist);
  1100. else if (type == DAMAGE_SLIME)
  1101. CalcAbsorbResist(this, SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE, damage, &absorb, &resist);
  1102. damage -= absorb + resist;
  1103. DealDamageMods(this, damage, &absorb);
  1104. WorldPacket data(SMSG_ENVIRONMENTALDAMAGELOG, (21));
  1105. data << uint64(GetGUID());
  1106. data << uint8(type != DAMAGE_FALL_TO_VOID ? type : DAMAGE_FALL);
  1107. data << uint32(damage);
  1108. data << uint32(absorb);
  1109. data << uint32(resist);
  1110. SendMessageToSet(&data, true);
  1111. uint32 final_damage = DealDamage(this, damage, NULL, SELF_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
  1112. if (!IsAlive())
  1113. {
  1114. if (type == DAMAGE_FALL) // DealDamage not apply item durability loss at self damage
  1115. {
  1116. TC_LOG_DEBUG("entities.player", "We are fall to death, loosing 10 percents durability");
  1117. DurabilityLossAll(0.10f, false);
  1118. // durability lost message
  1119. SendDurabilityLoss(this, 10);
  1120. }
  1121. UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM, 1, type);
  1122. }
  1123. return final_damage;
  1124. }
  1125. int32 Player::getMaxTimer(MirrorTimerType timer)
  1126. {
  1127. switch (timer)
  1128. {
  1129. case FATIGUE_TIMER:
  1130. return MINUTE * IN_MILLISECONDS;
  1131. case BREATH_TIMER:
  1132. {
  1133. if (!IsAlive() || HasAuraType(SPELL_AURA_WATER_BREATHING) || GetSession()->GetSecurity() >= AccountTypes(sWorld->getIntConfig(CONFIG_DISABLE_BREATHING)))
  1134. return DISABLED_MIRROR_TIMER;
  1135. int32 UnderWaterTime = 3 * MINUTE * IN_MILLISECONDS;
  1136. AuraEffectList const& mModWaterBreathing = GetAuraEffectsByType(SPELL_AURA_MOD_WATER_BREATHING);
  1137. for (AuraEffectList::const_iterator i = mModWaterBreathing.begin(); i != mModWaterBreathing.end(); ++i)
  1138. AddPct(UnderWaterTime, (*i)->GetAmount());
  1139. return UnderWaterTime;
  1140. }
  1141. case FIRE_TIMER:
  1142. {
  1143. if (!IsAlive())
  1144. return DISABLED_MIRROR_TIMER;
  1145. return 1 * IN_MILLISECONDS;
  1146. }
  1147. default:
  1148. return 0;
  1149. }
  1150. }
  1151. void Player::UpdateMirrorTimers()
  1152. {
  1153. // Desync flags for update on next HandleDrowning
  1154. if (m_MirrorTimerFlags)
  1155. m_MirrorTimerFlagsLast = ~m_MirrorTimerFlags;
  1156. }
  1157. void Player::StopMirrorTimers()
  1158. {
  1159. StopMirrorTimer(FATIGUE_TIMER);
  1160. StopMirrorTimer(BREATH_TIMER);
  1161. StopMirrorTimer(FIRE_TIMER);
  1162. }
  1163. bool Player::IsMirrorTimerActive(MirrorTimerType type)
  1164. {
  1165. return m_MirrorTimer[type] == getMaxTimer(type);
  1166. }
  1167. void Player::HandleDrowning(uint32 time_diff)
  1168. {
  1169. if (!m_MirrorTimerFlags)
  1170. return;
  1171. // In water
  1172. if (m_MirrorTimerFlags & UNDERWATER_INWATER)
  1173. {
  1174. // Breath timer not activated - activate it
  1175. if (m_MirrorTimer[BREATH_TIMER] == DISABLED_MIRROR_TIMER)
  1176. {
  1177. m_MirrorTimer[BREATH_TIMER] = getMaxTimer(BREATH_TIMER);
  1178. SendMirrorTimer(BREATH_TIMER, m_MirrorTimer[BREATH_TIMER], m_MirrorTimer[BREATH_TIMER], -1);
  1179. }
  1180. else // If activated - do tick
  1181. {
  1182. m_MirrorTimer[BREATH_TIMER]-=time_diff;
  1183. // Timer limit - need deal damage
  1184. if (m_MirrorTimer[BREATH_TIMER] < 0)
  1185. {
  1186. m_MirrorTimer[BREATH_TIMER]+= 1*IN_MILLISECONDS;
  1187. // Calculate and deal damage
  1188. /// @todo Check this formula
  1189. uint32 damage = GetMaxHealth() / 5 + urand(0, getLevel()-1);
  1190. EnvironmentalDamage(DAMAGE_DROWNING, damage);
  1191. }
  1192. else if (!(m_MirrorTimerFlagsLast & UNDERWATER_INWATER)) // Update time in client if need
  1193. SendMirrorTimer(BREATH_TIMER, getMaxTimer(BREATH_TIMER), m_MirrorTimer[BREATH_TIMER], -1);
  1194. }
  1195. }
  1196. else if (m_MirrorTimer[BREATH_TIMER] != DISABLED_MIRROR_TIMER) // Regen timer
  1197. {
  1198. int32 UnderWaterTime = getMaxTimer(BREATH_TIMER);
  1199. // Need breath regen
  1200. m_MirrorTimer[BREATH_TIMER]+=10*time_diff;
  1201. if (m_MirrorTimer[BREATH_TIMER] >= UnderWaterTime || !IsAlive())
  1202. StopMirrorTimer(BREATH_TIMER);
  1203. else if (m_MirrorTimerFlagsLast & UNDERWATER_INWATER)
  1204. SendMirrorTimer(BREATH_TIMER, UnderWaterTime, m_MirrorTimer[BREATH_TIMER], 10);
  1205. }
  1206. // In dark water
  1207. if (m_MirrorTimerFlags & UNDERWARER_INDARKWATER)
  1208. {
  1209. // Fatigue timer not activated - activate it
  1210. if (m_MirrorTimer[FATIGUE_TIMER] == DISABLED_MIRROR_TIMER)
  1211. {
  1212. m_MirrorTimer[FATIGUE_TIMER] = getMaxTimer(FATIGUE_TIMER);
  1213. SendMirrorTimer(FATIGUE_TIMER, m_MirrorTimer[FATIGUE_TIMER], m_MirrorTimer[FATIGUE_TIMER], -1);
  1214. }
  1215. else
  1216. {
  1217. m_MirrorTimer[FATIGUE_TIMER]-=time_diff;
  1218. // Timer limit - need deal damage or teleport ghost t…

Large files files are truncated, but you can click here to view the full file