Guest User

player.cpp

a guest
Mar 13th, 2013
51
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 365.66 KB | None | 0 0
  1. /*
  2.  * ArcEmu MMORPG Server
  3.  * Copyright (C) 2005-2007 Ascent Team <http://www.ascentemu.com/>
  4.  * Copyright (C) 2008-2012 <http://www.ArcEmu.org/>
  5.  *
  6.  * This program is free software: you can redistribute it and/or modify
  7.  * it under the terms of the GNU Affero General Public License as published by
  8.  * the Free Software Foundation, either version 3 of the License, or
  9.  * any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU Affero General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Affero General Public License
  17.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  *
  19.  */
  20.  
  21. #include "StdAfx.h"
  22. UpdateMask Player::m_visibleUpdateMask;
  23. #define COLLISION_INDOOR_CHECK_INTERVAL 1000
  24. #define CANNON 24933 //39692, 34154
  25. #define MORTAR 25003 //33861 -- Triggers Explosion, 39695 --- Summons Mortar
  26. #define NITROUS 27746 //Needs Scripting
  27. #define FLAMETHROWER 39693 //25027
  28. #define MACHINEGUN 25026
  29. #define DROPMINE 25024
  30. #define SHIELD 27759
  31. static uint32 TonkSpecials[4] = {FLAMETHROWER, MACHINEGUN, DROPMINE, SHIELD};
  32.  
  33. //   0x3F = 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 for 80 level
  34. //          minor|Major |minor |Major |minor |Major
  35. static const uint8 glyphMask[81] =
  36. {
  37.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //lvl 0-14, no glyphs
  38.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, //lvl 15-29, 1 Minor 1 Major
  39.     11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, //lvl 30-49, 1 Minor 2 Major
  40.     15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, //lvl 50-69, 2 Minor 2 Major
  41.     31, 31, 31, 31, 31, 31, 31, 31, 31, 31, //lvl 70-79, 3 Minor 2 Major
  42.     63 //lvl 80, 3 Minor 3 Major
  43. };
  44.  
  45. static const float crit_to_dodge[ MAX_PLAYER_CLASSES ] = {
  46.     0.0f,      // empty
  47.     1.1f,      // Warrior
  48.     1.0f,      // Paladin
  49.     1.6f,      // Hunter
  50.     2.0f,      // Rogue
  51.     1.0f,      // Priest
  52.     1.0f,      // DK?
  53.     1.0f,      // Shaman
  54.     1.0f,      // Mage
  55.     1.0f,      // Warlock
  56.     0.0f,      // empty
  57.     1.7f       // Druid
  58. };
  59.  
  60. Player::Player(uint32 guid)
  61.     :
  62.     disableAppear(false),
  63.     disableSummon(false),
  64.     taxi_model_id(0),
  65.     lastNode(0),
  66.     m_taxi_ride_time(0),
  67.     m_taxi_pos_x(0),
  68.     m_taxi_pos_y(0),
  69.     m_taxi_pos_z(0),
  70.     m_onTaxi(false),
  71.     m_questSharer(0),
  72.     pctReputationMod(0),
  73.     DuelingWith(NULL),
  74.     m_lootGuid(0),
  75.     m_currentLoot(0),
  76.     bShouldHaveLootableOnCorpse(false),
  77.     offhand_dmg_mod(0.5),
  78.     m_currentMovement(MOVE_UNROOT),
  79.     m_isMoving(false),
  80.     moving(false),
  81.     strafing(false),
  82.     jumping(false),
  83.     m_isGmInvisible(false),
  84.     SpellHasteRatingBonus(1.0f),
  85.     m_furorChance(0),
  86. //WayPoint
  87.     waypointunit(NULL),
  88.     m_nextSave(getMSTime() + sWorld.getIntRate(INTRATE_SAVE)),
  89.     m_lifetapbonus(0),
  90.     PlayerTalkClass(NULL),
  91.     m_bUnlimitedBreath(false),
  92.     m_UnderwaterTime(180000),
  93.     m_UnderwaterState(0),
  94.     m_AllowAreaTriggerPort(true),
  95. // Battleground
  96.     m_bg(NULL),
  97.     m_bgEntryPointMap(0),
  98.     m_bgEntryPointX(0),
  99.     m_bgEntryPointY(0),
  100.     m_bgEntryPointZ(0),
  101.     m_bgEntryPointO(0),
  102.     m_bgEntryPointInstance(0),
  103.     m_bgHasFlag(false),
  104.     m_bgIsQueued(false),
  105.     m_bgQueueType(0),
  106.     m_bgQueueInstanceId(0),
  107. // Autoshot variables
  108.     m_AutoShotDuration(0),
  109.     m_AutoShotAttackTimer(0),
  110.     m_onAutoShot(false),
  111.     m_AutoShotTarget(0),
  112.     m_AutoShotSpell(NULL),
  113.     DetectedRange(0),
  114.     PctIgnoreRegenModifier(0.0f),
  115.     m_retainedrage(0),
  116.     SoulStone(0),
  117.     SoulStoneReceiver(0),
  118.     misdirectionTarget(0),
  119.     bReincarnation(false),
  120.     ignoreShapeShiftChecks(false),
  121.     ignoreAuraStateCheck(false),
  122.     m_GM_SelectedGO(0),
  123.     m_ShapeShifted(0),
  124.     m_MountSpellId(0),
  125.     bHasBindDialogOpen(false),
  126.     TrackingSpell(0),
  127.     m_CurrentCharm(0),
  128.     m_CurrentTransporter(NULL),
  129. // gm stuff
  130. //m_invincible(false),
  131.     CooldownCheat(false),
  132.     CastTimeCheat(false),
  133.     GodModeCheat(false),
  134.     PowerCheat(false),
  135.     FlyCheat(false),
  136.     Lfgcomment(""),
  137.     LfmDungeonId(0),
  138.     LfmType(0),
  139.     m_Autojoin(false),
  140.     m_AutoAddMem(false),
  141.     m_UnderwaterMaxTime(180000),
  142.     m_UnderwaterLastDmg(getMSTime()),
  143.     m_resurrectHealth(0),
  144.     m_resurrectMana(0),
  145.     m_resurrectInstanceID(0),
  146.     m_resurrectMapId(0),
  147.     m_mailBox(guid),
  148.     m_finishingmovesdodge(false),
  149.     mUpdateCount(0),
  150.     mCreationCount(0),
  151.     mOutOfRangeIdCount(0),
  152. //Trade
  153.     mTradeTarget(0),
  154.     info(NULL), // Playercreate info
  155.     m_AttackMsgTimer(0),
  156. //PVP
  157. //PvPTimeoutEnabled(false),
  158.     m_banned(false),
  159.     m_Summons(),
  160.     m_PetNumberMax(0),
  161. //DK
  162.     m_invitersGuid(0),
  163. //Bind position
  164.     m_bind_pos_x(0),
  165.     m_bind_pos_y(0),
  166.     m_bind_pos_z(0),
  167.     m_bind_mapid(0),
  168.     m_bind_zoneid(0),
  169. //Duel
  170.     m_duelCountdownTimer(0),
  171.     m_duelStatus(0),
  172.     m_duelState(DUEL_STATE_FINISHED),       // finished
  173. // Rest
  174.     m_timeLogoff(0),
  175.     m_isResting(0),
  176.     m_restState(0),
  177.     m_restAmount(0),
  178. // Attack related variables
  179.     m_blockfromspellPCT(0),
  180.     m_critfromspell(0),
  181.     m_spellcritfromspell(0),
  182.     m_hitfromspell(0),
  183.     m_healthfromspell(0),
  184.     m_manafromspell(0),
  185.     m_healthfromitems(0),
  186.     m_manafromitems(0),
  187. //FIX for shit like shirt etc
  188.     armor_proficiency(1),
  189. //FIX for professions
  190.     weapon_proficiency(0x4000), //2^14
  191.     m_talentresettimes(0),
  192.     m_status(0),
  193.     m_curTarget(0),
  194.     m_curSelection(0),
  195.     m_targetIcon(0),
  196.     m_session(NULL),
  197.     m_GroupInviter(0),
  198.     m_SummonedObject(NULL),
  199.     myCorpseLocation()
  200. #ifdef ENABLE_ACHIEVEMENTS
  201.     , m_achievementMgr(this)
  202. #endif
  203. {
  204.     m_cache = new PlayerCache;
  205.     m_cache->SetUInt32Value(CACHE_PLAYER_LOWGUID, guid);
  206.     objmgr.AddPlayerCache(guid, m_cache);
  207.     int i, j;
  208.  
  209.     m_H_regenTimer = 0;
  210.     m_P_regenTimer = 0;
  211.     //////////////////////////////////////////////////////////////////////////
  212.  
  213.     //These should be set in the object constructor..
  214.     m_runSpeed = PLAYER_NORMAL_RUN_SPEED;
  215.     m_walkSpeed = 2.5f;
  216.     m_objectTypeId = TYPEID_PLAYER;
  217.     m_valuesCount = PLAYER_END;
  218.     //////////////////////////////////////////////////////////////////////////
  219.  
  220.     //Why is there a pointer to the same thing in a derived class? ToDo: sort this out..
  221.     m_uint32Values = _fields;
  222.  
  223.     memset(m_uint32Values, 0, (PLAYER_END) * sizeof(uint32));
  224.     m_updateMask.SetCount(PLAYER_END);
  225.     SetUInt32Value(OBJECT_FIELD_TYPE, TYPE_PLAYER | TYPE_UNIT | TYPE_OBJECT);
  226.     SetLowGUID(guid);
  227.     m_wowGuid.Init(GetGUID());
  228.     SetUInt32Value(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ENABLE_POWER_REGEN);
  229.     SetFloatValue(PLAYER_RUNE_REGEN_1, 0.100000f);
  230.     SetFloatValue(PLAYER_RUNE_REGEN_1 + 1, 0.100000f);
  231.     SetFloatValue(PLAYER_RUNE_REGEN_1 + 2, 0.100000f);
  232.     SetFloatValue(PLAYER_RUNE_REGEN_1 + 3, 0.100000f);
  233.  
  234.     for(i = 0; i < 3; i++)
  235.     {
  236.         LfgType[i] = 0;
  237.         LfgDungeonId[i] = 0;
  238.     }
  239.  
  240.     for(i = 0; i < 28; i++)
  241.     {
  242.         MechanicDurationPctMod[i] = 0;
  243.     }
  244.  
  245.     //Trade
  246.     ResetTradeVariables();
  247.  
  248.     //Tutorials
  249.     for(i = 0 ; i < 8 ; i++)
  250.         m_Tutorials[ i ] = 0x00;
  251.  
  252.     m_playedtime[0]      = 0;
  253.     m_playedtime[1]      = 0;
  254.     m_playedtime[2]      = (uint32)UNIXTIME;
  255.  
  256.     for(i = 0; i < 7; i++)
  257.     {
  258.         FlatResistanceModifierPos[i] = 0;
  259.         FlatResistanceModifierNeg[i] = 0;
  260.         BaseResistanceModPctPos[i] = 0;
  261.         BaseResistanceModPctNeg[i] = 0;
  262.         ResistanceModPctPos[i] = 0;
  263.         ResistanceModPctNeg[i] = 0;
  264.         SpellDelayResist[i] = 0;
  265.         m_casted_amount[i] = 0;
  266.     }
  267.  
  268.     for(i = 0; i < 5; i++)
  269.     {
  270.         for(j = 0; j < 7; j++)
  271.         {
  272.             SpellHealDoneByAttribute[i][j] = 0;
  273.         }
  274.  
  275.         FlatStatModPos[i] = 0;
  276.         FlatStatModNeg[i] = 0;
  277.         StatModPctPos[i] = 0;
  278.         StatModPctNeg[i] = 0;
  279.         TotalStatModPctPos[i] = 0;
  280.         TotalStatModPctNeg[i] = 0;
  281.     }
  282.  
  283.     for(i = 0; i < 12; i++)
  284.     {
  285.         IncreaseDamageByType[i] = 0;
  286.         IncreaseDamageByTypePCT[i] = 0;
  287.         IncreaseCricticalByTypePCT[i] = 0;
  288.     }
  289.  
  290.     bCreationBuffer.reserve(40000);
  291.     bUpdateBuffer.reserve(30000);//ought to be > than enough ;)
  292.     mOutOfRangeIds.reserve(1000);
  293.  
  294.  
  295.     bProcessPending      = false;
  296.     for(i = 0; i < 25; ++i)
  297.         m_questlog[i] = NULL;
  298.  
  299.     m_ItemInterface      = new ItemInterface(this);
  300.     CurrentGossipMenu      = NULL;
  301.  
  302.     SDetector =  new SpeedCheatDetector;
  303.  
  304.     cannibalize          = false;
  305.     mAvengingWrath       = true;
  306.     m_AreaID                = 0;
  307.     cannibalizeCount        = 0;
  308.     rageFromDamageDealt  = 0;
  309.     rageFromDamageTaken  = 0;
  310.  
  311.     m_honorToday            = 0;
  312.     m_honorYesterday        = 0;
  313.     m_honorPoints          = 0;
  314.     m_killsToday            = 0;
  315.     m_killsYesterday        = 0;
  316.     m_killsLifetime      = 0;
  317.     m_honorless          = 0;
  318.     m_lastSeenWeather      = 0;
  319.     m_attacking          = false;
  320.  
  321.     myCorpseInstanceId      = 0;
  322.     bCorpseCreateable      = true;
  323.     blinked              = false;
  324.     m_explorationTimer    = getMSTime();
  325.     linkTarget            = NULL;
  326.     AuraStackCheat           = false;
  327.     ItemStackCheat = false;
  328.     TriggerpassCheat = false;
  329.     m_pvpTimer            = 0;
  330.     m_globalCooldown = 0;
  331.     m_unstuckCooldown = 0;
  332.     m_lastHonorResetTime    = 0;
  333.     tutorialsDirty = true;
  334.     m_TeleportState = 1;
  335.     m_beingPushed = false;
  336.     for(i = 0; i < NUM_CHARTER_TYPES; ++i)
  337.         m_charters[i] = NULL;
  338.     for(i = 0; i < NUM_ARENA_TEAM_TYPES; ++i)
  339.         m_arenaTeams[i] = NULL;
  340.     flying_aura = 0;
  341.     resend_speed = false;
  342.     rename_pending = false;
  343.     DualWield2H = false;
  344.     iInstanceType       = 0;
  345.     m_RaidDifficulty    = 0;
  346.     m_XpGain = true;
  347.     resettalents = false;
  348.     memset(reputationByListId, 0, sizeof(FactionReputation*) * 128);
  349.  
  350.     m_comboTarget = 0;
  351.     m_comboPoints = 0;
  352.  
  353.     SetAttackPowerMultiplier(0.0f);
  354.     SetRangedAttackPowerMultiplier(0.0f);
  355.  
  356.     UpdateLastSpeeds();
  357.  
  358.     m_resist_critical[0] = m_resist_critical[1] = 0;
  359.     m_castFilterEnabled = false;
  360.  
  361.     for(i = 0; i < 3; i++)
  362.     {
  363.         m_attack_speed[i]   = 1.0f;
  364.         m_castFilter[i]     = 0;
  365.     }
  366.  
  367.     for(i = 0; i < SCHOOL_COUNT; i++)
  368.         m_resist_hit_spell[i] = 0;
  369.  
  370.     m_resist_hit[MOD_MELEE]     = 0.0f;
  371.     m_resist_hit[MOD_RANGED]    = 0.0f;
  372.  
  373.     m_maxTalentPoints = 0; //VLack: 3 Aspire values initialized
  374.     m_talentActiveSpec = 0;
  375.     m_talentSpecsCount = 1;
  376.     for(uint8 s = 0; s < MAX_SPEC_COUNT; ++s)
  377.     {
  378.         m_specs[s].talents.clear();
  379.         memset(m_specs[s].glyphs, 0, GLYPHS_COUNT * sizeof(uint16));
  380.         memset(m_specs[s].mActions, 0, PLAYER_ACTION_BUTTON_SIZE);
  381.     }
  382.  
  383.     m_drunkTimer = 0;
  384.     m_drunk = 0;
  385.  
  386.     ok_to_remove = false;
  387.     m_modphyscritdmgPCT = 0;
  388.     m_RootedCritChanceBonus = 0;
  389.     m_IncreaseDmgSnaredSlowed = 0;
  390.     m_ModInterrMRegenPCT = 0;
  391.     m_ModInterrMRegen = 0;
  392.     m_RegenManaOnSpellResist = 0;
  393.     m_rap_mod_pct = 0;//only initialized to 0: why?
  394.     m_modblockabsorbvalue = 0;
  395.     m_modblockvaluefromspells = 0;
  396.     m_summoner = m_summonInstanceId = m_summonMapId = 0;
  397.     m_spellcomboPoints = 0;
  398.     m_pendingBattleground = NULL;
  399.     m_deathVision = false;
  400.     m_resurrecter = 0;
  401.     m_retainComboPoints = false;
  402.     last_heal_spell = NULL;
  403.     m_playerInfo = NULL;
  404.     m_sentTeleportPosition.ChangeCoords(999999.0f, 999999.0f, 999999.0f);
  405.     m_speedChangeCounter = 1;
  406.     memset(&m_bgScore, 0, sizeof(BGScore));
  407.     m_base_runSpeed = m_runSpeed;
  408.     m_base_walkSpeed = m_walkSpeed;
  409.     m_arenateaminviteguid = 0;
  410.     m_arenaPoints = 0;
  411.     m_honorRolloverTime = 0;
  412.     hearth_of_wild_pct = 0;
  413.     raidgrouponlysent = false;
  414.     loot.gold = 0;
  415.     m_waterwalk = false;
  416.     m_setwaterwalk = false;
  417.     m_areaSpiritHealer_guid = 0;
  418.     m_CurrentTaxiPath = NULL;
  419.     m_setflycheat = false;
  420.     m_fallDisabledUntil = 0;
  421.     m_lfgMatch = NULL;
  422.     m_lfgInviterGuid = 0;
  423.     m_indoorCheckTimer = 0;
  424.     m_taxiMapChangeNode = 0;
  425.     this->OnLogin();
  426.  
  427. #ifdef ENABLE_COMPRESSED_MOVEMENT
  428.     m_movementBuffer.reserve(5000);
  429. #endif
  430.  
  431.     m_requiresNoAmmo = false;
  432.     m_KickDelay = 0;
  433.     m_passOnLoot = false;
  434.     m_changingMaps = true;
  435.     m_outStealthDamageBonusPct = m_outStealthDamageBonusPeriod = m_outStealthDamageBonusTimer = 0;
  436.     m_flyhackCheckTimer = 0;
  437. #ifdef TRACK_IMMUNITY_BUG
  438.     m_immunityTime = 0;
  439. #endif
  440.  
  441.     m_skills.clear();
  442.     m_wratings.clear();
  443.     m_taxiPaths.clear();
  444.     m_removequests.clear();
  445.     m_finishedQuests.clear();
  446.     m_finishedDailies.clear();
  447.     quest_spells.clear();
  448.     quest_mobs.clear();
  449.  
  450.     m_onStrikeSpells.clear();
  451.     m_onStrikeSpellDmg.clear();
  452.     mSpellOverrideMap.clear();
  453.     mSpells.clear();
  454.     mDeletedSpells.clear();
  455.     mShapeShiftSpells.clear();
  456.     m_Pets.clear();
  457.     m_itemsets.clear();
  458.     m_reputation.clear();
  459.     m_channels.clear();
  460.     m_visibleObjects.clear();
  461.     m_forcedReactions.clear();
  462.  
  463.     loginauras.clear();
  464.     damagedone.clear();
  465.     tocritchance.clear();
  466.     m_visibleFarsightObjects.clear();
  467.     SummonSpells.clear();
  468.     PetSpells.clear();
  469.     delayedPackets.clear();
  470.     _splineMap.clear();
  471.  
  472.     m_lastPotionId      = 0;
  473.     for(i = 0; i < NUM_COOLDOWN_TYPES; i++)
  474.     {
  475.         m_cooldownMap[i].clear();
  476.     }
  477. //  m_achievement_points = 0;
  478.  
  479.     ChampioningFactionID = 0;
  480.     mountvehicleid = 0;
  481. }
  482.  
  483. void Player::OnLogin()
  484. {
  485.  
  486. }
  487.  
  488.  
  489. Player::~Player()
  490. {
  491.     objmgr.RemovePlayerCache(GetLowGUID());
  492.     m_cache->DecRef();
  493.     m_cache = NULL;
  494.  
  495.     if(!ok_to_remove)
  496.     {
  497.         LOG_ERROR("Player deleted from non-logoutplayer!");
  498.         printStackTrace(); // Win32 Debug
  499.  
  500.         objmgr.RemovePlayer(this);
  501.     }
  502.  
  503.     if(m_session)
  504.     {
  505.         m_session->SetPlayer(0);
  506.         if(!ok_to_remove)
  507.             m_session->Disconnect();
  508.     }
  509.  
  510.     Player* pTarget;
  511.     if(mTradeTarget != 0)
  512.     {
  513.         pTarget = GetTradeTarget();
  514.         if(pTarget)
  515.             pTarget->mTradeTarget = 0;
  516.     }
  517.  
  518.     pTarget = objmgr.GetPlayer(GetInviter());
  519.     if(pTarget)
  520.         pTarget->SetInviter(0);
  521.  
  522.     DismissActivePets();
  523.     mTradeTarget = 0;
  524.  
  525.     if(DuelingWith != NULL)
  526.         DuelingWith->DuelingWith = NULL;
  527.     DuelingWith = NULL;
  528.  
  529.     CleanupGossipMenu();
  530.     ARCEMU_ASSERT(!IsInWorld());
  531.  
  532.     // delete m_talenttree
  533.  
  534.     CleanupChannels();
  535.     for(int i = 0; i < 25; ++i)
  536.     {
  537.         if(m_questlog[i] != NULL)
  538.         {
  539.             delete m_questlog[i];
  540.             m_questlog[i] = NULL;
  541.         }
  542.     }
  543.  
  544.     for(SplineMap::iterator itr = _splineMap.begin(); itr != _splineMap.end(); ++itr)
  545.         delete itr->second;
  546.     _splineMap.clear();
  547.  
  548.     delete m_ItemInterface;
  549.     m_ItemInterface = NULL;
  550.  
  551.     for(ReputationMap::iterator itr = m_reputation.begin(); itr != m_reputation.end(); ++itr)
  552.         delete itr->second;
  553.     m_reputation.clear();
  554.  
  555.     if(m_playerInfo)
  556.         m_playerInfo->m_loggedInPlayer = NULL;
  557.  
  558.     delete SDetector;
  559.     SDetector = NULL;
  560.  
  561.     while(delayedPackets.size())
  562.     {
  563.         WorldPacket* pck = delayedPackets.next();
  564.         delete pck;
  565.     }
  566.  
  567.     /*std::map<uint32,AchievementVal*>::iterator itr;
  568.     for(itr=m_achievements.begin();itr!=m_achievements.end();itr++)
  569.         delete itr->second;*/
  570.  
  571.     std::map< uint32, PlayerPet* >::iterator itr = m_Pets.begin();
  572.     for(; itr != m_Pets.end(); itr++)
  573.         delete itr->second;
  574.     m_Pets.clear();
  575.  
  576.     RemoveGarbageItems();
  577. }
  578.  
  579. uint32 GetSpellForLanguage(uint32 SkillID)
  580. {
  581.     switch(SkillID)
  582.     {
  583.         case SKILL_LANG_COMMON:
  584.             return 668;
  585.             break;
  586.  
  587.         case SKILL_LANG_ORCISH:
  588.             return 669;
  589.             break;
  590.  
  591.         case SKILL_LANG_TAURAHE:
  592.             return 670;
  593.             break;
  594.  
  595.         case SKILL_LANG_DARNASSIAN:
  596.             return 671;
  597.             break;
  598.  
  599.         case SKILL_LANG_DWARVEN:
  600.             return 672;
  601.             break;
  602.  
  603.         case SKILL_LANG_THALASSIAN:
  604.             return 813;
  605.             break;
  606.  
  607.         case SKILL_LANG_DRACONIC:
  608.             return 814;
  609.             break;
  610.  
  611.         case SKILL_LANG_DEMON_TONGUE:
  612.             return 815;
  613.             break;
  614.  
  615.         case SKILL_LANG_TITAN:
  616.             return 816;
  617.             break;
  618.  
  619.         case SKILL_LANG_OLD_TONGUE:
  620.             return 817;
  621.             break;
  622.  
  623.         case SKILL_LANG_GNOMISH:
  624.             return 7430;
  625.             break;
  626.  
  627.         case SKILL_LANG_TROLL:
  628.             return 7341;
  629.             break;
  630.  
  631.         case SKILL_LANG_GUTTERSPEAK:
  632.             return 17737;
  633.             break;
  634.  
  635.         case SKILL_LANG_DRAENEI:
  636.             return 29932;
  637.             break;
  638.     }
  639.  
  640.     return 0;
  641. }
  642.  
  643. ///====================================================================
  644. ///  Create
  645. ///  params: p_newChar
  646. ///  desc:   data from client to create a new character
  647. ///====================================================================
  648. bool Player::Create(WorldPacket & data)
  649. {
  650.     uint8 race, class_, gender, skin, face, hairStyle, hairColor, facialHair, outfitId;
  651.  
  652.     // unpack data into member variables
  653.     data >> m_name;
  654.  
  655.     // correct capitalization
  656.     CapitalizeString(m_name);
  657.  
  658.     data >> race >> class_ >> gender >> skin >> face;
  659.     data >> hairStyle >> hairColor >> facialHair >> outfitId;
  660.  
  661.     info = objmgr.GetPlayerCreateInfo(race, class_);
  662.     if(!info)
  663.     {
  664.         // info not found... disconnect
  665.         //sCheatLog.writefromsession(m_session, "tried to create invalid player with race %u and class %u", race, class_);
  666.         m_session->Disconnect();
  667.         // don't use Log.LargeErrorMessage() here, it doesn't handle %s %u in the string.
  668.         if(class_ == DEATHKNIGHT)
  669.             LOG_ERROR("Account Name: %s tried to create a deathknight, however your playercreateinfo table does not support this class, please update your database.", m_session->GetAccountName().c_str());
  670.         else
  671.             LOG_ERROR("Account Name: %s tried to create an invalid character with race %u and class %u, if this is intended please update your playercreateinfo table inside your database.", m_session->GetAccountName().c_str(), race, class_);
  672.         return false;
  673.     }
  674.  
  675.     // check that the account can create TBC characters, if we're making some
  676.     if( race >= RACE_BLOODELF && !(m_session->_accountFlags & ACCOUNT_FLAG_XPACK_01) )
  677.     {
  678.         m_session->Disconnect();
  679.         return false;
  680.     }
  681.    
  682.     // check that the account can create deathknights, if we're making one
  683.     if( class_ == DEATHKNIGHT && !(m_session->_accountFlags & ACCOUNT_FLAG_XPACK_02) )
  684.     {
  685.         m_session->Disconnect();
  686.         return false;
  687.     }
  688.  
  689.     m_mapId = info->mapId;
  690.     SetZoneId(info->zoneId);
  691.     m_position.ChangeCoords(info->positionX, info->positionY, info->positionZ);
  692.     m_bind_pos_x = info->positionX;
  693.     m_bind_pos_y = info->positionY;
  694.     m_bind_pos_z = info->positionZ;
  695.     m_bind_mapid = info->mapId;
  696.     m_bind_zoneid = info->zoneId;
  697.     m_isResting = 0;
  698.     m_restAmount = 0;
  699.     m_restState = 0;
  700.  
  701.     // set race dbc
  702.     myRace = dbcCharRace.LookupEntryForced(race);
  703.     myClass = dbcCharClass.LookupEntryForced(class_);
  704.     if(!myRace || !myClass)
  705.     {
  706.         // information not found
  707.         sCheatLog.writefromsession(m_session, "tried to create invalid player with race %u and class %u, dbc info not found", race, class_);
  708.         m_session->Disconnect();
  709.         return false;
  710.     }
  711.  
  712.     if(myRace->team_id == 7)
  713.         m_team = 0;
  714.     else
  715.         m_team = 1;
  716.     m_cache->SetUInt32Value(CACHE_PLAYER_INITIALTEAM, m_team);
  717.  
  718.     uint8 powertype = static_cast<uint8>(myClass->power_type);
  719.  
  720.     // Automatically add the race's taxi hub to the character's taximask at creation time ( 1 << (taxi_node_id-1) )
  721.     // this is defined in table playercreateinfo, field taximask
  722.     memcpy(m_taximask, info->taximask, sizeof(m_taximask));
  723.  
  724.     // Set Starting stats for char
  725.     //SetScale(  ((race==RACE_TAUREN)?1.3f:1.0f));
  726.     SetScale(1.0f);
  727.     SetHealth(info->health);
  728.     SetPower(POWER_TYPE_MANA, info->mana);
  729.     SetPower(POWER_TYPE_RAGE, 0);
  730.     SetPower(POWER_TYPE_FOCUS, info->focus); // focus
  731.     SetPower(POWER_TYPE_ENERGY, info->energy);
  732.     SetPower(POWER_TYPE_RUNES, 8);
  733.  
  734.     SetMaxHealth(info->health);
  735.     SetMaxPower(POWER_TYPE_MANA, info->mana);
  736.     SetMaxPower(POWER_TYPE_RAGE, info->rage);
  737.     SetMaxPower(POWER_TYPE_FOCUS, info->focus);
  738.     SetMaxPower(POWER_TYPE_ENERGY, info->energy);
  739.     SetMaxPower(POWER_TYPE_RUNES, 8);
  740.     SetMaxPower(POWER_TYPE_RUNIC_POWER, 1000);
  741.  
  742.     //THIS IS NEEDED
  743.     SetBaseHealth(info->health);
  744.     SetBaseMana(info->mana);
  745.     SetFaction(info->factiontemplate);
  746.  
  747.     if(class_ == DEATHKNIGHT)
  748.         SetTalentPointsForAllSpec(sWorld.DKStartTalentPoints); // Default is 0 in case you do not want to modify it
  749.     else
  750.         SetTalentPointsForAllSpec(0);
  751.     if(class_ != DEATHKNIGHT || sWorld.StartingLevel > 55)
  752.     {
  753.         setLevel(sWorld.StartingLevel);
  754.         if(sWorld.StartingLevel >= 10 && class_ != DEATHKNIGHT)
  755.             SetTalentPointsForAllSpec(sWorld.StartingLevel - 9);
  756.     }
  757.     else
  758.     {
  759.         setLevel(55);
  760.         SetNextLevelXp(148200);
  761.     }
  762.     UpdateGlyphs();
  763.  
  764.     SetPrimaryProfessionPoints(sWorld.MaxProfs);
  765.  
  766.     setRace(race);
  767.     setClass(class_);
  768.     setGender(gender);
  769.     SetPowerType(powertype);
  770.  
  771.     SetUInt32Value(UNIT_FIELD_BYTES_2, (U_FIELD_BYTES_FLAG_PVP << 8));
  772.  
  773.     if(class_ == WARRIOR)
  774.         SetShapeShift(FORM_BATTLESTANCE);
  775.  
  776.     SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
  777.     SetStat(STAT_STRENGTH, info->strength);
  778.     SetStat(STAT_AGILITY, info->ability);
  779.     SetStat(STAT_STAMINA, info->stamina);
  780.     SetStat(STAT_INTELLECT, info->intellect);
  781.     SetStat(STAT_SPIRIT, info->spirit);
  782.     SetBoundingRadius(0.388999998569489f);
  783.     SetCombatReach(1.5f);
  784.     if(race != RACE_BLOODELF)
  785.     {
  786.         SetDisplayId(info->displayId + gender);
  787.         SetNativeDisplayId(info->displayId + gender);
  788.     }
  789.     else
  790.     {
  791.         SetDisplayId(info->displayId - gender);
  792.         SetNativeDisplayId(info->displayId - gender);
  793.     }
  794.     EventModelChange();
  795.     //SetMinDamage(info->mindmg );
  796.     //SetMaxDamage(info->maxdmg );
  797.     SetAttackPower(info->attackpower);
  798.     SetUInt32Value(PLAYER_BYTES, ((skin) | (face << 8) | (hairStyle << 16) | (hairColor << 24)));
  799.     //PLAYER_BYTES_2                               GM ON/OFF     BANKBAGSLOTS   RESTEDSTATE
  800.     SetUInt32Value(PLAYER_BYTES_2, (facialHair /*| (0xEE << 8)*/  | (0x02 << 24)));//no bank slot by default!
  801.  
  802.     //PLAYER_BYTES_3                           DRUNKENSTATE              PVPRANK
  803.     SetUInt32Value(PLAYER_BYTES_3, ((gender) | (0x00 << 8) | (0x00 << 16) | (GetPVPRank() << 24)));
  804.     SetNextLevelXp(400);
  805.     SetUInt32Value(PLAYER_FIELD_BYTES, 0x08);
  806.     SetCastSpeedMod(1.0f);
  807.     SetUInt32Value(PLAYER_FIELD_MAX_LEVEL, sWorld.m_levelCap);
  808.  
  809.     // Gold Starting Amount
  810.     SetGold(sWorld.GoldStartAmount);
  811.  
  812.  
  813.     for(uint32 x = 0; x < 7; x++)
  814.         SetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT + x, 1.00);
  815.  
  816.     SetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, 0xEEEEEEEE);
  817.  
  818.     m_StableSlotCount = 0;
  819.     Item* item;
  820.  
  821.     for(std::set<uint32>::iterator sp = info->spell_list.begin(); sp != info->spell_list.end(); sp++)
  822.     {
  823.         mSpells.insert((*sp));
  824.     }
  825.  
  826.     m_FirstLogin = true;
  827.  
  828.     skilllineentry* se;
  829.     for(std::list<CreateInfo_SkillStruct>::iterator ss = info->skills.begin(); ss != info->skills.end(); ++ss)
  830.     {
  831.         se = dbcSkillLine.LookupEntry(ss->skillid);
  832.         if(se->type != SKILL_TYPE_LANGUAGE)
  833.             _AddSkillLine(se->id, ss->currentval, ss->maxval);
  834.     }
  835.     _UpdateMaxSkillCounts();
  836.     //Chances depend on stats must be in this order!
  837.     //UpdateStats();
  838.     //UpdateChances();
  839.  
  840.     _InitialReputation();
  841.  
  842.     // Add actionbars
  843.     for(std::list<CreateInfo_ActionBarStruct>::iterator itr = info->actionbars.begin(); itr != info->actionbars.end(); ++itr)
  844.     {
  845.         setAction(static_cast<uint8>(itr->button), static_cast<uint16>(itr->action), static_cast<uint8>(itr->type), static_cast<uint8>(itr->misc));
  846.     }
  847.  
  848.     for(std::list<CreateInfo_ItemStruct>::iterator is = info->items.begin(); is != info->items.end(); ++is)
  849.     {
  850.         if((*is).protoid != 0)
  851.         {
  852.             item = objmgr.CreateItem((*is).protoid, this);
  853.             if(item)
  854.             {
  855.                 item->SetStackCount((*is).amount);
  856.                 if((*is).slot < INVENTORY_SLOT_BAG_END)
  857.                 {
  858.                     if(!GetItemInterface()->SafeAddItem(item, INVENTORY_SLOT_NOT_SET, (*is).slot))
  859.                         item->DeleteMe();
  860.                 }
  861.                 else
  862.                 {
  863.                     if(!GetItemInterface()->AddItemToFreeSlot(item))
  864.                         item->DeleteMe();
  865.                 }
  866.             }
  867.         }
  868.     }
  869.  
  870.     sHookInterface.OnCharacterCreate(this);
  871.     load_health = GetHealth();
  872.     load_mana = GetPower(POWER_TYPE_MANA);
  873.     return true;
  874. }
  875.  
  876.  
  877. void Player::Update(uint32 p_time)
  878. {
  879.     if(!IsInWorld())
  880.         return;
  881.  
  882.     Unit::Update(p_time);
  883.     uint32 mstime = getMSTime();
  884.  
  885.     RemoveGarbageItems();
  886.  
  887.     if(m_attacking)
  888.     {
  889.         // Check attack timer.
  890.         if(mstime >= m_attackTimer)
  891.             _EventAttack(false);
  892.  
  893.         if(m_dualWield && mstime >= m_attackTimer_1)
  894.             _EventAttack(true);
  895.     }
  896.  
  897.     if(m_onAutoShot)
  898.     {
  899.         if(m_AutoShotAttackTimer > p_time)
  900.         {
  901.             //LOG_DEBUG( "HUNTER AUTOSHOT 0) %i, %i", m_AutoShotAttackTimer, p_time );
  902.             m_AutoShotAttackTimer -= p_time;
  903.         }
  904.         else
  905.         {
  906.             //LOG_DEBUG( "HUNTER AUTOSHOT 1) %i", p_time );
  907.             EventRepeatSpell();
  908.         }
  909.     }
  910.     else if(m_AutoShotAttackTimer > 0)
  911.     {
  912.         if(m_AutoShotAttackTimer > p_time)
  913.             m_AutoShotAttackTimer -= p_time;
  914.         else
  915.             m_AutoShotAttackTimer = 0;
  916.     }
  917.  
  918.     // Breathing
  919.     if(m_UnderwaterState & UNDERWATERSTATE_UNDERWATER)
  920.     {
  921.         // keep subtracting timer
  922.         if(m_UnderwaterTime)
  923.         {
  924.             // not taking dmg yet
  925.             if(p_time >= m_UnderwaterTime)
  926.                 m_UnderwaterTime = 0;
  927.             else
  928.                 m_UnderwaterTime -= p_time;
  929.         }
  930.  
  931.         if(!m_UnderwaterTime)
  932.         {
  933.             // check last damage dealt timestamp, and if enough time has elapsed deal damage
  934.             if(mstime >= m_UnderwaterLastDmg)
  935.             {
  936.                 uint32 damage = m_uint32Values[UNIT_FIELD_MAXHEALTH] / 10;
  937.  
  938.                 SendEnvironmentalDamageLog(GetGUID(), uint8(DAMAGE_DROWNING), damage);
  939.                 DealDamage(this, damage, 0, 0, 0);
  940.                 m_UnderwaterLastDmg = mstime + 1000;
  941.             }
  942.         }
  943.     }
  944.     else
  945.     {
  946.         // check if we're not on a full breath timer
  947.         if(m_UnderwaterTime < m_UnderwaterMaxTime)
  948.         {
  949.             // regenning
  950.             m_UnderwaterTime += (p_time * 10);
  951.  
  952.             if(m_UnderwaterTime >= m_UnderwaterMaxTime)
  953.             {
  954.                 m_UnderwaterTime = m_UnderwaterMaxTime;
  955.                 StopMirrorTimer(1);
  956.             }
  957.         }
  958.     }
  959.  
  960.     // Lava Damage
  961.     if(m_UnderwaterState & UNDERWATERSTATE_LAVA)
  962.     {
  963.         // check last damage dealt timestamp, and if enough time has elapsed deal damage
  964.         if(mstime >= m_UnderwaterLastDmg)
  965.         {
  966.             uint32 damage = m_uint32Values[UNIT_FIELD_MAXHEALTH] / 5;
  967.  
  968.             SendEnvironmentalDamageLog(GetGUID(), uint8(DAMAGE_LAVA), damage);
  969.             DealDamage(this, damage, 0, 0, 0);
  970.             m_UnderwaterLastDmg = mstime + 1000;
  971.         }
  972.     }
  973.  
  974.     // Autosave
  975.     if(mstime >= m_nextSave)
  976.         SaveToDB(false);
  977.  
  978.     // Exploration
  979.     if(mstime >= m_explorationTimer)
  980.     {
  981.         _EventExploration();
  982.         m_explorationTimer = mstime + 3000;
  983.     }
  984.  
  985.     if(m_pvpTimer)
  986.     {
  987.         if(p_time >= m_pvpTimer)
  988.         {
  989.             RemovePvPFlag();
  990.             m_pvpTimer = 0;
  991.         }
  992.         else
  993.             m_pvpTimer -= p_time;
  994.     }
  995.  
  996.     if(sWorld.Collision)
  997.     {
  998.         if(mstime >= m_indoorCheckTimer)
  999.         {
  1000.             if(CollideInterface.IsIndoor(m_mapId, m_position))
  1001.             {
  1002.                 // this is duplicated check, but some mount auras comes w/o this flag set, maybe due to spellfixes.cpp line:663
  1003.                 Dismount();
  1004.  
  1005.                 for(uint32 x = MAX_POSITIVE_AURAS_EXTEDED_START; x < MAX_POSITIVE_AURAS_EXTEDED_END; x++)
  1006.                 {
  1007.                     if(m_auras[x] && m_auras[x]->GetSpellProto()->Attributes & ATTRIBUTES_ONLY_OUTDOORS)
  1008.                         RemoveAura(m_auras[x]);
  1009.                 }
  1010.             }
  1011.             m_indoorCheckTimer = mstime + COLLISION_INDOOR_CHECK_INTERVAL;
  1012.         }
  1013.  
  1014.         /*if( mstime >= m_flyhackCheckTimer )
  1015.         {
  1016.             _FlyhackCheck();
  1017.             m_flyhackCheckTimer = mstime + 10000;
  1018.         }*/
  1019.     }
  1020.  
  1021.     if(m_drunk > 0)
  1022.     {
  1023.         m_drunkTimer += p_time;
  1024.  
  1025.         if(m_drunkTimer > 10000)
  1026.             HandleSobering();
  1027.     }
  1028.  
  1029. #ifdef TRACK_IMMUNITY_BUG
  1030.     bool immune = false;
  1031.     for(uint32 i = 0; i < 7; i++)
  1032.         if(SchoolImmunityList[i]) immune = true;
  1033.  
  1034.     if(immune)
  1035.     {
  1036.         if(m_immunityTime == 0)
  1037.         {
  1038.             m_immunityTime = mstime;
  1039.         }
  1040.  
  1041.         if((mstime - m_immunityTime) > 15000)
  1042.         {
  1043.             LOG_DETAIL("plr guid=%d has been immune for > 15sec: %u %u %u %u %u %u %u, resetting states", GetLowGUID(),
  1044.                        SchoolImmunityList[0], SchoolImmunityList[1], SchoolImmunityList[2], SchoolImmunityList[3],
  1045.                        SchoolImmunityList[4], SchoolImmunityList[5], SchoolImmunityList[6]);
  1046.             for(uint32 i = 0; i < 7; i++)
  1047.                 if(SchoolImmunityList[i]) SchoolImmunityList[i] = 0;
  1048.         }
  1049.     }
  1050.     else
  1051.     {
  1052.         m_immunityTime = 0;
  1053.     }
  1054. #endif
  1055.  
  1056.     WorldPacket* pending_packet = m_cache->m_pendingPackets.pop();
  1057.     while(pending_packet != NULL)
  1058.     {
  1059.         SendPacket(pending_packet);
  1060.         delete pending_packet;
  1061.         pending_packet = m_cache->m_pendingPackets.pop();
  1062.     }
  1063. }
  1064.  
  1065. void Player::EventDismount(uint32 money, float x, float y, float z)
  1066. {
  1067.     ModGold(-(int32)money);
  1068.  
  1069.     if(money > 0 && m_fallDisabledUntil < time(NULL) + 5) m_fallDisabledUntil = time(NULL) + 5; //VLack: If the ride wasn't free, the player shouldn't die after arrival because of fall damage... So we'll disable it for 5 seconds.
  1070.  
  1071.     SetPosition(x, y, z, true);
  1072.     if(!m_taxiPaths.size())
  1073.         SetTaxiState(false);
  1074.  
  1075.     SetTaxiPath(NULL);
  1076.     UnSetTaxiPos();
  1077.     m_taxi_ride_time = 0;
  1078.  
  1079.     SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID , 0);
  1080.     RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNTED_TAXI);
  1081.     RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOCK_PLAYER);
  1082.  
  1083.     SetSpeeds(RUN, m_runSpeed);
  1084.  
  1085.     sEventMgr.RemoveEvents(this, EVENT_PLAYER_TAXI_INTERPOLATE);
  1086.  
  1087.     // Save to database on dismount
  1088.     SaveToDB(false);
  1089.  
  1090.     // If we have multiple "trips" to do, "jump" on the next one :p
  1091.     if(m_taxiPaths.size())
  1092.     {
  1093.         TaxiPath* p = *m_taxiPaths.begin();
  1094.         m_taxiPaths.erase(m_taxiPaths.begin());
  1095.         TaxiStart(p, taxi_model_id, 0);
  1096.     }
  1097. }
  1098.  
  1099. void Player::_EventAttack(bool offhand)
  1100. {
  1101.     if(m_currentSpell)
  1102.     {
  1103.         if(m_currentSpell->GetProto()->ChannelInterruptFlags != 0) // this is a channeled spell - ignore the attack event
  1104.             return;
  1105.         m_currentSpell->cancel();
  1106.         setAttackTimer(500, offhand);
  1107.         return;
  1108.     }
  1109.  
  1110.     if(IsFeared() || IsStunned())
  1111.         return;
  1112.  
  1113.     Unit* pVictim = NULL;
  1114.     if(m_curSelection)
  1115.         pVictim = GetMapMgr()->GetUnit(m_curSelection);
  1116.  
  1117.     //Can't find victim, stop attacking
  1118.     if(!pVictim)
  1119.     {
  1120.         LOG_DETAIL("Player::Update:  No valid current selection to attack, stopping attack");
  1121.         setHRegenTimer(5000); //prevent clicking off creature for a quick heal
  1122.         EventAttackStop();
  1123.         return;
  1124.     }
  1125.  
  1126.     if( !isAttackable( this, pVictim ) )
  1127.     {
  1128.         setHRegenTimer(5000);
  1129.         EventAttackStop();
  1130.         return;
  1131.     }
  1132.  
  1133.     if(!canReachWithAttack(pVictim))
  1134.     {
  1135.         if(m_AttackMsgTimer != 1)
  1136.         {
  1137.             m_session->OutPacket(SMSG_ATTACKSWING_NOTINRANGE);
  1138.             m_AttackMsgTimer = 1;
  1139.         }
  1140.         setAttackTimer(300, offhand);
  1141.     }
  1142.     else if(!isInFront(pVictim))
  1143.     {
  1144.         // We still have to do this one.
  1145.         if(m_AttackMsgTimer != 2)
  1146.         {
  1147.             m_session->OutPacket(SMSG_ATTACKSWING_BADFACING);
  1148.             m_AttackMsgTimer = 2;
  1149.         }
  1150.         setAttackTimer(300, offhand);
  1151.     }
  1152.     else
  1153.     {
  1154.         m_AttackMsgTimer = 0;
  1155.  
  1156.         // Set to weapon time.
  1157.         setAttackTimer(0, offhand);
  1158.  
  1159.         //pvp timeout reset
  1160.         if(pVictim->IsPlayer())
  1161.         {
  1162.             if(TO< Player* >(pVictim)->cannibalize)
  1163.             {
  1164.                 sEventMgr.RemoveEvents(pVictim, EVENT_CANNIBALIZE);
  1165.                 pVictim->SetEmoteState(0);
  1166.                 TO< Player* >(pVictim)->cannibalize = false;
  1167.             }
  1168.         }
  1169.  
  1170.         if(this->IsStealth())
  1171.         {
  1172.             RemoveAura(m_stealth);
  1173.             SetStealth(0);
  1174.         }
  1175.  
  1176.         if( ( GetOnMeleeSpell() == 0 ) || offhand)
  1177.             Strike(pVictim, (offhand ? OFFHAND : MELEE), NULL, 0, 0, 0, false, false);
  1178.         else
  1179.             CastOnMeleeSpell();
  1180.     }
  1181. }
  1182.  
  1183. void Player::_EventCharmAttack()
  1184. {
  1185.     if(!m_CurrentCharm)
  1186.         return;
  1187.  
  1188.     Unit* pVictim = NULL;
  1189.     if(!IsInWorld())
  1190.     {
  1191.         m_CurrentCharm = 0;
  1192.         sEventMgr.RemoveEvents(this, EVENT_PLAYER_CHARM_ATTACK);
  1193.         return;
  1194.     }
  1195.  
  1196.     if(m_curSelection == 0)
  1197.     {
  1198.         sEventMgr.RemoveEvents(this, EVENT_PLAYER_CHARM_ATTACK);
  1199.         return;
  1200.     }
  1201.  
  1202.     pVictim = GetMapMgr()->GetUnit(m_curSelection);
  1203.  
  1204.     //Can't find victim, stop attacking
  1205.     if(!pVictim)
  1206.     {
  1207.         LOG_ERROR("WORLD: " I64FMT " doesn't exist.", m_curSelection);
  1208.         LOG_DETAIL("Player::Update:  No valid current selection to attack, stopping attack");
  1209.         this->setHRegenTimer(5000); //prevent clicking off creature for a quick heal
  1210.         clearStateFlag(UF_ATTACKING);
  1211.         EventAttackStop();
  1212.     }
  1213.     else
  1214.     {
  1215.         Unit* currentCharm = GetMapMgr()->GetUnit(m_CurrentCharm);
  1216.  
  1217.         if(!currentCharm)
  1218.             return;
  1219.  
  1220.         if(!currentCharm->canReachWithAttack(pVictim))
  1221.         {
  1222.             if(m_AttackMsgTimer == 0)
  1223.             {
  1224.                 //m_session->OutPacket(SMSG_ATTACKSWING_NOTINRANGE);
  1225.                 // 2 sec till next msg.
  1226.                 m_AttackMsgTimer = 2000;
  1227.             }
  1228.             // Shorten, so there isnt a delay when the client IS in the right position.
  1229.             sEventMgr.ModifyEventTimeLeft(this, EVENT_PLAYER_CHARM_ATTACK, 100);
  1230.         }
  1231.         else if(!currentCharm->isInFront(pVictim))
  1232.         {
  1233.             if(m_AttackMsgTimer == 0)
  1234.             {
  1235.                 m_session->OutPacket(SMSG_ATTACKSWING_BADFACING);
  1236.                 m_AttackMsgTimer = 2000;        // 2 sec till next msg.
  1237.             }
  1238.             // Shorten, so there isnt a delay when the client IS in the right position.
  1239.             sEventMgr.ModifyEventTimeLeft(this, EVENT_PLAYER_CHARM_ATTACK, 100);
  1240.         }
  1241.         else
  1242.         {
  1243.             //if(pVictim->GetTypeId() == TYPEID_UNIT)
  1244.             //  pVictim->GetAIInterface()->StopMovement(5000);
  1245.  
  1246.             //pvp timeout reset
  1247.             /*if(pVictim->IsPlayer())
  1248.             {
  1249.                 if( TO< Player* >( pVictim )->DuelingWith == NULL)//Dueling doesn't trigger PVP
  1250.                     TO< Player* >( pVictim )->PvPTimeoutUpdate(false); //update targets timer
  1251.  
  1252.                 if(DuelingWith == NULL)//Dueling doesn't trigger PVP
  1253.                     PvPTimeoutUpdate(false); //update casters timer
  1254.             }*/
  1255.  
  1256.             if(!currentCharm->GetOnMeleeSpell())
  1257.             {
  1258.                 currentCharm->Strike(pVictim, MELEE, NULL, 0, 0, 0, false, false);
  1259.             }
  1260.             else
  1261.             {
  1262.                 SpellEntry* spellInfo = dbcSpell.LookupEntry(currentCharm->GetOnMeleeSpell());
  1263.                 currentCharm->SetOnMeleeSpell(0);
  1264.                 Spell* spell = sSpellFactoryMgr.NewSpell(currentCharm, spellInfo, true, NULL);
  1265.                 SpellCastTargets targets;
  1266.                 targets.m_unitTarget = GetSelection();
  1267.                 spell->prepare(&targets);
  1268.                 //delete spell;      // deleted automatically, no need to do this.
  1269.             }
  1270.         }
  1271.     }
  1272. }
  1273.  
  1274. void Player::EventAttackStart()
  1275. {
  1276.     m_attacking = true;
  1277.     Dismount();
  1278. }
  1279.  
  1280. void Player::EventAttackStop()
  1281. {
  1282.     if(m_CurrentCharm != 0)
  1283.         sEventMgr.RemoveEvents(this, EVENT_PLAYER_CHARM_ATTACK);
  1284.  
  1285.     m_attacking = false;
  1286. }
  1287.  
  1288. bool Player::HasOverlayUncovered(uint32 overlayID)
  1289. {
  1290.     WorldMapOverlay const* overlay = dbcWorldMapOverlayStore.LookupEntry(overlayID);
  1291.     if(overlay == 0)
  1292.         return false;
  1293.  
  1294.     if(overlay->areaID && HasAreaExplored(dbcArea.LookupEntry(overlay->areaID)))
  1295.         return true;
  1296.     if(overlay->areaID_2 && HasAreaExplored(dbcArea.LookupEntry(overlay->areaID_2)))
  1297.         return true;
  1298.     if(overlay->areaID_3 && HasAreaExplored(dbcArea.LookupEntry(overlay->areaID_3)))
  1299.         return true;
  1300.     if(overlay->areaID_4 && HasAreaExplored(dbcArea.LookupEntry(overlay->areaID_4)))
  1301.         return true;
  1302.  
  1303.     return false;
  1304. }
  1305.  
  1306. bool Player::HasAreaExplored(AreaTable const* at)
  1307. {
  1308.     if(at == NULL)
  1309.         return false;
  1310.  
  1311.     int offset = at->explorationFlag / 32;
  1312.     offset += PLAYER_EXPLORED_ZONES_1;
  1313.  
  1314.     uint32 val = (uint32)(1 << (at->explorationFlag % 32));
  1315.     uint32 currFields = GetUInt32Value(offset);
  1316.  
  1317.     return (currFields & val) != 0;
  1318. }
  1319.  
  1320. void Player::_EventExploration()
  1321. {
  1322.     if(IsDead())
  1323.         return;
  1324.  
  1325.     if(!IsInWorld())
  1326.         return;
  1327.  
  1328.     if(m_position.x > _maxX || m_position.x < _minX || m_position.y > _maxY || m_position.y < _minY)
  1329.         return;
  1330.  
  1331.     if(GetMapMgr()->GetCellByCoords(GetPositionX(), GetPositionY()) == NULL)
  1332.         return;
  1333.  
  1334.     AreaTable* at = GetMapMgr()->GetArea(GetPositionX(), GetPositionY(), GetPositionZ());
  1335.     if(at == NULL)
  1336.         return;
  1337.  
  1338.     uint32 AreaId = at->AreaId;
  1339.  
  1340.     /*char areaname[200];
  1341.     if(at)
  1342.     {
  1343.         strcpy(areaname, sAreaStore.LookupString((uint32)at->name));
  1344.     }
  1345.     else
  1346.     {
  1347.         strcpy(areaname, "UNKNOWN");
  1348.     }
  1349.     sChatHandler.BlueSystemMessageToPlr(this,areaname);*/
  1350.  
  1351.     int offset = at->explorationFlag / 32;
  1352.     offset += PLAYER_EXPLORED_ZONES_1;
  1353.  
  1354.     uint32 val = (uint32)(1 << (at->explorationFlag % 32));
  1355.     uint32 currFields = GetUInt32Value(offset);
  1356.  
  1357.     if(AreaId != m_AreaID)
  1358.     {
  1359.         m_AreaID = AreaId;
  1360.         UpdatePvPArea();
  1361.         if(GetGroup())
  1362.             GetGroup()->UpdateOutOfRangePlayer(this, 128, true, NULL);
  1363.     }
  1364.  
  1365.     // Zone update, this really should update to a parent zone if one exists.
  1366.     //  Will show correct location on your character screen, as well zoneid in DB will have correct value
  1367.     //  for any web sites that access that data.
  1368.     if(at->ZoneId == 0 && m_zoneId != AreaId)
  1369.     {
  1370.         ZoneUpdate(AreaId);
  1371.     }
  1372.     else if(at->ZoneId != 0 && m_zoneId != at->ZoneId)
  1373.     {
  1374.         ZoneUpdate(at->ZoneId);
  1375.     }
  1376.  
  1377.  
  1378.     if(at->ZoneId != 0 && m_zoneId != at->ZoneId)
  1379.         ZoneUpdate(at->ZoneId);
  1380.  
  1381.     bool rest_on = false;
  1382.     // Check for a restable area
  1383.     if(at->AreaFlags & AREA_CITY_AREA || at->AreaFlags & AREA_CITY)
  1384.     {
  1385.         // check faction
  1386.         if((at->category == AREAC_ALLIANCE_TERRITORY && IsTeamAlliance()) || (at->category == AREAC_HORDE_TERRITORY && IsTeamHorde()))
  1387.         {
  1388.             rest_on = true;
  1389.         }
  1390.         else if(at->category != AREAC_ALLIANCE_TERRITORY && at->category != AREAC_HORDE_TERRITORY)
  1391.         {
  1392.             rest_on = true;
  1393.         }
  1394.     }
  1395.     else
  1396.     {
  1397.         //second AT check for subzones.
  1398.         if(at->ZoneId)
  1399.         {
  1400.             AreaTable* at2 = dbcArea.LookupEntryForced(at->ZoneId);
  1401.             if(at2 && (at2->AreaFlags & AREA_CITY_AREA || at2->AreaFlags & AREA_CITY))
  1402.             {
  1403.                 if((at2->category == AREAC_ALLIANCE_TERRITORY && IsTeamAlliance()) || (at2->category == AREAC_HORDE_TERRITORY && IsTeamHorde()))
  1404.                 {
  1405.                     rest_on = true;
  1406.                 }
  1407.                 else if(at2->category != AREAC_ALLIANCE_TERRITORY && at2->category != AREAC_HORDE_TERRITORY)
  1408.                 {
  1409.                     rest_on = true;
  1410.                 }
  1411.             }
  1412.         }
  1413.     }
  1414.  
  1415.     if(rest_on)
  1416.     {
  1417.         if(!m_isResting) ApplyPlayerRestState(true);
  1418.     }
  1419.     else
  1420.     {
  1421.         if(m_isResting)
  1422.         {
  1423.             if(sWorld.Collision)
  1424.             {
  1425.                 const LocationVector & loc = GetPosition();
  1426.                 if(!CollideInterface.IsIndoor(GetMapId(), loc.x, loc.y, loc.z + 2.0f))
  1427.                     ApplyPlayerRestState(false);
  1428.             }
  1429.             else
  1430.             {
  1431.                 ApplyPlayerRestState(false);
  1432.             }
  1433.         }
  1434.     }
  1435.  
  1436.     if(!(currFields & val) && !GetTaxiState() && !transporter_info.guid) //Unexplored Area      // bur: we don't want to explore new areas when on taxi
  1437.     {
  1438.         SetUInt32Value(offset, (uint32)(currFields | val));
  1439.  
  1440.         uint32 explore_xp = at->level * 10;
  1441.         explore_xp *= float2int32(sWorld.getRate(RATE_EXPLOREXP));
  1442.  
  1443. #ifdef ENABLE_ACHIEVEMENTS
  1444.         GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA);
  1445. #endif
  1446.         uint32 maxlevel = GetMaxLevel();
  1447.  
  1448.         if(getLevel() <  maxlevel && explore_xp > 0)
  1449.         {
  1450.             SendExploreXP(at->AreaId, explore_xp);
  1451.             GiveXP(explore_xp, 0, false);
  1452.         }
  1453.         else
  1454.         {
  1455.             SendExploreXP(at->AreaId, 0);
  1456.         }
  1457.     }
  1458. }
  1459.  
  1460. void Player::EventDeath()
  1461. {
  1462.     if(m_state & UF_ATTACKING)
  1463.         EventAttackStop();
  1464.  
  1465.     if(m_onTaxi)
  1466.         sEventMgr.RemoveEvents(this, EVENT_PLAYER_TAXI_DISMOUNT);
  1467.  
  1468.     if(!IS_INSTANCE(GetMapId()) && !sEventMgr.HasEvent(this, EVENT_PLAYER_FORCED_RESURRECT)) //Should never be true
  1469.         sEventMgr.AddEvent(this, &Player::RepopRequestedPlayer, EVENT_PLAYER_FORCED_RESURRECT, PLAYER_FORCED_RESURRECT_INTERVAL, 1, 0); //in case he forgets to release spirit (afk or something)
  1470.  
  1471.     RemoveNegativeAuras();
  1472.  
  1473.     SetDrunkValue(0);
  1474. }
  1475.  
  1476.  
  1477. ///  This function sends the message displaying the purple XP gain for the char
  1478. ///  It assumes you will send out an UpdateObject packet at a later time.
  1479. void Player::GiveXP(uint32 xp, const uint64 & guid, bool allowbonus)
  1480. {
  1481.     if(xp < 1)
  1482.         return;
  1483.  
  1484.     // Obviously if Xp gaining is disabled we don't want to gain XP
  1485.     if(!m_XpGain)
  1486.         return;
  1487.  
  1488.     if(getLevel() >= GetMaxLevel())
  1489.         return;
  1490.  
  1491.     uint32 restxp = xp;
  1492.  
  1493.     //add reststate bonus (except for quests)
  1494.     if(m_restState == RESTSTATE_RESTED && allowbonus)
  1495.     {
  1496.         restxp = SubtractRestXP(xp);
  1497.         xp += restxp;
  1498.     }
  1499.  
  1500.     UpdateRestState();
  1501.     SendLogXPGain(guid, xp, restxp, guid == 0 ? true : false);
  1502.  
  1503.     int32 newxp = GetXp() + xp;
  1504.     int32 nextlevelxp = lvlinfo->XPToNextLevel;
  1505.     uint32 level = getLevel();
  1506.     LevelInfo* li;
  1507.     bool levelup = false;
  1508.  
  1509.     while(newxp >= nextlevelxp && newxp > 0)
  1510.     {
  1511.         ++level;
  1512.         li = objmgr.GetLevelInfo(getRace(), getClass(), level);
  1513.         if(li == NULL) return;
  1514.         newxp -= nextlevelxp;
  1515.         nextlevelxp = li->XPToNextLevel;
  1516.         levelup = true;
  1517.  
  1518.         if(level > 9)
  1519.             AddTalentPointsToAllSpec( 1 );
  1520.  
  1521.         if(level >= GetMaxLevel())
  1522.             break;
  1523.     }
  1524.  
  1525.     if(level > GetMaxLevel())
  1526.         level = GetMaxLevel();
  1527.  
  1528.     if(levelup)
  1529.     {
  1530.         m_playedtime[0] = 0; //Reset the "Current level played time"
  1531.  
  1532.         setLevel(level);
  1533.         LevelInfo* oldlevel = lvlinfo;
  1534.         lvlinfo = objmgr.GetLevelInfo(getRace(), getClass(), level);
  1535.         if(lvlinfo == NULL) return;
  1536.         CalculateBaseStats();
  1537.  
  1538.         // Generate Level Info Packet and Send to client
  1539.         SendLevelupInfo(
  1540.             level,
  1541.             lvlinfo->HP - oldlevel->HP,
  1542.             lvlinfo->Mana - oldlevel->Mana,
  1543.             lvlinfo->Stat[0] - oldlevel->Stat[0],
  1544.             lvlinfo->Stat[1] - oldlevel->Stat[1],
  1545.             lvlinfo->Stat[2] - oldlevel->Stat[2],
  1546.             lvlinfo->Stat[3] - oldlevel->Stat[3],
  1547.             lvlinfo->Stat[4] - oldlevel->Stat[4]);
  1548.  
  1549.         _UpdateMaxSkillCounts();
  1550.         UpdateStats();
  1551.         //UpdateChances();
  1552.         UpdateGlyphs();
  1553.  
  1554.         // Set next level conditions
  1555.         SetNextLevelXp(lvlinfo->XPToNextLevel);
  1556.  
  1557.         // ScriptMgr hook for OnPostLevelUp
  1558.         sHookInterface.OnPostLevelUp(this);
  1559.  
  1560.         // Set stats
  1561.         for(uint32 i = 0; i < 5; ++i)
  1562.         {
  1563.             BaseStats[i] = lvlinfo->Stat[i];
  1564.             CalcStat(i);
  1565.         }
  1566.  
  1567.         // Small chance you die and levelup at the same time, and you enter a weird state.
  1568.         if(IsDead())
  1569.             ResurrectPlayer();
  1570.  
  1571.         //set full hp and mana
  1572.         SetHealth(GetMaxHealth());
  1573.         SetPower(POWER_TYPE_MANA, GetMaxPower(POWER_TYPE_MANA));
  1574.  
  1575.         // if warlock has summoned pet, increase its level too
  1576.         if(info->class_ == WARLOCK)
  1577.         {
  1578.             Pet* summon = GetSummon();
  1579.             if((summon != NULL) && (summon->IsInWorld()) && (summon->isAlive()))
  1580.             {
  1581.                 summon->modLevel(1);
  1582.                 summon->ApplyStatsForLevel();
  1583.                 summon->UpdateSpellList();
  1584.             }
  1585.         }
  1586.         //Event_Achiement_Received(ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL,0,level);
  1587. #ifdef ENABLE_ACHIEVEMENTS
  1588.         GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL);
  1589. #endif
  1590.  
  1591.         //VLack: 3.1.3, as a final step, send the player's talents, this will set the talent points right too...
  1592.         smsg_TalentsInfo(false);
  1593.     }
  1594.  
  1595.     // Set the update bit
  1596.     SetXp(newxp);
  1597.  
  1598. }
  1599.  
  1600. void Player::smsg_InitialSpells()
  1601. {
  1602.     PlayerCooldownMap::iterator itr, itr2;
  1603.  
  1604.     uint16 spellCount = (uint16)mSpells.size();
  1605.     size_t itemCount = m_cooldownMap[0].size() + m_cooldownMap[1].size();
  1606.     uint32 mstime = getMSTime();
  1607.     size_t pos;
  1608.  
  1609.     WorldPacket data(SMSG_INITIAL_SPELLS, 5 + (spellCount * 4) + (itemCount * 4));
  1610.     data << uint8(0);
  1611.     data << uint16(spellCount); // spell count
  1612.  
  1613.     SpellSet::iterator sitr;
  1614.     for(sitr = mSpells.begin(); sitr != mSpells.end(); ++sitr)
  1615.     {
  1616.         // todo: check out when we should send 0x0 and when we should send 0xeeee
  1617.         // this is not slot, values is always eeee or 0, seems to be cooldown
  1618.         data << uint32(*sitr);                 // spell id
  1619.         data << uint16(0x0000);
  1620.     }
  1621.  
  1622.     pos = data.wpos();
  1623.     data << uint16(0);      // placeholder
  1624.  
  1625.     itemCount = 0;
  1626.     for(itr = m_cooldownMap[COOLDOWN_TYPE_SPELL].begin(); itr != m_cooldownMap[COOLDOWN_TYPE_SPELL].end();)
  1627.     {
  1628.         itr2 = itr++;
  1629.  
  1630.         // don't keep around expired cooldowns
  1631.         if(itr2->second.ExpireTime < mstime || (itr2->second.ExpireTime - mstime) < 10000)
  1632.         {
  1633.             m_cooldownMap[COOLDOWN_TYPE_SPELL].erase(itr2);
  1634.             continue;
  1635.         }
  1636.  
  1637.         data << uint32(itr2->first);                        // spell id
  1638.         data << uint16(itr2->second.ItemId);                // item id
  1639.         data << uint16(0);                              // spell category
  1640.         data << uint32(itr2->second.ExpireTime - mstime);   // cooldown remaining in ms (for spell)
  1641.         data << uint32(0);                              // cooldown remaining in ms (for category)
  1642.  
  1643.         ++itemCount;
  1644.  
  1645. #ifdef _DEBUG
  1646.         Log.Debug("InitialSpells", "sending spell cooldown for spell %u to %u ms", itr2->first, itr2->second.ExpireTime - mstime);
  1647. #endif
  1648.     }
  1649.  
  1650.     for(itr = m_cooldownMap[COOLDOWN_TYPE_CATEGORY].begin(); itr != m_cooldownMap[COOLDOWN_TYPE_CATEGORY].end();)
  1651.     {
  1652.         itr2 = itr++;
  1653.  
  1654.         // don't keep around expired cooldowns
  1655.         if(itr2->second.ExpireTime < mstime || (itr2->second.ExpireTime - mstime) < 10000)
  1656.         {
  1657.             m_cooldownMap[COOLDOWN_TYPE_CATEGORY].erase(itr2);
  1658.             continue;
  1659.         }
  1660.  
  1661.         data << uint32(itr2->second.SpellId);               // spell id
  1662.         data << uint16(itr2->second.ItemId);                // item id
  1663.         data << uint16(itr2->first);                        // spell category
  1664.         data << uint32(0);                              // cooldown remaining in ms (for spell)
  1665.         data << uint32(itr2->second.ExpireTime - mstime);   // cooldown remaining in ms (for category)
  1666.  
  1667.         ++itemCount;
  1668.  
  1669. #ifdef _DEBUG
  1670.         Log.Debug("InitialSpells", "sending category cooldown for cat %u to %u ms", itr2->first, itr2->second.ExpireTime - mstime);
  1671. #endif
  1672.     }
  1673.  
  1674.  
  1675.     *(uint16*)&data.contents()[pos] = (uint16)itemCount;
  1676.  
  1677.     GetSession()->SendPacket(&data);
  1678.  
  1679.     uint32 v = 0;
  1680.     GetSession()->OutPacket(0x041d, 4, &v);
  1681.     //Log::getSingleton( ).outDetail( "CHARACTER: Sent Initial Spells" );
  1682. }
  1683.  
  1684. void Player::smsg_TalentsInfo(bool SendPetTalents)
  1685. {
  1686.     WorldPacket data(SMSG_TALENTS_INFO, 1000);
  1687.     data << uint8(SendPetTalents ? 1 : 0);
  1688.     if(SendPetTalents)
  1689.     {
  1690.         if(GetSummon())
  1691.             GetSummon()->SendTalentsToOwner();
  1692.         return;
  1693.     }
  1694.     else
  1695.     {
  1696.         //data << uint32(GetTalentPoints(SPEC_PRIMARY)); // Wrong, calculate the amount of talent points per spec
  1697.         data << uint32(m_specs[m_talentActiveSpec].GetTP() );
  1698.         data << uint8(m_talentSpecsCount);
  1699.         data << uint8(m_talentActiveSpec);
  1700.         for(uint8 s = 0; s < m_talentSpecsCount; s++)
  1701.         {
  1702.             PlayerSpec spec = m_specs[s];
  1703.             data << uint8(spec.talents.size());
  1704.             std::map<uint32, uint8>::iterator itr;
  1705.             for(itr = spec.talents.begin(); itr != spec.talents.end(); itr++)
  1706.             {
  1707.                 data << uint32(itr->first);     // TalentId
  1708.                 data << uint8(itr->second);     // TalentRank
  1709.             }
  1710.  
  1711.             // Send Glyph info
  1712.             data << uint8(GLYPHS_COUNT);
  1713.             for(uint8 i = 0; i < GLYPHS_COUNT; i++)
  1714.             {
  1715.                 data << uint16(spec.glyphs[i]);
  1716.             }
  1717.         }
  1718.     }
  1719.     GetSession()->SendPacket(&data);
  1720. }
  1721.  
  1722. void Player::ActivateSpec(uint8 spec)
  1723. {
  1724.     if(spec >= MAX_SPEC_COUNT || m_talentActiveSpec >= MAX_SPEC_COUNT)
  1725.         return;
  1726.  
  1727.     uint8 OldSpec = m_talentActiveSpec;
  1728.     m_talentActiveSpec = spec;
  1729.  
  1730.     // remove old glyphs
  1731.     for(uint8 i = 0; i < GLYPHS_COUNT; ++i)
  1732.     {
  1733.         GlyphPropertyEntry* glyph = dbcGlyphProperty.LookupEntryForced(m_specs[OldSpec].glyphs[i]);
  1734.         if(glyph == NULL)
  1735.             continue;
  1736.  
  1737.         RemoveAura(glyph->SpellID);
  1738.     }
  1739.  
  1740.     // remove old talents
  1741.     for(std::map<uint32, uint8>::iterator itr = m_specs[OldSpec].talents.begin(); itr != m_specs[OldSpec].talents.end(); ++itr)
  1742.     {
  1743.         TalentEntry* talentInfo = dbcTalent.LookupEntryForced(itr->first);
  1744.         if(talentInfo == NULL)
  1745.             continue;
  1746.  
  1747.         removeSpell(talentInfo->RankID[itr->second], true, false, 0);
  1748.     }
  1749.  
  1750.     // add new glyphs
  1751.     for(uint8 i = 0; i < GLYPHS_COUNT; ++i)
  1752.     {
  1753.         GlyphPropertyEntry* glyph = dbcGlyphProperty.LookupEntryForced(m_specs[m_talentActiveSpec].glyphs[i]);
  1754.         if(glyph == NULL)
  1755.             continue;
  1756.  
  1757.         CastSpell(this, glyph->SpellID, true);
  1758.     }
  1759.  
  1760.     //add talents from new spec
  1761.     for(std::map<uint32, uint8>::iterator itr = m_specs[m_talentActiveSpec].talents.begin();
  1762.             itr != m_specs[m_talentActiveSpec].talents.end(); ++itr)
  1763.     {
  1764.         TalentEntry* talentInfo = dbcTalent.LookupEntryForced(itr->first);
  1765.         if(talentInfo == NULL)
  1766.             continue;
  1767.  
  1768.         addSpell(talentInfo->RankID[itr->second]);
  1769.     }
  1770.     SetUInt32Value(PLAYER_CHARACTER_POINTS1, m_specs[ m_talentActiveSpec ].GetTP() );
  1771.     smsg_TalentsInfo(false);
  1772. }
  1773.  
  1774. void PlayerSpec::AddTalent( uint32 talentid, uint8 rankid ){
  1775.     std::map<uint32, uint8>::iterator itr = talents.find( talentid );
  1776.     if( itr != talents.end() )
  1777.         itr->second = rankid;
  1778.     else
  1779.         talents.insert( make_pair( talentid, rankid ) );
  1780. }
  1781.  
  1782. void Player::_SavePet(QueryBuffer* buf)
  1783. {
  1784.     // Remove any existing info
  1785.     if(buf == NULL)
  1786.         CharacterDatabase.Execute("DELETE FROM playerpets WHERE ownerguid = %u", GetLowGUID());
  1787.     else
  1788.         buf->AddQuery("DELETE FROM playerpets WHERE ownerguid = %u", GetLowGUID());
  1789.  
  1790.     Pet* summon = GetSummon();
  1791.     if(summon && summon->IsInWorld() && summon->GetPetOwner() == this)  // update PlayerPets array with current pet's info
  1792.     {
  1793.         PlayerPet* pPet = GetPlayerPet(summon->m_PetNumber);
  1794.         if(!pPet || pPet->active == false)
  1795.             summon->UpdatePetInfo(true);
  1796.         else summon->UpdatePetInfo(false);
  1797.  
  1798.         if(!summon->Summon)    // is a pet
  1799.         {
  1800.             // save pet spellz
  1801.             PetSpellMap::iterator itr = summon->mSpells.begin();
  1802.             uint32 pn = summon->m_PetNumber;
  1803.             if(buf == NULL)
  1804.                 CharacterDatabase.Execute("DELETE FROM playerpetspells WHERE ownerguid=%u AND petnumber=%u", GetLowGUID(), pn);
  1805.             else
  1806.                 buf->AddQuery("DELETE FROM playerpetspells WHERE ownerguid=%u AND petnumber=%u", GetLowGUID(), pn);
  1807.  
  1808.             for(; itr != summon->mSpells.end(); ++itr)
  1809.             {
  1810.                 if(buf == NULL)
  1811.                     CharacterDatabase.Execute("INSERT INTO playerpetspells VALUES(%u, %u, %u, %u)", GetLowGUID(), pn, itr->first->Id, itr->second);
  1812.                 else
  1813.                     buf->AddQuery("INSERT INTO playerpetspells VALUES(%u, %u, %u, %u)", GetLowGUID(), pn, itr->first->Id, itr->second);
  1814.             }
  1815.         }
  1816.     }
  1817.  
  1818.     std::stringstream ss;
  1819.  
  1820.     ss.rdbuf()->str("");
  1821.  
  1822.     for(std::map<uint32, PlayerPet*>::iterator itr = m_Pets.begin(); itr != m_Pets.end(); itr++)
  1823.     {
  1824.         ss.rdbuf()->str("");
  1825.  
  1826.         ss << "INSERT INTO playerpets VALUES('"
  1827.            << GetLowGUID() << "','"
  1828.            << itr->second->number << "','"
  1829.            << itr->second->name << "','"
  1830.            << itr->second->entry << "','"
  1831.            << itr->second->xp << "','"
  1832.            << (itr->second->active ?  1 : 0) + itr->second->stablestate * 10 << "','"
  1833.            << itr->second->level << "','"
  1834.            << itr->second->actionbar << "','"
  1835.            << itr->second->happinessupdate << "','"
  1836.            << (long)itr->second->reset_time << "','"
  1837.            << itr->second->reset_cost << "','"
  1838.            << itr->second->spellid << "','"
  1839.            << itr->second->petstate << "','"
  1840.            << itr->second->alive << "','"
  1841.            << itr->second->talentpoints << "','"
  1842.            << itr->second->current_power << "','"
  1843.            << itr->second->current_hp << "','"
  1844.            << itr->second->current_happiness << "','"
  1845.            << itr->second->renamable << "','"
  1846.            << itr->second->type << "')";
  1847.  
  1848.         if(buf == NULL)
  1849.             CharacterDatabase.ExecuteNA(ss.str().c_str());
  1850.         else
  1851.             buf->AddQueryStr(ss.str());
  1852.     }
  1853. }
  1854.  
  1855. void Player::_SavePetSpells(QueryBuffer* buf)
  1856. {
  1857.     // Remove any existing
  1858.     if(buf == NULL)
  1859.         CharacterDatabase.Execute("DELETE FROM playersummonspells WHERE ownerguid=%u", GetLowGUID());
  1860.     else
  1861.         buf->AddQuery("DELETE FROM playersummonspells WHERE ownerguid=%u", GetLowGUID());
  1862.  
  1863.     // Save summon spells
  1864.     map<uint32, set<uint32> >::iterator itr = SummonSpells.begin();
  1865.     for(; itr != SummonSpells.end(); ++itr)
  1866.     {
  1867.         set<uint32>::iterator it = itr->second.begin();
  1868.         for(; it != itr->second.end(); ++it)
  1869.         {
  1870.             if(buf == NULL)
  1871.                 CharacterDatabase.Execute("INSERT INTO playersummonspells VALUES(%u, %u, %u)", GetLowGUID(), itr->first, (*it));
  1872.             else
  1873.                 buf->AddQuery("INSERT INTO playersummonspells VALUES(%u, %u, %u)", GetLowGUID(), itr->first, (*it));
  1874.         }
  1875.     }
  1876. }
  1877.  
  1878. void Player::AddSummonSpell(uint32 Entry, uint32 SpellID)
  1879. {
  1880.     SpellEntry* sp = dbcSpell.LookupEntry(SpellID);
  1881.     map<uint32, set<uint32> >::iterator itr = SummonSpells.find(Entry);
  1882.     if(itr == SummonSpells.end())
  1883.         SummonSpells[Entry].insert(SpellID);
  1884.     else
  1885.     {
  1886.         set<uint32>::iterator it3;
  1887.         for(set<uint32>::iterator it2 = itr->second.begin(); it2 != itr->second.end();)
  1888.         {
  1889.             it3 = it2++;
  1890.             if(dbcSpell.LookupEntry(*it3)->NameHash == sp->NameHash)
  1891.                 itr->second.erase(it3);
  1892.         }
  1893.         itr->second.insert(SpellID);
  1894.     }
  1895. }
  1896.  
  1897. void Player::RemoveSummonSpell(uint32 Entry, uint32 SpellID)
  1898. {
  1899.     map<uint32, set<uint32> >::iterator itr = SummonSpells.find(Entry);
  1900.     if(itr != SummonSpells.end())
  1901.     {
  1902.         itr->second.erase(SpellID);
  1903.         if(itr->second.size() == 0)
  1904.             SummonSpells.erase(itr);
  1905.     }
  1906. }
  1907.  
  1908. set<uint32>* Player::GetSummonSpells(uint32 Entry)
  1909. {
  1910.     map<uint32, set<uint32> >::iterator itr = SummonSpells.find(Entry);
  1911.     if(itr != SummonSpells.end())
  1912.     {
  1913.         return &(itr->second);
  1914.     }
  1915.     return 0;
  1916. }
  1917.  
  1918. void Player::_LoadPet(QueryResult* result)
  1919. {
  1920.     m_PetNumberMax = 0;
  1921.     if(!result)
  1922.         return;
  1923.  
  1924.     do
  1925.     {
  1926.         Field* fields = result->Fetch();
  1927.  
  1928.         PlayerPet* pet = new PlayerPet;
  1929.         pet->number  = fields[1].GetUInt32();
  1930.         pet->name   = fields[2].GetString();
  1931.         pet->entry   = fields[3].GetUInt32();
  1932.  
  1933.         pet->xp   = fields[4].GetUInt32();
  1934.         pet->active  = fields[5].GetInt8() % 10 > 0 ? true : false;
  1935.         pet->stablestate = fields[5].GetInt8() / 10;
  1936.         pet->level   = fields[6].GetUInt32();
  1937.         pet->actionbar = fields[7].GetString();
  1938.         pet->happinessupdate = fields[8].GetUInt32();
  1939.         pet->reset_time = fields[9].GetUInt32();
  1940.         pet->reset_cost = fields[10].GetUInt32();
  1941.         pet->spellid = fields[11].GetUInt32();
  1942.         pet->petstate = fields[12].GetUInt32();
  1943.         pet->alive = fields[13].GetBool();
  1944.         pet->talentpoints = fields[14].GetUInt32();
  1945.         pet->current_power = fields[15].GetUInt32();
  1946.         pet->current_hp = fields[16].GetUInt32();
  1947.         pet->current_happiness = fields[17].GetUInt32();
  1948.         pet->renamable = fields[18].GetUInt32();
  1949.         pet->type = fields[19].GetUInt32();
  1950.  
  1951.         m_Pets[pet->number] = pet;
  1952.  
  1953.         if(pet->number > m_PetNumberMax)
  1954.             m_PetNumberMax =  pet->number;
  1955.     }
  1956.     while(result->NextRow());
  1957. }
  1958.  
  1959. void Player::SpawnPet(uint32 pet_number)
  1960. {
  1961.     std::map< uint32, PlayerPet* >::iterator itr = m_Pets.find(pet_number);
  1962.     if(itr == m_Pets.end())
  1963.     {
  1964.         LOG_ERROR("PET SYSTEM: " I64FMT " Tried to load invalid pet %d", GetGUID(), pet_number);
  1965.         return;
  1966.     }
  1967.     Pet* pPet = objmgr.CreatePet(itr->second->entry);
  1968.     pPet->LoadFromDB(this, itr->second);
  1969.  
  1970.     if(this->IsPvPFlagged())
  1971.         pPet->SetPvPFlag();
  1972.     else
  1973.         pPet->RemovePvPFlag();
  1974.  
  1975.     if(this->IsFFAPvPFlagged())
  1976.         pPet->SetFFAPvPFlag();
  1977.     else
  1978.         pPet->RemoveFFAPvPFlag();
  1979.  
  1980.     if(this->IsSanctuaryFlagged())
  1981.         pPet->SetSanctuaryFlag();
  1982.     else
  1983.         pPet->RemoveSanctuaryFlag();
  1984.  
  1985.     pPet->SetFaction(this->GetFaction());
  1986.  
  1987.     if(itr->second->spellid)
  1988.     {
  1989.         //if demonic sacrifice auras are still active, remove them
  1990.         RemoveAura(18789);
  1991.         RemoveAura(18790);
  1992.         RemoveAura(18791);
  1993.         RemoveAura(18792);
  1994.         RemoveAura(35701);
  1995.     }
  1996. }
  1997. void Player::SpawnActivePet()
  1998. {
  1999.     if(GetSummon() != NULL || !isAlive() || !IsInWorld())   //TODO: only hunters for now
  2000.         return;
  2001.  
  2002.     std::map< uint32, PlayerPet* >::iterator itr = m_Pets.begin();
  2003.     for(; itr != m_Pets.end(); itr++)
  2004.         if(itr->second->stablestate == STABLE_STATE_ACTIVE && itr->second->active)
  2005.         {
  2006.             if(itr->second->alive)
  2007.                 SpawnPet(itr->first);
  2008.             return;
  2009.         }
  2010. }
  2011. void Player::DismissActivePets()
  2012. {
  2013.     for(std::list<Pet*>::reverse_iterator itr = m_Summons.rbegin(); itr != m_Summons.rend();)
  2014.     {
  2015.         Pet* summon = (*itr);
  2016.         if(summon->IsSummonedPet())
  2017.             summon->Dismiss();          // summons
  2018.         else
  2019.             summon->Remove(true, false);  // hunter pets
  2020.     }
  2021. }
  2022.  
  2023. void Player::_LoadPetSpells(QueryResult* result)
  2024. {
  2025.     std::map<uint32, std::list<uint32>* >::iterator itr;
  2026.     uint32 entry = 0;
  2027.     uint32 spell = 0;
  2028.  
  2029.     if(result)
  2030.     {
  2031.         do
  2032.         {
  2033.             Field* fields = result->Fetch();
  2034.             entry = fields[1].GetUInt32();
  2035.             spell = fields[2].GetUInt32();
  2036.             AddSummonSpell(entry, spell);
  2037.         }
  2038.         while(result->NextRow());
  2039.     }
  2040. }
  2041.  
  2042. void Player::addSpell(uint32 spell_id)
  2043. {
  2044.     SpellSet::iterator iter = mSpells.find(spell_id);
  2045.     if(iter != mSpells.end())
  2046.         return;
  2047.  
  2048.     mSpells.insert(spell_id);
  2049.     if(IsInWorld())
  2050.     {
  2051.         WorldPacket data(SMSG_LEARNED_SPELL, 6);
  2052.         data << uint32(spell_id);
  2053.         data << uint16(0);
  2054.         m_session->SendPacket(&data);
  2055.     }
  2056.  
  2057.     // Check if we're a deleted spell
  2058.     iter = mDeletedSpells.find(spell_id);
  2059.     if(iter != mDeletedSpells.end())
  2060.         mDeletedSpells.erase(iter);
  2061.  
  2062.     // Check if we're logging in.
  2063.     if(!IsInWorld())
  2064.         return;
  2065.  
  2066.     // Add the skill line for this spell if we don't already have it.
  2067.     skilllinespell* sk = objmgr.GetSpellSkill(spell_id);
  2068.     SpellEntry* spell = dbcSpell.LookupEntry(spell_id);
  2069.     if(sk && !_HasSkillLine(sk->skilline))
  2070.     {
  2071.         skilllineentry* skill = dbcSkillLine.LookupEntry(sk->skilline);
  2072.         uint32 max = 1;
  2073.         switch(skill->type)
  2074.         {
  2075.             case SKILL_TYPE_PROFESSION:
  2076.                 max = 75 * ((spell->RankNumber) + 1);
  2077.                 ModPrimaryProfessionPoints(-1);   // we are learning a profession, so subtract a point.
  2078.                 break;
  2079.             case SKILL_TYPE_SECONDARY:
  2080.                 max = 75 * ((spell->RankNumber) + 1);
  2081.                 break;
  2082.             case SKILL_TYPE_WEAPON:
  2083.                 max = 5 * getLevel();
  2084.                 break;
  2085.             case SKILL_TYPE_CLASS:
  2086.             case SKILL_TYPE_ARMOR:
  2087.                 if(skill->id == SKILL_LOCKPICKING)
  2088.                     max = 5 * getLevel();
  2089.                 break;
  2090.         };
  2091.  
  2092.         _AddSkillLine(sk->skilline, 1, max);
  2093.         _UpdateMaxSkillCounts();
  2094.     }
  2095. #ifdef ENABLE_ACHIEVEMENTS
  2096.     m_achievementMgr.UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL, spell_id, 1, 0);
  2097.     if(spell->MechanicsType == MECHANIC_MOUNTED) // Mounts
  2098.     {
  2099.         // miscvalue1==777 for mounts, 778 for pets
  2100.         m_achievementMgr.UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_MOUNTS, 777, 0, 0);
  2101.     }
  2102.     else if(spell->Effect[0] == SPELL_EFFECT_SUMMON) // Companion pet?
  2103.     {
  2104.         // miscvalue1==777 for mounts, 778 for pets
  2105.         // make sure it's a companion pet, not some other summon-type spell
  2106.         if(strncmp(spell->Description, "Right Cl", 8) == 0) // "Right Click to summon and dismiss " ...
  2107.         {
  2108.             m_achievementMgr.UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_MOUNTS, 778, 0, 0);
  2109.         }
  2110.     }
  2111. #endif
  2112. }
  2113.  
  2114. //===================================================================================================================
  2115. //  Set Create Player Bits -- Sets bits required for creating a player in the updateMask.
  2116. //  Note:  Doesn't set Quest or Inventory bits
  2117. //  updateMask - the updatemask to hold the set bits
  2118. //===================================================================================================================
  2119. void Player::_SetCreateBits(UpdateMask* updateMask, Player* target) const
  2120. {
  2121.     if(target == this)
  2122.     {
  2123.         Object::_SetCreateBits(updateMask, target);
  2124.     }
  2125.     else
  2126.     {
  2127.         for(uint32 index = 0; index < m_valuesCount; index++)
  2128.         {
  2129.             if(m_uint32Values[index] != 0 && Player::m_visibleUpdateMask.GetBit(index))
  2130.                 updateMask->SetBit(index);
  2131.         }
  2132.     }
  2133. }
  2134.  
  2135.  
  2136. void Player::_SetUpdateBits(UpdateMask* updateMask, Player* target) const
  2137. {
  2138.     if(target == this)
  2139.     {
  2140.         Object::_SetUpdateBits(updateMask, target);
  2141.     }
  2142.     else
  2143.     {
  2144.         Object::_SetUpdateBits(updateMask, target);
  2145.         *updateMask &= Player::m_visibleUpdateMask;
  2146.     }
  2147. }
  2148.  
  2149.  
  2150. void Player::InitVisibleUpdateBits()
  2151. {
  2152.     Player::m_visibleUpdateMask.SetCount(PLAYER_END);
  2153.     Player::m_visibleUpdateMask.SetBit(OBJECT_FIELD_GUID);
  2154.     Player::m_visibleUpdateMask.SetBit(OBJECT_FIELD_TYPE);
  2155.     Player::m_visibleUpdateMask.SetBit(OBJECT_FIELD_ENTRY);
  2156.     Player::m_visibleUpdateMask.SetBit(OBJECT_FIELD_SCALE_X);
  2157.  
  2158.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_SUMMON);
  2159.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_SUMMON + 1);
  2160.  
  2161.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_TARGET);
  2162.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_TARGET + 1);
  2163.  
  2164.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_HEALTH);
  2165.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_POWER1);
  2166.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_POWER2);
  2167.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_POWER3);
  2168.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_POWER4);
  2169.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_POWER5);
  2170.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_POWER6);
  2171.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_POWER7);
  2172.  
  2173.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_MAXHEALTH);
  2174.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_MAXPOWER1);
  2175.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_MAXPOWER2);
  2176.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_MAXPOWER3);
  2177.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_MAXPOWER4);
  2178.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_MAXPOWER5);
  2179.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_MAXPOWER6);
  2180.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_MAXPOWER7);
  2181.  
  2182.     Player::m_visibleUpdateMask.SetBit(UNIT_VIRTUAL_ITEM_SLOT_ID);
  2183.     Player::m_visibleUpdateMask.SetBit(UNIT_VIRTUAL_ITEM_SLOT_ID + 1);
  2184.     Player::m_visibleUpdateMask.SetBit(UNIT_VIRTUAL_ITEM_SLOT_ID + 2);
  2185.  
  2186.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_LEVEL);
  2187.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_FACTIONTEMPLATE);
  2188.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_BYTES_0);
  2189.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_FLAGS);
  2190.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_FLAGS_2);
  2191.  
  2192.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_BASEATTACKTIME);
  2193.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_BASEATTACKTIME + 1);
  2194.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_BOUNDINGRADIUS);
  2195.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_COMBATREACH);
  2196.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_DISPLAYID);
  2197.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_NATIVEDISPLAYID);
  2198.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_MOUNTDISPLAYID);
  2199.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_BYTES_1);
  2200.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_MOUNTDISPLAYID);
  2201.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_PETNUMBER);
  2202.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_PET_NAME_TIMESTAMP);
  2203.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_CHANNEL_OBJECT);
  2204.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_CHANNEL_OBJECT + 1);
  2205.     Player::m_visibleUpdateMask.SetBit(UNIT_CHANNEL_SPELL);
  2206.     Player::m_visibleUpdateMask.SetBit(UNIT_DYNAMIC_FLAGS);
  2207.     Player::m_visibleUpdateMask.SetBit(UNIT_NPC_FLAGS);
  2208.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_HOVERHEIGHT);
  2209.  
  2210.     Player::m_visibleUpdateMask.SetBit(PLAYER_FLAGS);
  2211.     Player::m_visibleUpdateMask.SetBit(PLAYER_BYTES);
  2212.     Player::m_visibleUpdateMask.SetBit(PLAYER_BYTES_2);
  2213.     Player::m_visibleUpdateMask.SetBit(PLAYER_BYTES_3);
  2214.     Player::m_visibleUpdateMask.SetBit(PLAYER_GUILD_TIMESTAMP);
  2215.     Player::m_visibleUpdateMask.SetBit(PLAYER_DUEL_TEAM);
  2216.     Player::m_visibleUpdateMask.SetBit(PLAYER_DUEL_ARBITER);
  2217.     Player::m_visibleUpdateMask.SetBit(PLAYER_DUEL_ARBITER + 1);
  2218.     Player::m_visibleUpdateMask.SetBit(PLAYER_GUILDID);
  2219.     Player::m_visibleUpdateMask.SetBit(PLAYER_GUILDRANK);
  2220.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_BASE_MANA);
  2221.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_BYTES_2);
  2222.     Player::m_visibleUpdateMask.SetBit(UNIT_FIELD_AURASTATE);
  2223.  
  2224.     // Players visible items are not inventory stuff
  2225.     for(uint16 i = 0; i < EQUIPMENT_SLOT_END; ++i)
  2226.     {
  2227.         uint32 offset = i * PLAYER_VISIBLE_ITEM_LENGTH; //VLack: for 3.1.1 "* 18" is a bad idea, now it's "* 2"; but this could have been calculated based on UpdateFields.h! This is PLAYER_VISIBLE_ITEM_LENGTH
  2228.  
  2229.         // item entry
  2230.         Player::m_visibleUpdateMask.SetBit(PLAYER_VISIBLE_ITEM_1_ENTRYID + offset);
  2231.         // enchant
  2232.         Player::m_visibleUpdateMask.SetBit(PLAYER_VISIBLE_ITEM_1_ENCHANTMENT + offset);
  2233.     }
  2234.  
  2235.     //VLack: we have to send our quest list to the members of our group all the time for quest sharing's "who's on that quest" feature to work (in the quest log this way a number will be shown before the quest's name).
  2236.     //Unfortunately we don't have code for doing this only on our group's members, so everyone will receive it. The non-group member's client will do whatever it wants with it, probably wasting a few CPU cycles, but that's fine with me.
  2237.     for(uint16 i = PLAYER_QUEST_LOG_1_1; i <= PLAYER_QUEST_LOG_25_1; i += 5)
  2238.     {
  2239.         Player::m_visibleUpdateMask.SetBit(i);
  2240.     }
  2241.  
  2242.     Player::m_visibleUpdateMask.SetBit(PLAYER_CHOSEN_TITLE);
  2243. }
  2244.  
  2245.  
  2246. void Player::SaveToDB(bool bNewCharacter /* =false */)
  2247. {
  2248.     bool in_arena = false;
  2249.     QueryBuffer* buf = NULL;
  2250.     if(!bNewCharacter)
  2251.         buf = new QueryBuffer;
  2252.  
  2253.     if(m_bg != NULL && IS_ARENA(m_bg->GetType()))
  2254.         in_arena = true;
  2255.  
  2256.     if(GetPrimaryProfessionPoints() > sWorld.MaxProfs)
  2257.         SetPrimaryProfessionPoints(sWorld.MaxProfs);
  2258.  
  2259.     //Calc played times
  2260.     uint32 playedt = (uint32)UNIXTIME - m_playedtime[2];
  2261.     m_playedtime[0] += playedt;
  2262.     m_playedtime[1] += playedt;
  2263.     m_playedtime[2] += playedt;
  2264.  
  2265.     // active cheats
  2266.     uint32 active_cheats = 0;
  2267.     if(CooldownCheat)
  2268.         active_cheats |= 0x01;
  2269.     if(CastTimeCheat)
  2270.         active_cheats |= 0x02;
  2271.     if(GodModeCheat)
  2272.         active_cheats |= 0x04;
  2273.     if(PowerCheat)
  2274.         active_cheats |= 0x08;
  2275.     if(FlyCheat)
  2276.         active_cheats |= 0x10;
  2277.     if(AuraStackCheat)
  2278.         active_cheats |= 0x20;
  2279.     if(ItemStackCheat)
  2280.         active_cheats |= 0x40;
  2281.     if(TriggerpassCheat)
  2282.         active_cheats |= 0x80;
  2283.  
  2284.     std::stringstream ss;
  2285.  
  2286.     ss << "DELETE FROM characters WHERE guid = " << GetLowGUID() << ";";
  2287.  
  2288.     if(bNewCharacter)
  2289.         CharacterDatabase.WaitExecuteNA(ss.str().c_str());
  2290.     else
  2291.         buf->AddQueryNA(ss.str().c_str());
  2292.  
  2293.  
  2294.     ss.rdbuf()->str("");
  2295.  
  2296.     ss << "INSERT INTO characters VALUES ("
  2297.  
  2298.        << GetLowGUID() << ", "
  2299.        << GetSession()->GetAccountId() << ","
  2300.  
  2301.        // stat saving
  2302.        << "'" << m_name << "', "
  2303.        << uint32(getRace()) << ","
  2304.        << uint32(getClass()) << ","
  2305.        << uint32(getGender()) << ",";
  2306.  
  2307.     if(GetFaction() != info->factiontemplate)
  2308.         ss << GetFaction() << ",";
  2309.     else
  2310.         ss << "0,";
  2311.  
  2312.     ss << uint32(getLevel()) << ","
  2313.        << GetXp() << ","
  2314.        << active_cheats << ","
  2315.  
  2316.        // dump exploration data
  2317.        << "'";
  2318.  
  2319.     for(uint32 i = 0; i < PLAYER_EXPLORED_ZONES_LENGTH; ++i)
  2320.         ss << m_uint32Values[PLAYER_EXPLORED_ZONES_1 + i] << ",";
  2321.  
  2322.     ss << "',";
  2323.  
  2324.     SaveSkills(bNewCharacter, buf);
  2325.  
  2326.     ss << m_uint32Values[PLAYER_FIELD_WATCHED_FACTION_INDEX] << ","
  2327.        << m_uint32Values[PLAYER_CHOSEN_TITLE] << ","
  2328.        << GetUInt64Value(PLAYER__FIELD_KNOWN_TITLES) << ","
  2329.        << GetUInt64Value(PLAYER__FIELD_KNOWN_TITLES1) << ","
  2330.        << GetUInt64Value(PLAYER__FIELD_KNOWN_TITLES2) << ","
  2331.        << m_uint32Values[PLAYER_FIELD_COINAGE] << ",";
  2332.  
  2333.     if((getClass() == MAGE) || (getClass() == PRIEST) || (getClass() == WARLOCK))
  2334.         ss << (uint32)0 << ","; // make sure ammo slot is 0 for these classes, otherwise it can mess up wand shoot
  2335.     else
  2336.         ss << m_uint32Values[PLAYER_AMMO_ID] << ",";
  2337.     ss << GetPrimaryProfessionPoints() << ",";
  2338.  
  2339.     ss << load_health << ","
  2340.        << load_mana << ","
  2341.        << uint32(GetPVPRank()) << ","
  2342.        << m_uint32Values[PLAYER_BYTES] << ","
  2343.        << m_uint32Values[PLAYER_BYTES_2] << ",";
  2344.  
  2345.     uint32 player_flags = m_uint32Values[PLAYER_FLAGS];
  2346.  
  2347.     // Remove un-needed and problematic player flags from being saved :p
  2348.     if(player_flags & PLAYER_FLAG_PARTY_LEADER)
  2349.         player_flags &= ~PLAYER_FLAG_PARTY_LEADER;
  2350.  
  2351.     if(player_flags & PLAYER_FLAG_AFK)
  2352.         player_flags &= ~PLAYER_FLAG_AFK;
  2353.  
  2354.     if(player_flags & PLAYER_FLAG_DND)
  2355.         player_flags &= ~PLAYER_FLAG_DND;
  2356.  
  2357.     if(player_flags & PLAYER_FLAG_GM)
  2358.         player_flags &= ~PLAYER_FLAG_GM;
  2359.  
  2360.     if(player_flags & PLAYER_FLAG_PVP_TOGGLE)
  2361.         player_flags &= ~PLAYER_FLAG_PVP_TOGGLE;
  2362.  
  2363.     if(player_flags & PLAYER_FLAG_FREE_FOR_ALL_PVP)
  2364.         player_flags &= ~PLAYER_FLAG_FREE_FOR_ALL_PVP;
  2365.  
  2366.     ss << player_flags << ","
  2367.        << m_uint32Values[PLAYER_FIELD_BYTES] << ",";
  2368.  
  2369.     if(in_arena)
  2370.     {
  2371.         // if its an arena, save the entry coords instead
  2372.         ss << m_bgEntryPointX << ", ";
  2373.         ss << m_bgEntryPointY << ", ";
  2374.         ss << m_bgEntryPointZ << ", ";
  2375.         ss << m_bgEntryPointO << ", ";
  2376.         ss << m_bgEntryPointMap << ", ";
  2377.     }
  2378.     else
  2379.     {
  2380.         // save the normal position
  2381.         ss << m_position.x << ", "
  2382.            << m_position.y << ", "
  2383.            << m_position.z << ", "
  2384.            << m_position.o << ", "
  2385.            << m_mapId << ", ";
  2386.     }
  2387.  
  2388.     ss << m_zoneId << ", '";
  2389.  
  2390.     for(uint32 i = 0; i < 12; i++)
  2391.         ss << m_taximask[i] << " ";
  2392.     ss << "', "
  2393.  
  2394.        << m_banned << ", '"
  2395.        << CharacterDatabase.EscapeString(m_banreason) << "', "
  2396.        << uint32(UNIXTIME) << ",";
  2397.  
  2398.     //online state
  2399.     if(GetSession()->_loggingOut || bNewCharacter)
  2400.     {
  2401.         ss << "0,";
  2402.     }
  2403.     else
  2404.     {
  2405.         ss << "1,";
  2406.     }
  2407.  
  2408.     ss
  2409.             << m_bind_pos_x          << ", "
  2410.             << m_bind_pos_y          << ", "
  2411.             << m_bind_pos_z          << ", "
  2412.             << m_bind_mapid          << ", "
  2413.             << m_bind_zoneid            << ", "
  2414.  
  2415.             << uint32(m_isResting)    << ", "
  2416.             << uint32(m_restState)    << ", "
  2417.             << uint32(m_restAmount)  << ", '"
  2418.  
  2419.             << uint32(m_playedtime[0])  << " "
  2420.             << uint32(m_playedtime[1])  << " "
  2421.             << uint32(playedt)        << " ', "
  2422.             << uint32(m_deathState)  << ", "
  2423.  
  2424.             << m_talentresettimes      << ", "
  2425.             << m_FirstLogin          << ", "
  2426.             << rename_pending
  2427.             << "," << m_arenaPoints << ","
  2428.             << (uint32)m_StableSlotCount << ",";
  2429.  
  2430.     // instances
  2431.     if(in_arena)
  2432.     {
  2433.         ss << m_bgEntryPointInstance << ", ";
  2434.     }
  2435.     else
  2436.     {
  2437.         ss << m_instanceId         << ", ";
  2438.     }
  2439.  
  2440.     ss << m_bgEntryPointMap   << ", "
  2441.        << m_bgEntryPointX       << ", "
  2442.        << m_bgEntryPointY       << ", "
  2443.        << m_bgEntryPointZ       << ", "
  2444.        << m_bgEntryPointO       << ", "
  2445.        << m_bgEntryPointInstance << ", ";
  2446.  
  2447.     // taxi
  2448.     if(m_onTaxi && m_CurrentTaxiPath)
  2449.     {
  2450.         ss << m_CurrentTaxiPath->GetID() << ", ";
  2451.         ss << lastNode << ", ";
  2452.         ss << GetMount();
  2453.     }
  2454.     else
  2455.     {
  2456.         ss << "0, 0, 0";
  2457.     }
  2458.  
  2459.     ss << "," << (m_CurrentTransporter ? m_CurrentTransporter->GetEntry() : (uint32)0);
  2460.     ss << ",'" << transporter_info.x << "','" << transporter_info.y << "','" << transporter_info.z << "'";
  2461.     ss << ",'";
  2462.  
  2463.     SaveSpells(bNewCharacter, buf);
  2464.  
  2465.     SaveDeletedSpells(bNewCharacter, buf);
  2466.  
  2467.     SaveReputations( bNewCharacter, buf );
  2468.  
  2469.     // Add player action bars
  2470.     for(uint8 s = 0; s < MAX_SPEC_COUNT; ++s)
  2471.     {
  2472.         for(uint32 i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
  2473.         {
  2474.             ss  << uint32(m_specs[s].mActions[i].Action) << ","
  2475.                 << uint32(m_specs[s].mActions[i].Misc) << ","
  2476.                 << uint32(m_specs[s].mActions[i].Type) << ",";
  2477.         }
  2478.         ss << "','";
  2479.     }
  2480.  
  2481.     if(!bNewCharacter)
  2482.         SaveAuras(ss);
  2483.  
  2484.     ss << "','";
  2485.  
  2486.     // Add player finished quests
  2487.     set<uint32>::iterator fq = m_finishedQuests.begin();
  2488.     for(; fq != m_finishedQuests.end(); ++fq)
  2489.     {
  2490.         ss << (*fq) << ",";
  2491.     }
  2492.  
  2493.     ss << "', '";
  2494.     DailyMutex.Acquire();
  2495.     set<uint32>::iterator fdq = m_finishedDailies.begin();
  2496.     for(; fdq != m_finishedDailies.end(); fdq++)
  2497.     {
  2498.         ss << (*fdq) << ",";
  2499.     }
  2500.     DailyMutex.Release();
  2501.     ss << "', ";
  2502.     ss << m_honorRolloverTime << ", ";
  2503.     ss << m_killsToday << ", " << m_killsYesterday << ", " << m_killsLifetime << ", ";
  2504.     ss << m_honorToday << ", " << m_honorYesterday << ", ";
  2505.     ss << m_honorPoints << ", ";
  2506.     ss << iInstanceType << ", ";
  2507.  
  2508.     ss << (m_uint32Values[PLAYER_BYTES_3] & 0xFFFE) << ", ";
  2509.  
  2510.     for(uint8 s = 0; s < MAX_SPEC_COUNT; ++s)
  2511.     {
  2512.         ss << "'";
  2513.         for(uint8 i = 0; i < GLYPHS_COUNT; ++i)
  2514.             ss << m_specs[s].glyphs[i] << ",";
  2515.         ss << "','";
  2516.         for(std::map<uint32, uint8>::iterator itr = m_specs[s].talents.begin(); itr != m_specs[s].talents.end(); ++itr)
  2517.             ss << itr->first << "," << uint32(itr->second) << ",";
  2518.         ss << "',";
  2519.     }
  2520.     ss << uint32(m_talentSpecsCount) << ", " << uint32(m_talentActiveSpec);
  2521.     ss << ", '";
  2522.     ss << uint32(m_specs[SPEC_PRIMARY].GetTP() ) << " " << uint32(m_specs[SPEC_SECONDARY].GetTP() );
  2523.     ss << "', ";
  2524.  
  2525.     ss << "'" << m_phase << "','";
  2526.  
  2527.     uint32 xpfield;
  2528.  
  2529.     if(m_XpGain)
  2530.         xpfield = 1;
  2531.     else
  2532.         xpfield = 0;
  2533.  
  2534.     ss << xpfield << "'" << ", '";
  2535.  
  2536.     bool saveData = Config.MainConfig.GetBoolDefault("Server", "SaveExtendedCharData", false);
  2537.     if(saveData)
  2538.     {
  2539.         for(uint32 offset = OBJECT_END; offset < PLAYER_END; offset++)
  2540.             ss << uint32(m_uint32Values[ offset ]) << ";";
  2541.     }
  2542.     ss << "', '";
  2543.  
  2544.     if( resettalents )
  2545.         ss << uint32( 1 );
  2546.     else
  2547.         ss << uint32( 0 );
  2548.  
  2549.     ss << "')";
  2550.  
  2551.     if(bNewCharacter)
  2552.         CharacterDatabase.WaitExecuteNA(ss.str().c_str());
  2553.     else
  2554.         buf->AddQueryNA(ss.str().c_str());
  2555.  
  2556.     //Save Other related player stuff
  2557.  
  2558.     // Inventory
  2559.     GetItemInterface()->mSaveItemsToDatabase(bNewCharacter, buf);
  2560.  
  2561.     GetItemInterface()->m_EquipmentSets.SavetoDB(buf);
  2562.  
  2563.     // save quest progress
  2564.     _SaveQuestLogEntry(buf);
  2565.  
  2566.     // Tutorials
  2567.     _SaveTutorials(buf);
  2568.  
  2569.     // GM Ticket
  2570.     //TODO: Is this really necessary? Tickets will always be saved on creation, update and so on...
  2571.     GM_Ticket* ticket = objmgr.GetGMTicketByPlayer(GetGUID());
  2572.     if(ticket != NULL)
  2573.         objmgr.SaveGMTicket(ticket, buf);
  2574.  
  2575.     // Cooldown Items
  2576.     _SavePlayerCooldowns(buf);
  2577.  
  2578.     // Pets
  2579.     if(getClass() == HUNTER || getClass() == WARLOCK)
  2580.     {
  2581.         _SavePet(buf);
  2582.         _SavePetSpells(buf);
  2583.     }
  2584.     m_nextSave = getMSTime() + sWorld.getIntRate(INTRATE_SAVE);
  2585. #ifdef ENABLE_ACHIEVEMENTS
  2586.     m_achievementMgr.SaveToDB(buf);
  2587. #endif
  2588.  
  2589.     if(buf)
  2590.         CharacterDatabase.AddQueryBuffer(buf);
  2591. }
  2592.  
  2593. void Player::_SaveQuestLogEntry(QueryBuffer* buf)
  2594. {
  2595.     for(std::set<uint32>::iterator itr = m_removequests.begin(); itr != m_removequests.end(); ++itr)
  2596.     {
  2597.         if(buf == NULL)
  2598.             CharacterDatabase.Execute("DELETE FROM questlog WHERE player_guid=%u AND quest_id=%u", GetLowGUID(), (*itr));
  2599.         else
  2600.             buf->AddQuery("DELETE FROM questlog WHERE player_guid=%u AND quest_id=%u", GetLowGUID(), (*itr));
  2601.     }
  2602.  
  2603.     m_removequests.clear();
  2604.  
  2605.     for(int i = 0; i < 25; ++i)
  2606.     {
  2607.         if(m_questlog[i] != NULL)
  2608.             m_questlog[i]->SaveToDB(buf);
  2609.     }
  2610. }
  2611.  
  2612. bool Player::canCast(SpellEntry* m_spellInfo)
  2613. {
  2614.     if(m_spellInfo->EquippedItemClass != 0)
  2615.     {
  2616.         if(this->GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_MAINHAND))
  2617.         {
  2618.             if((int32)this->GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_MAINHAND)->GetProto()->Class == m_spellInfo->EquippedItemClass)
  2619.             {
  2620.                 if(m_spellInfo->EquippedItemSubClass != 0)
  2621.                 {
  2622.                     if(m_spellInfo->EquippedItemSubClass != 173555 && m_spellInfo->EquippedItemSubClass != 96 && m_spellInfo->EquippedItemSubClass != 262156)
  2623.                     {
  2624.                         if(pow(2.0, (this->GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_MAINHAND)->GetProto()->SubClass) != m_spellInfo->EquippedItemSubClass))
  2625.                             return false;
  2626.                     }
  2627.                 }
  2628.             }
  2629.         }
  2630.         else if(m_spellInfo->EquippedItemSubClass == 173555)
  2631.             return false;
  2632.  
  2633.         if(this->GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_RANGED))
  2634.         {
  2635.             if((int32)this->GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_RANGED)->GetProto()->Class == m_spellInfo->EquippedItemClass)
  2636.             {
  2637.                 if(m_spellInfo->EquippedItemSubClass != 0)
  2638.                 {
  2639.                     if(m_spellInfo->EquippedItemSubClass != 173555 && m_spellInfo->EquippedItemSubClass != 96 && m_spellInfo->EquippedItemSubClass != 262156)
  2640.                     {
  2641.                         if(pow(2.0, (this->GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_RANGED)->GetProto()->SubClass) != m_spellInfo->EquippedItemSubClass))                            return false;
  2642.                     }
  2643.                 }
  2644.             }
  2645.         }
  2646.         else if
  2647.         (m_spellInfo->EquippedItemSubClass == 262156)
  2648.             return false;
  2649.     }
  2650.     return true;
  2651. }
  2652.  
  2653. void Player::RemovePendingPlayer()
  2654. {
  2655.     if(m_session)
  2656.     {
  2657.         uint8 respons = E_CHAR_LOGIN_NO_CHARACTER;
  2658.         m_session->OutPacket(SMSG_CHARACTER_LOGIN_FAILED, 1, &respons);
  2659.         m_session->m_loggingInPlayer = NULL;
  2660.     }
  2661.  
  2662.     ok_to_remove = true;
  2663.     delete this;
  2664. }
  2665.  
  2666. bool Player::LoadFromDB(uint32 guid)
  2667. {
  2668.     AsyncQuery* q = new AsyncQuery(new SQLClassCallbackP0<Player>(this, &Player::LoadFromDBProc));
  2669.  
  2670.     q->AddQuery("SELECT * FROM characters WHERE guid = %u AND forced_rename_pending = 0", guid); // 0
  2671.     q->AddQuery("SELECT * FROM tutorials WHERE playerId = %u", guid); // 1
  2672.     q->AddQuery("SELECT cooldown_type, cooldown_misc, cooldown_expire_time, cooldown_spellid, cooldown_itemid FROM playercooldowns WHERE player_guid = %u", guid); // 2
  2673.     q->AddQuery("SELECT * FROM questlog WHERE player_guid = %u", guid); // 3
  2674.     q->AddQuery("SELECT * FROM playeritems WHERE ownerguid = %u ORDER BY containerslot ASC", guid); // 4
  2675.     q->AddQuery("SELECT * FROM playerpets WHERE ownerguid = %u ORDER BY petnumber", guid); // 5
  2676.     q->AddQuery("SELECT * FROM playersummonspells where ownerguid = %u ORDER BY entryid", guid); // 6
  2677.     q->AddQuery("SELECT * FROM mailbox WHERE player_guid = %u", guid); // 7
  2678.  
  2679.     // social
  2680.     q->AddQuery("SELECT friend_guid, note FROM social_friends WHERE character_guid = %u", guid); // 8
  2681.     q->AddQuery("SELECT character_guid FROM social_friends WHERE friend_guid = %u", guid); // 9
  2682.     q->AddQuery("SELECT ignore_guid FROM social_ignores WHERE character_guid = %u", guid); // 10
  2683.  
  2684.  
  2685.     q->AddQuery("SELECT * FROM equipmentsets WHERE ownerguid = %u", guid);  // 11
  2686.     q->AddQuery("SELECT faction, flag, basestanding, standing FROM playerreputations WHERE guid = %u", guid ); //12
  2687.     q->AddQuery("SELECT SpellID FROM playerspells WHERE GUID = %u", guid);  // 13
  2688.     q->AddQuery("SELECT SpellID FROM playerdeletedspells WHERE GUID = %u", guid);  // 14
  2689.     q->AddQuery("SELECT SkillID, CurrentValue, MaximumValue FROM playerskills WHERE GUID = %u", guid);  // 15
  2690.  
  2691.     //Achievements
  2692.     q->AddQuery("SELECT achievement, date FROM character_achievement WHERE guid = '%u'", guid); // 16
  2693.     q->AddQuery("SELECT criteria, counter, date FROM character_achievement_progress WHERE guid = '%u'", guid); // 17
  2694.  
  2695.     // queue it!
  2696.     SetLowGUID(guid);
  2697.     CharacterDatabase.QueueAsyncQuery(q);
  2698.     return true;
  2699.  
  2700. }
  2701.  
  2702. void Player::LoadFromDBProc(QueryResultVector & results)
  2703. {
  2704.     uint32 field_index = 2;
  2705. #define get_next_field fields[field_index++]
  2706.  
  2707.     if(GetSession() == NULL || results.size() < 8)      // should have 8 queryresults for aplayer load.
  2708.     {
  2709.         RemovePendingPlayer();
  2710.         return;
  2711.     }
  2712.  
  2713.     QueryResult* result = results[0].result;
  2714.     if(!result)
  2715.     {
  2716.         Log.Error("Player::LoadFromDB",
  2717.                   "Player login query failed! guid = %u",
  2718.                   GetLowGUID());
  2719.         RemovePendingPlayer();
  2720.         return;
  2721.     }
  2722.  
  2723.     const uint32 fieldcount = 91;
  2724.  
  2725.     if(result->GetFieldCount() != fieldcount)
  2726.     {
  2727.         Log.Error("Player::LoadFromDB",
  2728.                   "Expected %u fields from the database, "
  2729.                   "but received %u!  You may need to update your character database.", fieldcount,  uint32(result->GetFieldCount()));
  2730.         RemovePendingPlayer();
  2731.         return;
  2732.     }
  2733.  
  2734.     Field* fields = result->Fetch();
  2735.  
  2736.     if(fields[1].GetUInt32() != m_session->GetAccountId())
  2737.     {
  2738.         sCheatLog.writefromsession(m_session, "player tried to load character not belonging to them (guid %u, on account %u)",
  2739.                                    fields[0].GetUInt32(), fields[1].GetUInt32());
  2740.         RemovePendingPlayer();
  2741.         return;
  2742.     }
  2743.  
  2744.     uint32 banned = fields[34].GetUInt32();
  2745.     if(banned && (banned < 100 || banned > (uint32)UNIXTIME))
  2746.     {
  2747.         RemovePendingPlayer();
  2748.         return;
  2749.     }
  2750.  
  2751.     // Load name
  2752.     m_name = get_next_field.GetString();
  2753.     // Update Cache
  2754.     m_cache->SetStringValue(CACHE_PLAYER_NAME, m_name);
  2755.  
  2756.     // Load race/class from fields
  2757.     setRace(get_next_field.GetUInt8());
  2758.     setClass(get_next_field.GetUInt8());
  2759.     setGender(get_next_field.GetUInt8());
  2760.     uint32 cfaction = get_next_field.GetUInt32();
  2761.  
  2762.     // set race dbc
  2763.     myRace = dbcCharRace.LookupEntryForced(getRace());
  2764.     myClass = dbcCharClass.LookupEntryForced(getClass());
  2765.     if(!myClass || !myRace)
  2766.     {
  2767.         // bad character
  2768.         LOG_ERROR("guid %u failed to login, no race or class dbc found. (race %u class %u)", (unsigned int)GetLowGUID(), (unsigned int)getRace(), (unsigned int)getClass());
  2769.         RemovePendingPlayer();
  2770.         return;
  2771.     }
  2772.  
  2773.     if(myRace->team_id == 7)
  2774.     {
  2775.         m_bgTeam = m_team = 0;
  2776.     }
  2777.     else
  2778.     {
  2779.         m_bgTeam = m_team = 1;
  2780.     }
  2781.     m_cache->SetUInt32Value(CACHE_PLAYER_INITIALTEAM, m_team);
  2782.  
  2783.     SetNoseLevel();
  2784.  
  2785.     // set power type
  2786.     SetPowerType(static_cast<uint8>(myClass->power_type));
  2787.  
  2788.     // obtain player create info
  2789.     info = objmgr.GetPlayerCreateInfo(getRace(), getClass());
  2790.     if(!info)
  2791.     {
  2792.         LOG_ERROR("player guid %u has no playerCreateInfo!", (unsigned int)GetLowGUID());
  2793.         RemovePendingPlayer();
  2794.         return;
  2795.     }
  2796.  
  2797.     // set level
  2798.     setLevel(get_next_field.GetUInt32());
  2799.  
  2800.     // obtain level/stats information
  2801.     lvlinfo = objmgr.GetLevelInfo(getRace(), getClass(), getLevel());
  2802.  
  2803.     if(!lvlinfo)
  2804.     {
  2805.         LOG_ERROR("guid %u level %u class %u race %u levelinfo not found!", (unsigned int)GetLowGUID(), (unsigned int)getLevel(), (unsigned int)getClass(), (unsigned int)getRace());
  2806.         RemovePendingPlayer();
  2807.         return;
  2808.     }
  2809.  
  2810.     // load achievements before anything else otherwise skills would complete achievements already in the DB, leading to duplicate achievements and criterias(like achievement=126).
  2811. #ifdef ENABLE_ACHIEVEMENTS
  2812.     m_achievementMgr.LoadFromDB(results[16].result, results[17].result);
  2813. #endif
  2814.  
  2815.     CalculateBaseStats();
  2816.  
  2817.     // set xp
  2818.     SetXp(get_next_field.GetUInt32());
  2819.  
  2820.     // Load active cheats
  2821.     uint32 active_cheats = get_next_field.GetUInt32();
  2822.     if(active_cheats & 0x01)
  2823.         CooldownCheat = true;
  2824.     if(active_cheats & 0x02)
  2825.         CastTimeCheat = true;
  2826.     if(active_cheats & 0x04)
  2827.         GodModeCheat = true;
  2828.     if(active_cheats & 0x08)
  2829.         PowerCheat = true;
  2830.     if(active_cheats & 0x10)
  2831.         FlyCheat = true;
  2832.     if(active_cheats & 0x20)
  2833.         AuraStackCheat = true;
  2834.     if(active_cheats & 0x40)
  2835.         ItemStackCheat = true;
  2836.     if(active_cheats & 0x80)
  2837.         TriggerpassCheat = true;
  2838.  
  2839.     // Process exploration data.
  2840.     LoadFieldsFromString(get_next_field.GetString(), PLAYER_EXPLORED_ZONES_1, PLAYER_EXPLORED_ZONES_LENGTH);
  2841.  
  2842.     // Process skill data.
  2843.     uint32 Counter = 0;
  2844.     char* start = NULL;
  2845.     char* end = NULL;
  2846.  
  2847.     // new format
  2848.     const ItemProf* prof;
  2849.  
  2850.     LoadSkills(results[ 15 ].result);
  2851.  
  2852.     if(m_skills.empty())
  2853.     {
  2854.         /* no skills - reset to defaults */
  2855.         for(std::list<CreateInfo_SkillStruct>::iterator ss = info->skills.begin(); ss != info->skills.end(); ++ss)
  2856.         {
  2857.             if(ss->skillid && ss->currentval && ss->maxval && !::GetSpellForLanguage(ss->skillid))
  2858.                 _AddSkillLine(ss->skillid, ss->currentval, ss->maxval);
  2859.         }
  2860.     }
  2861.  
  2862.     for(SkillMap::iterator itr = m_skills.begin(); itr != m_skills.end(); ++itr)
  2863.     {
  2864.         if(itr->first == SKILL_RIDING)
  2865.         {
  2866.             itr->second.CurrentValue = itr->second.MaximumValue;
  2867.         }
  2868.  
  2869.         prof = GetProficiencyBySkill(itr->first);
  2870.         if(prof)
  2871.         {
  2872.             if(prof->itemclass == 4)
  2873.                 armor_proficiency |= prof->subclass;
  2874.             else
  2875.                 weapon_proficiency |= prof->subclass;
  2876.         }
  2877.         _LearnSkillSpells(itr->second.Skill->id, itr->second.CurrentValue);
  2878.     }
  2879.  
  2880.     // set the rest of the stuff
  2881.     m_uint32Values[ PLAYER_FIELD_WATCHED_FACTION_INDEX ]    = get_next_field.GetUInt32();
  2882.     SetChosenTitle(get_next_field.GetUInt32());
  2883.     SetUInt64Value(PLAYER__FIELD_KNOWN_TITLES, get_next_field.GetUInt64());
  2884.     SetUInt64Value(PLAYER__FIELD_KNOWN_TITLES1, get_next_field.GetUInt64());
  2885.     SetUInt64Value(PLAYER__FIELD_KNOWN_TITLES2, get_next_field.GetUInt64());
  2886.     m_uint32Values[ PLAYER_FIELD_COINAGE ]                  = get_next_field.GetUInt32();
  2887.     m_uint32Values[ PLAYER_AMMO_ID ]                        = get_next_field.GetUInt32();
  2888.     m_uint32Values[ PLAYER_CHARACTER_POINTS2 ]              = get_next_field.GetUInt32();
  2889.     load_health                                             = get_next_field.GetUInt32();
  2890.     load_mana                                               = get_next_field.GetUInt32();
  2891.     SetHealth(load_health);
  2892.     uint8 pvprank = get_next_field.GetUInt8();
  2893.     SetUInt32Value(PLAYER_BYTES, get_next_field.GetUInt32());
  2894.     SetUInt32Value(PLAYER_BYTES_2, get_next_field.GetUInt32());
  2895.     SetUInt32Value(PLAYER_BYTES_3, getGender() | (pvprank << 24));
  2896.     SetUInt32Value(PLAYER_FLAGS, get_next_field.GetUInt32());
  2897.     SetUInt32Value(PLAYER_FIELD_BYTES, get_next_field.GetUInt32());
  2898.     //m_uint32Values[0x22]=(m_uint32Values[0x22]>0x46)?0x46:m_uint32Values[0x22];
  2899.  
  2900.     m_position.x                                        = get_next_field.GetFloat();
  2901.     m_position.y                                        = get_next_field.GetFloat();
  2902.     m_position.z                                        = get_next_field.GetFloat();
  2903.     m_position.o                                        = get_next_field.GetFloat();
  2904.  
  2905.     m_mapId                                             = get_next_field.GetUInt32();
  2906.     m_zoneId                                            = get_next_field.GetUInt32();
  2907.     SetZoneId(m_zoneId);
  2908.  
  2909.     // Calculate the base stats now they're all loaded
  2910.     for(uint32 i = 0; i < 5; ++i)
  2911.         CalcStat(i);
  2912.  
  2913.     //  for(uint32 x = PLAYER_SPELL_CRIT_PERCENTAGE1; x < PLAYER_SPELL_CRIT_PERCENTAGE06 + 1; ++x)
  2914.     /// SetFloatValue(x, 0.0f);
  2915.  
  2916.     for(uint32 x = PLAYER_FIELD_MOD_DAMAGE_DONE_PCT; x < PLAYER_FIELD_MOD_HEALING_DONE_POS; ++x)
  2917.         SetFloatValue(x, 1.0f);
  2918.  
  2919.     // Normal processing...
  2920.     UpdateStats();
  2921.  
  2922.     // Initialize 'normal' fields
  2923.     SetScale(1.0f);
  2924.     //SetUInt32Value(UNIT_FIELD_POWER2, 0);
  2925.     SetPower(POWER_TYPE_FOCUS, info->focus); // focus
  2926.     SetPower(POWER_TYPE_ENERGY, info->energy);
  2927.     SetPower(POWER_TYPE_RUNES, 8);
  2928.     SetMaxPower(POWER_TYPE_RAGE, info->rage);
  2929.     SetMaxPower(POWER_TYPE_FOCUS, info->focus);
  2930.     SetMaxPower(POWER_TYPE_ENERGY, info->energy);
  2931.     SetMaxPower(POWER_TYPE_RUNES, 8);
  2932.     SetMaxPower(POWER_TYPE_RUNIC_POWER, 1000);
  2933.     if(getClass() == WARRIOR)
  2934.         SetShapeShift(FORM_BATTLESTANCE);
  2935.  
  2936.     SetUInt32Value(UNIT_FIELD_BYTES_2, (0x28 << 8));
  2937.     SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
  2938.     SetBoundingRadius(0.388999998569489f);
  2939.     SetCombatReach(1.5f);
  2940.  
  2941.     if(getRace() != RACE_BLOODELF)
  2942.     {
  2943.         SetDisplayId(info->displayId + getGender());
  2944.         SetNativeDisplayId(info->displayId + getGender());
  2945.     }
  2946.     else
  2947.     {
  2948.         SetDisplayId(info->displayId - getGender());
  2949.         SetNativeDisplayId(info->displayId - getGender());
  2950.     }
  2951.     EventModelChange();
  2952.  
  2953.     SetCastSpeedMod(1.0f);
  2954.     SetUInt32Value(PLAYER_FIELD_MAX_LEVEL, sWorld.m_levelCap);
  2955.     SetFaction(info->factiontemplate);
  2956.     if(cfaction)
  2957.     {
  2958.         SetFaction(cfaction);
  2959.         // re-calculate team
  2960.         switch(cfaction)
  2961.         {
  2962.             case 1: // human
  2963.             case 3: // dwarf
  2964.             case 4: // ne
  2965.             case 8: // gnome
  2966.             case 927:   // draenei
  2967.                 m_team = m_bgTeam = 0;
  2968.                 break;
  2969.             case 2: // orc
  2970.             case 5: // undead
  2971.             case 6: // tauren
  2972.             case 9: // troll
  2973.             case 914: // bloodelf
  2974.                 m_team = m_bgTeam = 1;
  2975.                 break;
  2976.         }
  2977.     }
  2978.  
  2979.     LoadTaxiMask(get_next_field.GetString());
  2980.  
  2981.     m_banned = get_next_field.GetUInt32(); //Character ban
  2982.     m_banreason = get_next_field.GetString();
  2983.     m_timeLogoff = get_next_field.GetUInt32();
  2984.     field_index++;
  2985.  
  2986.     m_bind_pos_x = get_next_field.GetFloat();
  2987.     m_bind_pos_y = get_next_field.GetFloat();
  2988.     m_bind_pos_z = get_next_field.GetFloat();
  2989.     m_bind_mapid = get_next_field.GetUInt32();
  2990.     m_bind_zoneid = get_next_field.GetUInt32();
  2991.  
  2992.     m_isResting = get_next_field.GetUInt8();
  2993.     m_restState = get_next_field.GetUInt8();
  2994.     m_restAmount = get_next_field.GetUInt32();
  2995.  
  2996.  
  2997.     std::string tmpStr = get_next_field.GetString();
  2998.     m_playedtime[0] = (uint32)atoi((const char*)strtok((char*)tmpStr.c_str(), " "));
  2999.     m_playedtime[1] = (uint32)atoi((const char*)strtok(NULL, " "));
  3000.  
  3001.     m_deathState = (DeathState)get_next_field.GetUInt32();
  3002.     m_talentresettimes = get_next_field.GetUInt32();
  3003.     m_FirstLogin = get_next_field.GetBool();
  3004.     rename_pending = get_next_field.GetBool();
  3005.     m_arenaPoints = get_next_field.GetUInt32();
  3006.     if(m_arenaPoints > sWorld.m_limits.arenapoints)
  3007.     {  
  3008.         char hlogmsg[256]; 
  3009.         snprintf(hlogmsg, 256, "has over %u arena points (%u)", sWorld.m_limits.arenapoints, m_arenaPoints);
  3010.         sCheatLog.writefromsession(m_session, hlogmsg);
  3011.         if(sWorld.m_limits.broadcast) // report to online GMs  
  3012.         {
  3013.           string gm_ann = MSG_COLOR_GREEN; 
  3014.           gm_ann += "|Hplayer:";
  3015.           gm_ann += GetName();
  3016.           gm_ann += "|h[";
  3017.           gm_ann += GetName();
  3018.           gm_ann += "]|h: ";
  3019.           gm_ann += MSG_COLOR_YELLOW;
  3020.           gm_ann += hlogmsg;
  3021.           sWorld.SendGMWorldText(gm_ann.c_str());  
  3022.         }
  3023.         if(sWorld.m_limits.disconnect)
  3024.         {
  3025.             m_session->Disconnect();   
  3026.         }
  3027.         m_arenaPoints = sWorld.m_limits.arenapoints;
  3028.       }
  3029.     for(uint32 z = 0; z < NUM_CHARTER_TYPES; ++z)
  3030.         m_charters[z] = objmgr.GetCharterByGuid(GetGUID(), (CharterTypes)z);
  3031.     for(uint32 z = 0; z < NUM_ARENA_TEAM_TYPES; ++z)
  3032.     {
  3033.         m_arenaTeams[z] = objmgr.GetArenaTeamByGuid(GetLowGUID(), z);
  3034.         if(m_arenaTeams[z] != NULL)
  3035.         {
  3036.             SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (z * 7), m_arenaTeams[z]->m_id);
  3037.             if(m_arenaTeams[z]->m_leader == GetLowGUID())
  3038.                 SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (z * 7) + 1, 0);
  3039.             else
  3040.                 SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (z * 7) + 1, 1);
  3041.         }
  3042.     }
  3043.  
  3044.     m_StableSlotCount = static_cast<uint8>(get_next_field.GetUInt32());
  3045.     m_instanceId = get_next_field.GetUInt32();
  3046.     m_bgEntryPointMap = get_next_field.GetUInt32();
  3047.     m_bgEntryPointX = get_next_field.GetFloat();
  3048.     m_bgEntryPointY = get_next_field.GetFloat();
  3049.     m_bgEntryPointZ = get_next_field.GetFloat();
  3050.     m_bgEntryPointO = get_next_field.GetFloat();
  3051.     m_bgEntryPointInstance = get_next_field.GetUInt32();
  3052.  
  3053.     uint32 taxipath = get_next_field.GetUInt32();
  3054.     TaxiPath* path = NULL;
  3055.     if(taxipath)
  3056.     {
  3057.         path = sTaxiMgr.GetTaxiPath(taxipath);
  3058.         lastNode = get_next_field.GetUInt32();
  3059.         if(path)
  3060.         {
  3061.             SetMount(get_next_field.GetUInt32());
  3062.             SetTaxiPath(path);
  3063.             m_onTaxi = true;
  3064.         }
  3065.         else
  3066.             field_index++;
  3067.     }
  3068.     else
  3069.     {
  3070.         field_index++;
  3071.         field_index++;
  3072.     }
  3073.  
  3074.     transporter_info.guid = get_next_field.GetUInt32();
  3075.     if(transporter_info.guid)
  3076.     {
  3077.         Transporter* t = objmgr.GetTransporter(Arcemu::Util::GUID_LOPART(transporter_info.guid));
  3078.         transporter_info.guid = t ? t->GetGUID() : 0;
  3079.     }
  3080.  
  3081.     transporter_info.x = get_next_field.GetFloat();
  3082.     transporter_info.y = get_next_field.GetFloat();
  3083.     transporter_info.z = get_next_field.GetFloat();
  3084.  
  3085.     LoadSpells(results[ 13 ].result);
  3086.  
  3087.     LoadDeletedSpells(results[ 14 ].result);
  3088.  
  3089.     LoadReputations( results[ 12 ].result );
  3090.  
  3091.     // Load saved actionbars
  3092.     for(uint8 s = 0; s < MAX_SPEC_COUNT; ++s)
  3093.     {
  3094.         start = (char*)get_next_field.GetString();
  3095.         Counter = 0;
  3096.         while(Counter < PLAYER_ACTION_BUTTON_COUNT)
  3097.         {
  3098.             end = strchr(start, ',');
  3099.             if(!end)break;
  3100.             *end = 0;
  3101.             m_specs[s].mActions[Counter].Action = (uint16)atol(start);
  3102.             start = end + 1;
  3103.             end = strchr(start, ',');
  3104.             if(!end)break;
  3105.             *end = 0;
  3106.             m_specs[s].mActions[Counter].Misc = (uint8)atol(start);
  3107.             start = end + 1;
  3108.             end = strchr(start, ',');
  3109.             if(!end)break;
  3110.             *end = 0;
  3111.             m_specs[s].mActions[Counter++].Type = (uint8)atol(start);
  3112.             start = end + 1;
  3113.         }
  3114.     }
  3115.  
  3116.     start = (char*)get_next_field.GetString();//buff;
  3117.     do
  3118.     {
  3119.         end = strchr(start, ',');
  3120.         if(!end)break;
  3121.         *end = 0;
  3122.         LoginAura la;
  3123.         la.id = atol(start);
  3124.         start = end + 1;
  3125.         end = strchr(start, ',');
  3126.         if(!end)break;
  3127.         *end = 0;
  3128.         la.dur = atol(start);
  3129.         start = end + 1;
  3130.         end = strchr(start, ',');
  3131.         if(!end)break;
  3132.         *end = 0;
  3133.         la.positive = (start != NULL);
  3134.         start = end + 1;
  3135.         end = strchr(start, ',');
  3136.         if(!end)break;
  3137.         *end = 0;
  3138.         la.charges = atol(start);
  3139.         start = end + 1;
  3140.         loginauras.push_back(la);
  3141.     }
  3142.     while(true);
  3143.  
  3144.     // Load saved finished quests
  3145.  
  3146.     start = (char*)get_next_field.GetString();
  3147.     while(true)
  3148.     {
  3149.         end = strchr(start, ',');
  3150.         if(!end)break;
  3151.         *end = 0;
  3152.         m_finishedQuests.insert(atol(start));
  3153.         start = end + 1;
  3154.     }
  3155.  
  3156.     start = (char*)get_next_field.GetString();
  3157.     while(true)
  3158.     {
  3159.         end = strchr(start, ',');
  3160.         if(!end) break;
  3161.         *end = 0;
  3162.         m_finishedDailies.insert(atol(start));
  3163.         start = end + 1;
  3164.     }
  3165.  
  3166.     m_honorRolloverTime = get_next_field.GetUInt32();
  3167.     m_killsToday = get_next_field.GetUInt32();
  3168.     m_killsYesterday = get_next_field.GetUInt32();
  3169.     m_killsLifetime = get_next_field.GetUInt32();
  3170.  
  3171.     m_honorToday = get_next_field.GetUInt32();
  3172.     m_honorYesterday = get_next_field.GetUInt32();
  3173.     m_honorPoints = get_next_field.GetUInt32();
  3174.     if(m_honorPoints > sWorld.m_limits.honorpoints)
  3175.         {
  3176.           char hlogmsg[256];   
  3177.           snprintf(hlogmsg, 256, "has over %u honor points (%u)", sWorld.m_limits.honorpoints, m_honorPoints); 
  3178.           sCheatLog.writefromsession(m_session, hlogmsg);
  3179.           if(sWorld.m_limits.broadcast) // report to online GMs
  3180.           {
  3181.             string gm_ann = MSG_COLOR_GREEN;   
  3182.             gm_ann += "|Hplayer:"; 
  3183.             gm_ann += GetName();
  3184.             gm_ann += "|h[";
  3185.             gm_ann += GetName();
  3186.             gm_ann += "]|h: ";
  3187.             gm_ann += MSG_COLOR_YELLOW;
  3188.             gm_ann += hlogmsg;
  3189.             sWorld.SendGMWorldText(gm_ann.c_str());
  3190.           }
  3191.           if(sWorld.m_limits.disconnect)
  3192.           {
  3193.               m_session->Disconnect();
  3194.           }
  3195.           m_honorPoints = sWorld.m_limits.honorpoints;
  3196.         }
  3197.  
  3198.     RolloverHonor();
  3199.     iInstanceType = get_next_field.GetUInt32();
  3200.  
  3201.     // Load drunk value and calculate sobering. after 15 minutes logged out, the player will be sober again
  3202.     uint32 timediff = (uint32)UNIXTIME - m_timeLogoff;
  3203.     uint32 soberFactor;
  3204.     if(timediff > 900)
  3205.         soberFactor = 0;
  3206.     else
  3207.         soberFactor = 1 - timediff / 900;
  3208.     SetDrunkValue(uint16(soberFactor * get_next_field.GetUInt32()));
  3209.  
  3210.     for(uint8 s = 0; s < MAX_SPEC_COUNT; ++s)
  3211.     {
  3212.         start = (char*)get_next_field.GetString();
  3213.         uint8 glyphid = 0;
  3214.         while(glyphid < GLYPHS_COUNT)
  3215.         {
  3216.             end = strchr(start, ',');
  3217.             if(!end)break;
  3218.             *end = 0;
  3219.             m_specs[s].glyphs[glyphid] = (uint16)atol(start);
  3220.             ++glyphid;
  3221.             start = end + 1;
  3222.         }
  3223.  
  3224.         //Load talents for spec
  3225.         start = (char*)get_next_field.GetString();
  3226.         while(end != NULL)
  3227.         {
  3228.             end = strchr(start, ',');
  3229.             if(!end)
  3230.                 break;
  3231.             *end = 0;
  3232.             uint32 talentid = atol(start);
  3233.             start = end + 1;
  3234.  
  3235.             end = strchr(start, ',');
  3236.             if(!end)
  3237.                 break;
  3238.             *end = 0;
  3239.             uint8 rank = (uint8)atol(start);
  3240.             start = end + 1;
  3241.  
  3242.             m_specs[s].talents.insert(pair<uint32, uint8>(talentid, rank));
  3243.         }
  3244.     }
  3245.  
  3246.     m_talentSpecsCount = get_next_field.GetUInt8();
  3247.     m_talentActiveSpec = get_next_field.GetUInt8();
  3248.  
  3249.     {
  3250.         std::stringstream ss( get_next_field.GetString() );
  3251.         uint32 tp1 = 0;
  3252.         uint32 tp2 = 0;
  3253.  
  3254.         ss >> tp1;
  3255.         ss >> tp2;
  3256.  
  3257.         m_specs[ SPEC_PRIMARY ].SetTP( tp1 );
  3258.         m_specs[ SPEC_SECONDARY ].SetTP( tp2 );
  3259.         SetUInt32Value( PLAYER_CHARACTER_POINTS1, m_specs[ m_talentActiveSpec ].GetTP() );
  3260.     }
  3261.  
  3262.     m_phase = get_next_field.GetUInt32(); //Load the player's last phase
  3263.  
  3264.     uint32 xpfield = get_next_field.GetUInt32();
  3265.  
  3266.     if(xpfield == 0)
  3267.         m_XpGain = false;
  3268.     else
  3269.         m_XpGain = true;
  3270.  
  3271.     get_next_field;//skipping one
  3272.  
  3273.     if( get_next_field.GetUInt32() == 1 )
  3274.         resettalents = true;
  3275.     else
  3276.         resettalents = false;
  3277.  
  3278.     HonorHandler::RecalculateHonorFields(this);
  3279.  
  3280.     for(uint32 x = 0; x < 5; x++)
  3281.         BaseStats[x] = GetStat(x);
  3282.  
  3283.     UpdateGlyphs();
  3284.  
  3285.     for(uint8 i = 0; i < GLYPHS_COUNT; ++i)
  3286.     {
  3287.         SetGlyph(i, m_specs[m_talentActiveSpec].glyphs[i]);
  3288.     }
  3289.  
  3290.     //class fixes
  3291.     switch(getClass())
  3292.     {
  3293.         case PALADIN:
  3294.             armor_proficiency |= (1 << 7);  //LIBRAM
  3295.             break;
  3296.         case DRUID:
  3297.             armor_proficiency |= (1 << 8);  //IDOL
  3298.             break;
  3299.         case SHAMAN:
  3300.             armor_proficiency |= (1 << 9);  //TOTEM
  3301.             break;
  3302.         case DEATHKNIGHT:
  3303.             armor_proficiency |= (1 << 10);  //SIGIL
  3304.             break;
  3305.         case WARLOCK:
  3306.         case HUNTER:
  3307.             _LoadPet(results[5].result);
  3308.             _LoadPetSpells(results[6].result);
  3309.             break;
  3310.     }
  3311.  
  3312.     if(m_session->CanUseCommand('c'))
  3313.         _AddLanguages(true);
  3314.     else
  3315.         _AddLanguages(false);
  3316.  
  3317.     OnlineTime  = (uint32)UNIXTIME;
  3318.     if(GetGuildId())
  3319.         SetUInt32Value(PLAYER_GUILD_TIMESTAMP, (uint32)UNIXTIME);
  3320.  
  3321. #undef get_next_field
  3322.  
  3323.     // load properties
  3324.     _LoadTutorials(results[1].result);
  3325.     _LoadPlayerCooldowns(results[2].result);
  3326.     _LoadQuestLogEntry(results[3].result);
  3327.     m_ItemInterface->mLoadItemsFromDatabase(results[4].result);
  3328.     m_ItemInterface->m_EquipmentSets.LoadfromDB(results[ 11 ].result);
  3329.  
  3330.     m_mailBox.Load(results[7].result);
  3331.  
  3332.     // SOCIAL
  3333.     if(results[8].result != NULL)           // this query is "who are our friends?"
  3334.     {
  3335.         result = results[8].result;
  3336.         do
  3337.         {
  3338.             fields = result->Fetch();
  3339.             uint32 friendguid = fields[0].GetUInt32();
  3340.             const char* str = fields[1].GetString();
  3341.             char* note = NULL;
  3342.             if(strlen(str) > 0)
  3343.                 note = strdup(str);
  3344.             m_cache->InsertValue64(CACHE_SOCIAL_FRIENDLIST, friendguid, note);
  3345.         }
  3346.         while(result->NextRow());
  3347.     }
  3348.  
  3349.     if(results[9].result != NULL)           // this query is "who has us in their friends?"
  3350.     {
  3351.         result = results[9].result;
  3352.         do
  3353.         {
  3354.             m_cache->InsertValue64(CACHE_SOCIAL_HASFRIENDLIST, result->Fetch()[0].GetUInt32());
  3355.         }
  3356.         while(result->NextRow());
  3357.     }
  3358.  
  3359.     if(results[10].result != NULL)      // this query is "who are we ignoring"
  3360.     {
  3361.         result = results[10].result;
  3362.         do
  3363.         {
  3364.             uint32 guid = result->Fetch()[0].GetUInt32();
  3365.             m_cache->InsertValue64(CACHE_SOCIAL_IGNORELIST, guid);
  3366.         }
  3367.         while(result->NextRow());
  3368.     }
  3369.  
  3370.     // END SOCIAL
  3371.  
  3372.     // Check skills that player shouldn't have
  3373.     if(_HasSkillLine(SKILL_DUAL_WIELD) && !HasSpell(674))
  3374.     {
  3375.         _RemoveSkillLine(SKILL_DUAL_WIELD);
  3376.     }
  3377.  
  3378.     // update achievements before adding player to World, otherwise we'll get a nice race condition.
  3379.     //move CheckAllAchievementCriteria() after FullLogin(this) and i'll cut your b***s.
  3380. #ifdef ENABLE_ACHIEVEMENTS
  3381.     m_achievementMgr.CheckAllAchievementCriteria();
  3382. #endif
  3383.  
  3384.     m_session->FullLogin(this);
  3385.     m_session->m_loggingInPlayer = NULL;
  3386.  
  3387.     if(!isAlive())
  3388.     {
  3389.         Corpse* myCorpse = objmgr.GetCorpseByOwner(GetLowGUID());
  3390.         if(myCorpse != NULL)
  3391.         {
  3392.             myCorpseLocation = myCorpse->GetPosition();
  3393.             myCorpseInstanceId = myCorpse->GetInstanceID();
  3394.         }
  3395.     }
  3396.  
  3397.     // check for multiple gems with unique-equipped flag
  3398.     uint32 count;
  3399.     uint32 uniques[64];
  3400.     int nuniques = 0;
  3401.  
  3402.     for(uint8 x = EQUIPMENT_SLOT_START; x < EQUIPMENT_SLOT_END; ++x)
  3403.     {
  3404.         ItemInterface* itemi = GetItemInterface();
  3405.         Item* it = itemi->GetInventoryItem(x);
  3406.  
  3407.         if(it != NULL)
  3408.         {
  3409.             for(count = 0; count < it->GetSocketsCount(); count++)
  3410.             {
  3411.                 EnchantmentInstance* ei = it->GetEnchantment(SOCK_ENCHANTMENT_SLOT1 + count);
  3412.  
  3413.                 if(ei && ei->Enchantment)
  3414.                 {
  3415.                     ItemPrototype* ip = ItemPrototypeStorage.LookupEntry(ei->Enchantment->GemEntry);
  3416.  
  3417.                     if(ip && ip->Flags & ITEM_FLAG_UNIQUE_EQUIP &&
  3418.                             itemi->IsEquipped(ip->ItemId))
  3419.                     {
  3420.                         int i;
  3421.  
  3422.                         for(i = 0; i < nuniques; i++)
  3423.                         {
  3424.                             if(uniques[i] == ip->ItemId)
  3425.                             {
  3426.                                 // found a duplicate unique-equipped gem, remove it
  3427.                                 it->RemoveEnchantment(2 + count);
  3428.                                 break;
  3429.                             }
  3430.                         }
  3431.  
  3432.                         if(i == nuniques)  // not found
  3433.                             uniques[nuniques++] = ip->ItemId;
  3434.                     }
  3435.                 }
  3436.             }
  3437.         }
  3438.     }
  3439. }
  3440.  
  3441. void Player::SetPersistentInstanceId(Instance* pInstance)
  3442. {
  3443.     if(pInstance == NULL)
  3444.         return;
  3445.     // Skip this handling for flagged GMs.
  3446.     if(HasFlag(PLAYER_FLAGS, PLAYER_FLAG_GM))
  3447.         return;
  3448.     // Bind instance to "my" group.
  3449.     if(m_playerInfo && m_playerInfo->m_Group && pInstance->m_creatorGroup == 0)
  3450.         pInstance->m_creatorGroup = m_playerInfo && m_playerInfo->m_Group->GetID();
  3451.     // Skip handling for non-persistent instances.
  3452.     if(!IS_PERSISTENT_INSTANCE(pInstance))
  3453.         return;
  3454.     // Set instance for group if not done yet.
  3455.     if(m_playerInfo && m_playerInfo->m_Group && (m_playerInfo->m_Group->m_instanceIds[pInstance->m_mapId][pInstance->m_difficulty] == 0 || !sInstanceMgr.InstanceExists(pInstance->m_mapId, m_playerInfo->m_Group->m_instanceIds[pInstance->m_mapId][pInstance->m_difficulty])))
  3456.     {
  3457.         m_playerInfo->m_Group->m_instanceIds[pInstance->m_mapId][pInstance->m_difficulty] = pInstance->m_instanceId;
  3458.         m_playerInfo->m_Group->SaveToDB();
  3459.     }
  3460.     // Instance is not saved yet (no bosskill)
  3461.     if(!pInstance->m_persistent)
  3462.     {
  3463.         SetPersistentInstanceId(pInstance->m_mapId, pInstance->m_difficulty, 0);
  3464.     }
  3465.     // Set instance id to player.
  3466.     else
  3467.     {
  3468.         SetPersistentInstanceId(pInstance->m_mapId, pInstance->m_difficulty, pInstance->m_instanceId);
  3469.     }
  3470.     LOG_DEBUG("Added player %u to saved instance %u on map %u.", (uint32)GetGUID(), pInstance->m_instanceId, pInstance->m_mapId);
  3471. }
  3472.  
  3473. void Player::SetPersistentInstanceId(uint32 mapId, uint32 difficulty, uint32 instanceId)
  3474. {
  3475.     if(mapId >= NUM_MAPS || difficulty >= NUM_INSTANCE_MODES || m_playerInfo == NULL)
  3476.         return;
  3477.     m_playerInfo->savedInstanceIdsLock.Acquire();
  3478.     PlayerInstanceMap::iterator itr = m_playerInfo->savedInstanceIds[difficulty].find(mapId);
  3479.     if(itr == m_playerInfo->savedInstanceIds[difficulty].end())
  3480.     {
  3481.         if(instanceId != 0)
  3482.             m_playerInfo->savedInstanceIds[difficulty].insert(PlayerInstanceMap::value_type(mapId, instanceId));
  3483.     }
  3484.     else
  3485.     {
  3486.         if(instanceId == 0)
  3487.             m_playerInfo->savedInstanceIds[difficulty].erase(itr);
  3488.         else
  3489.             (*itr).second = instanceId;
  3490.     }
  3491.     m_playerInfo->savedInstanceIdsLock.Release();
  3492.     CharacterDatabase.Execute("DELETE FROM instanceids WHERE playerguid = %u AND mapid = %u AND mode = %u;", m_playerInfo->guid, mapId, difficulty);
  3493.     CharacterDatabase.Execute("INSERT INTO instanceids (playerguid, mapid, mode, instanceid) VALUES ( %u, %u, %u, %u )", m_playerInfo->guid, mapId, difficulty, instanceId);
  3494. }
  3495.  
  3496. void Player::RolloverHonor()
  3497. {
  3498.     uint32 current_val = (g_localTime.tm_year << 16) | g_localTime.tm_yday;
  3499.     if(current_val != m_honorRolloverTime)
  3500.     {
  3501.         m_honorRolloverTime = current_val;
  3502.         m_honorYesterday = m_honorToday;
  3503.         m_killsYesterday = m_killsToday;
  3504.         m_honorToday = m_killsToday = 0;
  3505.     }
  3506. }
  3507.  
  3508. void Player::_LoadQuestLogEntry(QueryResult* result)
  3509. {
  3510.     QuestLogEntry* entry;
  3511.     Quest* quest;
  3512.     Field* fields;
  3513.     uint32 questid;
  3514.     uint32 baseindex;
  3515.  
  3516.     // clear all fields
  3517.     for(int i = 0; i < 25; ++i)
  3518.     {
  3519.         baseindex = PLAYER_QUEST_LOG_1_1 + (i * 5);
  3520.         SetUInt32Value(baseindex + 0, 0);
  3521.         SetUInt32Value(baseindex + 1, 0);
  3522.         SetUInt64Value(baseindex + 2, 0);
  3523.         SetUInt32Value(baseindex + 4, 0);
  3524.     }
  3525.  
  3526.     int slot = 0;
  3527.  
  3528.     if(result)
  3529.     {
  3530.         do
  3531.         {
  3532.             fields = result->Fetch();
  3533.             questid = fields[1].GetUInt32();
  3534.             quest = QuestStorage.LookupEntry(questid);
  3535.             slot = fields[2].GetUInt32();
  3536.             ARCEMU_ASSERT(slot != -1);
  3537.  
  3538.             // remove on next save if bad quest
  3539.             if(!quest)
  3540.             {
  3541.                 m_removequests.insert(questid);
  3542.                 continue;
  3543.             }
  3544.             if(m_questlog[slot] != 0)
  3545.                 continue;
  3546.  
  3547.             entry = new QuestLogEntry;
  3548.             entry->Init(quest, this, slot);
  3549.             entry->LoadFromDB(fields);
  3550.             entry->UpdatePlayerFields();
  3551.  
  3552.         }
  3553.         while(result->NextRow());
  3554.     }
  3555. }
  3556.  
  3557. QuestLogEntry* Player::GetQuestLogForEntry(uint32 quest)
  3558. {
  3559.     for(int i = 0; i < MAX_QUEST_LOG_SIZE; ++i)
  3560.     {
  3561.         if(m_questlog[i] != NULL)
  3562.         {
  3563.             if(m_questlog[i]->GetQuest()->id == quest)
  3564.                 return m_questlog[i];
  3565.         }
  3566.     }
  3567.     return NULL;
  3568. }
  3569.  
  3570. void Player::SetQuestLogSlot(QuestLogEntry* entry, uint32 slot)
  3571. {
  3572.     m_questlog[slot] = entry;
  3573. }
  3574.  
  3575. void Player::AddToWorld()
  3576. {
  3577.     FlyCheat = false;
  3578.     m_setflycheat = false;
  3579.  
  3580.     // check transporter
  3581.     if(transporter_info.guid && m_CurrentTransporter)
  3582.     {
  3583.         SetPosition(m_CurrentTransporter->GetPositionX() + transporter_info.x,
  3584.                     m_CurrentTransporter->GetPositionY() + transporter_info.y,
  3585.                     m_CurrentTransporter->GetPositionZ() + transporter_info.z,
  3586.                     GetOrientation(), false);
  3587.     }
  3588.  
  3589.     // If we join an invalid instance and get booted out, this will prevent our stats from doubling :P
  3590.     if(IsInWorld())
  3591.         return;
  3592.  
  3593.     m_beingPushed = true;
  3594.     Object::AddToWorld();
  3595.  
  3596.     // Add failed.
  3597.     if(m_mapMgr == NULL)
  3598.     {
  3599.         // eject from instance
  3600.         m_beingPushed = false;
  3601.         EjectFromInstance();
  3602.         return;
  3603.     }
  3604.  
  3605.     if(m_session)
  3606.         m_session->SetInstance(m_mapMgr->GetInstanceID());
  3607.  
  3608.     SendInstanceDifficulty(m_mapMgr->iInstanceMode);
  3609. }
  3610.  
  3611. void Player::AddToWorld(MapMgr* pMapMgr)
  3612. {
  3613.     FlyCheat = false;
  3614.     m_setflycheat = false;
  3615.     // check transporter
  3616.     if(transporter_info.guid && m_CurrentTransporter)
  3617.     {
  3618.         SetPosition(m_CurrentTransporter->GetPositionX() + transporter_info.x,
  3619.                     m_CurrentTransporter->GetPositionY() + transporter_info.y,
  3620.                     m_CurrentTransporter->GetPositionZ() + transporter_info.z,
  3621.                     GetOrientation(), false);
  3622.     }
  3623.  
  3624.     // If we join an invalid instance and get booted out, this will prevent our stats from doubling :P
  3625.     if(IsInWorld())
  3626.         return;
  3627.  
  3628.     m_beingPushed = true;
  3629.     Object::AddToWorld(pMapMgr);
  3630.  
  3631.     // Add failed.
  3632.     if(m_mapMgr == NULL)
  3633.     {
  3634.         // eject from instance
  3635.         m_beingPushed = false;
  3636.         EjectFromInstance();
  3637.         return;
  3638.     }
  3639.  
  3640.     if(m_session)
  3641.         m_session->SetInstance(m_mapMgr->GetInstanceID());
  3642.  
  3643.     SendInstanceDifficulty(m_mapMgr->iInstanceMode);
  3644. }
  3645.  
  3646. void Player::OnPrePushToWorld()
  3647. {
  3648.     SendInitialLogonPackets();
  3649. #ifdef ENABLE_ACHIEVEMENTS
  3650.     m_achievementMgr.SendAllAchievementData(this);
  3651. #endif
  3652. }
  3653.  
  3654. void Player::OnPushToWorld()
  3655. {
  3656.     uint8 class_ = getClass();
  3657.     uint8 startlevel = 1;
  3658.  
  3659.     // Process create packet
  3660.     ProcessPendingUpdates();
  3661.  
  3662.     if(m_TeleportState == 2)   // Worldport Ack
  3663.         OnWorldPortAck();
  3664.  
  3665.     SpeedCheatReset();
  3666.     m_beingPushed = false;
  3667.     AddItemsToWorld();
  3668.  
  3669.     // delay the unlock movement packet
  3670.     WorldPacket* data = new WorldPacket(SMSG_TIME_SYNC_REQ, 4);
  3671.     *data << uint32(0);
  3672.     delayedPackets.add(data);
  3673.  
  3674.     // Update PVP Situation
  3675.     LoginPvPSetup();
  3676.     RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, 0x28);
  3677.  
  3678.     if(m_playerInfo->lastOnline + 900 < UNIXTIME)    // did we logged out for more than 15 minutes?
  3679.         m_ItemInterface->RemoveAllConjured();
  3680.  
  3681.     Unit::OnPushToWorld();
  3682.  
  3683.     if(m_FirstLogin)
  3684.     {
  3685.         if(class_ == DEATHKNIGHT)
  3686.             startlevel = static_cast<uint8>(max(55, sWorld.StartingLevel));
  3687.         else startlevel = static_cast<uint8>(sWorld.StartingLevel);
  3688.  
  3689.         sHookInterface.OnFirstEnterWorld(this);
  3690.         LevelInfo* Info = objmgr.GetLevelInfo(getRace(), getClass(), startlevel);
  3691.         ApplyLevelInfo(Info, startlevel);
  3692.         m_FirstLogin = false;
  3693.     }
  3694.  
  3695.     sHookInterface.OnEnterWorld(this);
  3696.     CALL_INSTANCE_SCRIPT_EVENT(m_mapMgr, OnZoneChange)(this, m_zoneId, 0);
  3697.     CALL_INSTANCE_SCRIPT_EVENT(m_mapMgr, OnPlayerEnter)(this);
  3698.  
  3699.     if(m_TeleportState == 1)        // First world enter
  3700.         CompleteLoading();
  3701.  
  3702.     m_TeleportState = 0;
  3703.  
  3704.     if(GetTaxiState())
  3705.     {
  3706.         if(m_taxiMapChangeNode != 0)
  3707.         {
  3708.             lastNode = m_taxiMapChangeNode;
  3709.         }
  3710.  
  3711.         TaxiStart(GetTaxiPath(),
  3712.                   GetMount(),
  3713.                   lastNode);
  3714.  
  3715.         m_taxiMapChangeNode = 0;
  3716.     }
  3717.  
  3718.     if(flying_aura && ((m_mapId != 530) && (m_mapId != 571 || !HasSpellwithNameHash(SPELL_HASH_COLD_WEATHER_FLYING))))
  3719.         // can only fly in outlands or northrend (northrend requires cold weather flying)
  3720.     {
  3721.         RemoveAura(flying_aura);
  3722.         flying_aura = 0;
  3723.     }
  3724.  
  3725.     /* send weather */
  3726.     sWeatherMgr.SendWeather(this);
  3727.  
  3728.     SetHealth((load_health > m_uint32Values[UNIT_FIELD_MAXHEALTH] ? m_uint32Values[UNIT_FIELD_MAXHEALTH] : load_health));
  3729.     SetPower(POWER_TYPE_MANA, (load_mana > GetMaxPower(POWER_TYPE_MANA) ? GetMaxPower(POWER_TYPE_MANA) : load_mana));
  3730.  
  3731.     if(!GetSession()->HasGMPermissions())
  3732.         GetItemInterface()->CheckAreaItems();
  3733.  
  3734. #ifdef ENABLE_COMPRESSED_MOVEMENT
  3735.     //sEventMgr.AddEvent(this, &Player::EventDumpCompressedMovement, EVENT_PLAYER_FLUSH_MOVEMENT, World::m_movementCompressInterval, 0, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
  3736.     MovementCompressor->AddPlayer(this);
  3737. #endif
  3738.  
  3739.     if(m_mapMgr && m_mapMgr->m_battleground != NULL && m_bg != m_mapMgr->m_battleground)
  3740.     {
  3741.         m_mapMgr->m_battleground->PortPlayer(this, true);
  3742.     }
  3743.  
  3744.     if(m_bg != NULL)
  3745.     {
  3746.         m_bg->OnAddPlayer(this);   // add buffs and so, must be after zone update and related aura removal
  3747.         m_bg->OnPlayerPushed(this);
  3748.     }
  3749.  
  3750.     m_changingMaps = false;
  3751.     SendFullAuraUpdate();
  3752.  
  3753.     m_ItemInterface->HandleItemDurations();
  3754.  
  3755.     SendInitialWorldstates();
  3756.  
  3757.     if( resettalents ){
  3758.         Reset_AllTalents();
  3759.         resettalents = false;
  3760.     }
  3761. }
  3762.  
  3763. void Player::RemoveFromWorld()
  3764. {
  3765.     if(raidgrouponlysent)
  3766.         event_RemoveEvents(EVENT_PLAYER_EJECT_FROM_INSTANCE);
  3767.  
  3768.     load_health = GetHealth();
  3769.     load_mana = GetPower(POWER_TYPE_MANA);
  3770.  
  3771.     if(m_bg)
  3772.     {
  3773.         m_bg->RemovePlayer(this, true);
  3774.     }
  3775.  
  3776.     // Cancel trade if it's active.
  3777.     Player* pTarget;
  3778.     if(mTradeTarget != 0)
  3779.     {
  3780.         pTarget = GetTradeTarget();
  3781.         if(pTarget)
  3782.             pTarget->ResetTradeVariables();
  3783.  
  3784.         ResetTradeVariables();
  3785.     }
  3786.  
  3787.     //stop dueling
  3788.     if(DuelingWith != NULL)
  3789.         DuelingWith->EndDuel(DUEL_WINNER_RETREAT);
  3790.  
  3791.     //clear buyback
  3792.     GetItemInterface()->EmptyBuyBack();
  3793.  
  3794.     ClearSplinePackets();
  3795.  
  3796.  
  3797.     summonhandler.RemoveAllSummons();
  3798.     DismissActivePets();
  3799.     RemoveFieldSummon();
  3800.  
  3801.  
  3802.  
  3803.     if(m_SummonedObject)
  3804.     {
  3805.         if(m_SummonedObject->GetInstanceID() != GetInstanceID())
  3806.         {
  3807.             sEventMgr.AddEvent(m_SummonedObject, &Object::Delete, EVENT_GAMEOBJECT_EXPIRE, 100, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT | EVENT_FLAG_DELETES_OBJECT);
  3808.         }
  3809.         else
  3810.         {
  3811.             if(m_SummonedObject->IsInWorld())
  3812.             {
  3813.                 m_SummonedObject->RemoveFromWorld(true);
  3814.             }
  3815.             ARCEMU_ASSERT(m_SummonedObject->IsGameObject());
  3816.             delete m_SummonedObject;
  3817.         }
  3818.         m_SummonedObject = NULL;
  3819.     }
  3820.  
  3821.     if(IsInWorld())
  3822.     {
  3823.         RemoveItemsFromWorld();
  3824.         Unit::RemoveFromWorld(false);
  3825.     }
  3826.  
  3827.  
  3828. #ifdef ENABLE_COMPRESSED_MOVEMENT
  3829.     MovementCompressor->RemovePlayer(this);
  3830.     m_movementBufferLock.Acquire();
  3831.     m_movementBuffer.clear();
  3832.     m_movementBufferLock.Release();
  3833.     //sEventMgr.RemoveEvents(this, EVENT_PLAYER_FLUSH_MOVEMENT);
  3834.  
  3835. #endif
  3836.  
  3837.     if(GetTaxiState())
  3838.         event_RemoveEvents(EVENT_PLAYER_TAXI_INTERPOLATE);
  3839.  
  3840.     m_changingMaps = true;
  3841.     m_playerInfo->lastOnline = UNIXTIME; // don't destroy conjured items yet
  3842. }
  3843.  
  3844. // TODO: perhaps item should just have a list of mods, that will simplify code
  3845. void Player::_ApplyItemMods(Item* item, int16 slot, bool apply, bool justdrokedown /* = false */, bool skip_stat_apply /* = false  */)
  3846. {
  3847.     if(slot >= INVENTORY_SLOT_BAG_END)
  3848.         return;
  3849.  
  3850.     ARCEMU_ASSERT(item != NULL);
  3851.     ItemPrototype* proto = item->GetProto();
  3852.  
  3853.     //fast check to skip mod applying if the item doesnt meat the requirements.
  3854.     if(!item->IsContainer() && item->GetDurability() == 0 && item->GetDurabilityMax() && justdrokedown == false)
  3855.     {
  3856.         return;
  3857.     }
  3858.  
  3859.     //check for rnd prop
  3860.     item->ApplyRandomProperties(true);
  3861.  
  3862.     //Items Set check
  3863.     uint32 setid = proto->ItemSet;
  3864.  
  3865.     // These season pvp itemsets are interchangeable and each set group has the same
  3866.     // bonuses if you have a full set made up of parts from any of the 3 similar sets
  3867.     // you will get the highest sets bonus
  3868.  
  3869.     // TODO: make a config for server so they can configure which season is active season
  3870.  
  3871.     // * Gladiator's Battlegear
  3872.     if(setid == 701 || setid == 736 || setid == 567)
  3873.         setid = 736;
  3874.  
  3875.     // * Gladiator's Dreadgear
  3876.     if(setid == 702 || setid == 734 || setid == 568)
  3877.         setid = 734;
  3878.  
  3879.     // * Gladiator's Earthshaker
  3880.     if(setid == 703 || setid == 732 || setid == 578)
  3881.         setid = 732;
  3882.  
  3883.     // * Gladiator's Felshroud
  3884.     if(setid == 704 || setid == 735 || setid == 615)
  3885.         setid = 735;
  3886.  
  3887.     // * Gladiator's Investiture
  3888.     if(setid == 705 || setid == 728 || setid == 687)
  3889.         setid = 728;
  3890.  
  3891.     // * Gladiator's Pursuit
  3892.     if(setid == 706 || setid == 723 || setid == 586)
  3893.         setid = 723;
  3894.  
  3895.     // * Gladiator's Raiment
  3896.     if(setid == 707 || setid == 729 || setid == 581)
  3897.         setid = 729;
  3898.  
  3899.     // * Gladiator's Redemption
  3900.     if(setid == 708 || setid == 725 || setid == 690)
  3901.         setid = 725;
  3902.  
  3903.     // * Gladiator's Refuge
  3904.     if(setid == 709 || setid == 720 || setid == 685)
  3905.         setid = 720;
  3906.  
  3907.     // * Gladiator's Regalia
  3908.     if(setid == 710 || setid == 724 || setid == 579)
  3909.         setid = 724;
  3910.  
  3911.     // * Gladiator's Sanctuary
  3912.     if(setid == 711 || setid == 721 || setid == 584)
  3913.         setid = 721;
  3914.  
  3915.     // * Gladiator's Thunderfist
  3916.     if(setid == 712 || setid == 733 || setid == 580)
  3917.         setid = 733;
  3918.  
  3919.     // * Gladiator's Vestments
  3920.     if(setid == 713 || setid == 730 || setid == 577)
  3921.         setid = 730;
  3922.  
  3923.     // * Gladiator's Vindication
  3924.     if(setid == 714 || setid == 726 || setid == 583)
  3925.         setid = 726;
  3926.  
  3927.     // * Gladiator's Wartide
  3928.     if(setid == 715 || setid == 731 || setid == 686)
  3929.         setid = 731;
  3930.  
  3931.     // * Gladiator's Wildhide
  3932.     if(setid == 716 || setid == 722 || setid == 585)
  3933.         setid = 722;
  3934.  
  3935.     // Set
  3936.     if(setid != 0)
  3937.     {
  3938.         ItemSetEntry* set = dbcItemSet.LookupEntryForced(setid);
  3939.         if(set == NULL)
  3940.         {
  3941.             LOG_ERROR("Item %u has wrong ItemSet %u", proto->ItemId, setid);
  3942.         }
  3943.         else
  3944.         {
  3945.             ItemSet* Set = NULL;
  3946.             std::list<ItemSet>::iterator i;
  3947.             for(i = m_itemsets.begin(); i != m_itemsets.end(); ++i)
  3948.             {
  3949.                 if(i->setid == setid)
  3950.                 {
  3951.                     Set = &(*i);
  3952.                     break;
  3953.                 }
  3954.             }
  3955.  
  3956.             if(apply)
  3957.             {
  3958.                 if(Set == NULL)
  3959.                 {
  3960.                     Set = new ItemSet;
  3961.                     memset(Set, 0, sizeof(ItemSet));
  3962.                     Set->itemscount = 1;
  3963.                     Set->setid = setid;
  3964.                 }
  3965.                 else
  3966.                     Set->itemscount++;
  3967.  
  3968.                 if(!set->RequiredSkillID || (_GetSkillLineCurrent(set->RequiredSkillID, true) >= set->RequiredSkillAmt))
  3969.                 {
  3970.                     for(uint32 x = 0; x < 8; x++)
  3971.                     {
  3972.                         if(Set->itemscount == set->itemscount[x])
  3973.                         {
  3974.                             //cast new spell
  3975.                             SpellEntry* info = dbcSpell.LookupEntry(set->SpellID[x]);
  3976.                             Spell* spell = sSpellFactoryMgr.NewSpell(this, info, true, NULL);
  3977.                             SpellCastTargets targets;
  3978.                             targets.m_unitTarget = this->GetGUID();
  3979.                             spell->prepare(&targets);
  3980.                         }
  3981.                     }
  3982.                 }
  3983.                 if(i == m_itemsets.end())
  3984.                 {
  3985.                     m_itemsets.push_back(*Set);
  3986.                     delete Set;
  3987.                 }
  3988.             }
  3989.             else
  3990.             {
  3991.                 if(Set)
  3992.                 {
  3993.                     for(uint32 x = 0; x < 8; x++)
  3994.                         if(Set->itemscount == set->itemscount[x])
  3995.                         {
  3996.                             this->RemoveAura(set->SpellID[x], GetGUID());
  3997.                         }
  3998.  
  3999.                     if(!(--Set->itemscount))
  4000.                         m_itemsets.erase(i);
  4001.                 }
  4002.             }
  4003.         }
  4004.     }
  4005.  
  4006.     // Resistances
  4007.     //TODO: FIX ME: can there be negative resistances from items?
  4008.     if(proto->FireRes)
  4009.     {
  4010.         if(apply)
  4011.             FlatResistanceModifierPos[2] += proto->FireRes;
  4012.         else
  4013.             FlatResistanceModifierPos[2] -= proto->FireRes;
  4014.         CalcResistance(2);
  4015.     }
  4016.  
  4017.     if(proto->NatureRes)
  4018.     {
  4019.         if(apply)
  4020.             FlatResistanceModifierPos[3] += proto->NatureRes;
  4021.         else
  4022.             FlatResistanceModifierPos[3] -= proto->NatureRes;
  4023.         CalcResistance(3);
  4024.     }
  4025.  
  4026.     if(proto->FrostRes)
  4027.     {
  4028.         if(apply)
  4029.             FlatResistanceModifierPos[4] += proto->FrostRes;
  4030.         else
  4031.             FlatResistanceModifierPos[4] -= proto->FrostRes;
  4032.         CalcResistance(4);
  4033.     }
  4034.  
  4035.     if(proto->ShadowRes)
  4036.     {
  4037.         if(apply)
  4038.             FlatResistanceModifierPos[5] += proto->ShadowRes;
  4039.         else
  4040.             FlatResistanceModifierPos[5] -= proto->ShadowRes;
  4041.         CalcResistance(5);
  4042.     }
  4043.  
  4044.     if(proto->ArcaneRes)
  4045.     {
  4046.         if(apply)
  4047.             FlatResistanceModifierPos[6] += proto->ArcaneRes;
  4048.         else
  4049.             FlatResistanceModifierPos[6] -= proto->ArcaneRes;
  4050.         CalcResistance(6);
  4051.     }
  4052.     /* Heirloom scaling items */
  4053.     if(proto->ScalingStatsEntry != 0)
  4054.     {
  4055.         int i = 0;
  4056.         ScalingStatDistributionEntry* ssdrow = dbcScalingStatDistribution.LookupEntry(proto->ScalingStatsEntry);
  4057.         ScalingStatValuesEntry* ssvrow = NULL;
  4058.         uint32 StatType;
  4059.         uint32 StatMod;
  4060.         uint32 plrLevel = getLevel();
  4061.         int32 StatMultiplier;
  4062.         int32 StatValue;
  4063.         int32 col = 0;
  4064.  
  4065.         // this is needed because the heirloom items don't scale over lvl80
  4066.         if(plrLevel > 80)
  4067.             plrLevel = 80;
  4068.  
  4069.  
  4070.         DBCStorage<ScalingStatValuesEntry>::iterator itr;
  4071.  
  4072.         for(itr = dbcScalingStatValues.begin(); itr != dbcScalingStatValues.end(); ++itr)
  4073.             if((*itr)->level == plrLevel)
  4074.             {
  4075.                 ssvrow = *itr;
  4076.                 break;
  4077.             }
  4078.  
  4079.         /* Not going to put a check here since unless you put a random id/flag in the tables these should never return NULL */
  4080.  
  4081.         /* Calculating the stats correct for our level and applying them */
  4082.         for(i = 0; ssdrow->stat[i] != -1; i++)
  4083.         {
  4084.             StatType = ssdrow->stat[i];
  4085.             StatMod  = ssdrow->statmodifier[i];
  4086.             col = GetStatScalingStatValueColumn(proto, SCALINGSTATSTAT);
  4087.             if(col == -1)
  4088.                 continue;
  4089.             StatMultiplier = ssvrow->multiplier[col];
  4090.             StatValue = StatMod * StatMultiplier / 10000;
  4091.             ModifyBonuses(StatType, StatValue, apply);
  4092.         }
  4093.  
  4094.         if((proto->ScalingStatsFlag & 32768) && i < 10)
  4095.         {
  4096.             StatType = ssdrow->stat[i];
  4097.             StatMod  = ssdrow->statmodifier[i];
  4098.             col = GetStatScalingStatValueColumn(proto, SCALINGSTATSPELLPOWER);
  4099.             if(col != -1)
  4100.             {
  4101.                 StatMultiplier = ssvrow->multiplier[col];
  4102.                 StatValue = StatMod * StatMultiplier / 10000;
  4103.                 ModifyBonuses(45, StatValue, apply);
  4104.             }
  4105.         }
  4106.  
  4107.         /* Calculating the Armor correct for our level and applying it */
  4108.         col = GetStatScalingStatValueColumn(proto, SCALINGSTATARMOR);
  4109.         if(col != -1)
  4110.         {
  4111.             uint32 scaledarmorval = ssvrow->multiplier[ col ];
  4112.             if(apply)BaseResistance[0 ] += scaledarmorval;
  4113.             else  BaseResistance[0] -= scaledarmorval;
  4114.             CalcResistance(0);
  4115.         }
  4116.  
  4117.         /* Calculating the damages correct for our level and applying it */
  4118.         col = GetStatScalingStatValueColumn(proto, SCALINGSTATDAMAGE);
  4119.         if(col != -1)
  4120.         {
  4121.             uint32 scaleddps = ssvrow->multiplier [ col ];
  4122.             float dpsmod = 1.0;
  4123.  
  4124.             if(proto->ScalingStatsFlag & 0x1400)
  4125.                 dpsmod = 0.2f;
  4126.             else dpsmod = 0.3f;
  4127.  
  4128.             float scaledmindmg = (scaleddps - (scaleddps * dpsmod)) * (proto->Delay / 1000);
  4129.             float scaledmaxdmg = (scaleddps * (dpsmod + 1.0f)) * (proto->Delay / 1000);
  4130.  
  4131.             if(proto->InventoryType == INVTYPE_RANGED || proto->InventoryType == INVTYPE_RANGEDRIGHT || proto->InventoryType == INVTYPE_THROWN)
  4132.             {
  4133.                 BaseRangedDamage[0] += apply ? scaledmindmg : -scaledmindmg;
  4134.                 BaseRangedDamage[1] += apply ? scaledmaxdmg : -scaledmaxdmg;
  4135.             }
  4136.             else
  4137.             {
  4138.                 if(slot == EQUIPMENT_SLOT_OFFHAND)
  4139.                 {
  4140.                     BaseOffhandDamage[0] = apply ? scaledmindmg : 0;
  4141.                     BaseOffhandDamage[1] = apply ? scaledmaxdmg : 0;
  4142.                 }
  4143.                 else
  4144.                 {
  4145.                     BaseDamage[0] = apply ? scaledmindmg : 0;
  4146.                     BaseDamage[1] = apply ? scaledmaxdmg : 0;
  4147.                 }
  4148.             }
  4149.         }
  4150.  
  4151.         /* Normal items */
  4152.     }
  4153.     else
  4154.     {
  4155.         // Stats
  4156.         for(uint32 i = 0; i < proto->itemstatscount; i++)
  4157.         {
  4158.             int32 val = proto->Stats[i].Value;
  4159.             /*
  4160.             if( val == 0 )
  4161.                 continue;
  4162.             */
  4163.             ModifyBonuses(proto->Stats[i].Type, val, apply);
  4164.         }
  4165.  
  4166.         // Armor
  4167.         if(proto->Armor)
  4168.         {
  4169.             if(apply)BaseResistance[0 ] += proto->Armor;
  4170.             else  BaseResistance[0] -= proto->Armor;
  4171.             CalcResistance(0);
  4172.         }
  4173.  
  4174.         // Damage
  4175.         if(proto->Damage[0].Min)
  4176.         {
  4177.             if(proto->InventoryType == INVTYPE_RANGED || proto->InventoryType == INVTYPE_RANGEDRIGHT || proto->InventoryType == INVTYPE_THROWN)
  4178.             {
  4179.                 BaseRangedDamage[0] += apply ? proto->Damage[0].Min : -proto->Damage[0].Min;
  4180.                 BaseRangedDamage[1] += apply ? proto->Damage[0].Max : -proto->Damage[0].Max;
  4181.             }
  4182.             else
  4183.             {
  4184.                 if(slot == EQUIPMENT_SLOT_OFFHAND)
  4185.                 {
  4186.                     BaseOffhandDamage[0] = apply ? proto->Damage[0].Min : 0;
  4187.                     BaseOffhandDamage[1] = apply ? proto->Damage[0].Max : 0;
  4188.                 }
  4189.                 else
  4190.                 {
  4191.                     BaseDamage[0] = apply ? proto->Damage[0].Min : 0;
  4192.                     BaseDamage[1] = apply ? proto->Damage[0].Max : 0;
  4193.                 }
  4194.             }
  4195.         }
  4196.     } // end of the scalingstats else branch
  4197.  
  4198.     if(this->getClass() == DRUID && slot == EQUIPMENT_SLOT_MAINHAND)
  4199.     {
  4200.         uint8 ss = GetShapeShift();
  4201.         if(ss == FORM_MOONKIN || ss == FORM_CAT || ss == FORM_BEAR || ss == FORM_DIREBEAR)
  4202.             this->ApplyFeralAttackPower(apply, item);
  4203.     }
  4204.  
  4205.     // Misc
  4206.     if(apply)
  4207.     {
  4208.         // Apply all enchantment bonuses
  4209.         item->ApplyEnchantmentBonuses();
  4210.  
  4211.         SpellEntry* spells;
  4212.         for(int k = 0; k < 5; k++)
  4213.         {
  4214.             if(item->GetProto()->Spells[k].Id == 0)
  4215.                 continue;//this isn't needed since the check below handles this case but it's a lot faster performance-wise.
  4216.  
  4217.             spells = dbcSpell.LookupEntryForced(item->GetProto()->Spells[k].Id);
  4218.             if(spells == NULL)
  4219.                 continue;
  4220.  
  4221.             if(item->GetProto()->Spells[k].Trigger == ON_EQUIP)
  4222.             {
  4223.                 if(spells->RequiredShapeShift)
  4224.                 {
  4225.                     AddShapeShiftSpell(spells->Id);
  4226.                     continue;
  4227.                 }
  4228.  
  4229.                 Spell* spell = sSpellFactoryMgr.NewSpell(this, spells , true, NULL);
  4230.                 SpellCastTargets targets;
  4231.                 targets.m_unitTarget = this->GetGUID();
  4232.                 spell->castedItemId = item->GetEntry();
  4233.                 spell->prepare(&targets);
  4234.  
  4235.             }
  4236.             else if(item->GetProto()->Spells[k].Trigger == CHANCE_ON_HIT)
  4237.             {
  4238.                 this->AddProcTriggerSpell(spells, NULL, this->GetGUID(), 5, PROC_ON_MELEE_ATTACK, 0, NULL, NULL);
  4239.             }
  4240.         }
  4241.     }
  4242.     else
  4243.     {
  4244.         // Remove all enchantment bonuses
  4245.         item->RemoveEnchantmentBonuses();
  4246.         for(int k = 0; k < 5; k++)
  4247.         {
  4248.             if(item->GetProto()->Spells[k].Trigger == ON_EQUIP)
  4249.             {
  4250.                 SpellEntry* spells = dbcSpell.LookupEntry(item->GetProto()->Spells[k].Id);
  4251.                 if(spells->RequiredShapeShift)
  4252.                     RemoveShapeShiftSpell(spells->Id);
  4253.                 else
  4254.                     RemoveAura(item->GetProto()->Spells[k].Id);
  4255.             }
  4256.             else if(item->GetProto()->Spells[k].Trigger == CHANCE_ON_HIT)
  4257.             {
  4258.                 this->RemoveProcTriggerSpell(item->GetProto()->Spells[k].Id);
  4259.             }
  4260.         }
  4261.     }
  4262.  
  4263.     if(!apply)   // force remove auras added by using this item
  4264.     {
  4265.         for(uint32 k = MAX_POSITIVE_AURAS_EXTEDED_START; k < MAX_POSITIVE_AURAS_EXTEDED_END; ++k)
  4266.         {
  4267.             Aura* m_aura = this->m_auras[k];
  4268.             if(m_aura != NULL && m_aura->m_castedItemId && m_aura->m_castedItemId == proto->ItemId)
  4269.                 m_aura->Remove();
  4270.         }
  4271.     }
  4272.  
  4273.     if(!skip_stat_apply)
  4274.         UpdateStats();
  4275. }
  4276.  
  4277.  
  4278. void Player::SetMovement(uint8 pType, uint32 flag)
  4279. {
  4280.     WorldPacket data(13);
  4281.  
  4282.     switch(pType)
  4283.     {
  4284.         case MOVE_ROOT:
  4285.             {
  4286.                 data.SetOpcode(SMSG_FORCE_MOVE_ROOT);
  4287.                 data << GetNewGUID();
  4288.                 data << flag;
  4289.                 m_currentMovement = MOVE_ROOT;
  4290.             }
  4291.             break;
  4292.         case MOVE_UNROOT:
  4293.             {
  4294.                 data.SetOpcode(SMSG_FORCE_MOVE_UNROOT);
  4295.                 data << GetNewGUID();
  4296.                 data << flag;
  4297.                 m_currentMovement = MOVE_UNROOT;
  4298.             }
  4299.             break;
  4300.         case MOVE_WATER_WALK:
  4301.             {
  4302.                 m_setwaterwalk = true;
  4303.                 data.SetOpcode(SMSG_MOVE_WATER_WALK);
  4304.                 data << GetNewGUID();
  4305.                 data << flag;
  4306.             }
  4307.             break;
  4308.         case MOVE_LAND_WALK:
  4309.             {
  4310.                 m_setwaterwalk = false;
  4311.                 data.SetOpcode(SMSG_MOVE_LAND_WALK);
  4312.                 data << GetNewGUID();
  4313.                 data << flag;
  4314.             }
  4315.             break;
  4316.         default:
  4317.             break;
  4318.     }
  4319.  
  4320.     if(data.size() > 0)
  4321.         SendMessageToSet(&data, true);
  4322. }
  4323.  
  4324. void Player::SetSpeeds( uint8 type, float speed )
  4325. {
  4326.     WorldPacket data(50);
  4327.  
  4328.     if(type != SWIMBACK)
  4329.     {
  4330.         data << GetNewGUID();
  4331.         data << m_speedChangeCounter++;
  4332.         if(type == RUN)
  4333.             data << uint8(1);
  4334.  
  4335.         data << float( speed );
  4336.     }
  4337.     else
  4338.     {
  4339.         data << GetNewGUID();
  4340.         data << uint32(0);
  4341.         data << uint8(0);
  4342.         data << uint32(getMSTime());
  4343.         data << GetPosition();
  4344.         data << float( m_position.o );
  4345.         data << uint32(0);
  4346.         data << float( speed );
  4347.     }
  4348.  
  4349.     switch(type)
  4350.     {
  4351.         case WALK:{
  4352.             data.SetOpcode( SMSG_FORCE_WALK_SPEED_CHANGE );
  4353.             m_walkSpeed = speed;
  4354.  
  4355.             break; }
  4356.  
  4357.         case RUN:
  4358.             {
  4359.                 if(speed == m_lastRunSpeed)
  4360.                     return;
  4361.  
  4362.                 data.SetOpcode(SMSG_FORCE_RUN_SPEED_CHANGE);
  4363.                 m_runSpeed = speed;
  4364.                 m_lastRunSpeed = speed;
  4365.             }
  4366.             break;
  4367.         case RUNBACK:
  4368.             {
  4369.                 if(speed == m_lastRunBackSpeed)
  4370.                     return;
  4371.  
  4372.                 data.SetOpcode(SMSG_FORCE_RUN_BACK_SPEED_CHANGE);
  4373.                 m_backWalkSpeed = speed;
  4374.                 m_lastRunBackSpeed = speed;
  4375.             }
  4376.             break;
  4377.         case SWIM:
  4378.             {
  4379.                 if(speed == m_lastSwimSpeed)
  4380.                     return;
  4381.  
  4382.                 data.SetOpcode(SMSG_FORCE_SWIM_SPEED_CHANGE);
  4383.                 m_swimSpeed = speed;
  4384.                 m_lastSwimSpeed = speed;
  4385.             }
  4386.             break;
  4387.         case SWIMBACK:
  4388.             {
  4389.                 if(speed == m_lastBackSwimSpeed)
  4390.                     break;
  4391.  
  4392.                 data.SetOpcode(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE);
  4393.                 m_backSwimSpeed = speed;
  4394.                 m_lastBackSwimSpeed = speed;
  4395.             }
  4396.             break;
  4397.         case FLY:
  4398.             {
  4399.                 if(speed == m_lastFlySpeed)
  4400.                     return;
  4401.  
  4402.                 data.SetOpcode(SMSG_FORCE_FLIGHT_SPEED_CHANGE);
  4403.                 m_flySpeed = speed;
  4404.                 m_lastFlySpeed = speed;
  4405.             }
  4406.             break;
  4407.         default:
  4408.             return;
  4409.     }
  4410.  
  4411.     SendMessageToSet(&data , true);
  4412. }
  4413.  
  4414. void Player::BuildPlayerRepop()
  4415. {
  4416.     WorldPacket data(SMSG_PRE_RESURRECT, 8);
  4417.     FastGUIDPack(data, GetGUID());       // caster guid
  4418.     GetSession()->SendPacket(&data);
  4419.  
  4420.     // Cleanup first
  4421.     uint32 AuraIds[] = {20584, 9036, 8326, 0};
  4422.     RemoveAuras(AuraIds); // Cebernic: Removeaura just remove once(bug?).
  4423.  
  4424.     SetHealth(1);
  4425.  
  4426.     SpellCastTargets tgt;
  4427.     tgt.m_unitTarget = this->GetGUID();
  4428.  
  4429.     if(getRace() == RACE_NIGHTELF)
  4430.     {
  4431.         SpellEntry* inf = dbcSpell.LookupEntry(9036);
  4432.         Spell* sp = sSpellFactoryMgr.NewSpell(this, inf, true, NULL);
  4433.         sp->prepare(&tgt);
  4434.     }
  4435.     else
  4436.     {
  4437.         SpellEntry* inf = dbcSpell.LookupEntry(8326);
  4438.         Spell* sp = sSpellFactoryMgr.NewSpell(this, inf, true, NULL);
  4439.         sp->prepare(&tgt);
  4440.     }
  4441.  
  4442.     StopMirrorTimer(0);
  4443.     StopMirrorTimer(1);
  4444.     StopMirrorTimer(2);
  4445.  
  4446.     SetFlag(PLAYER_FLAGS, PLAYER_FLAG_DEATH_WORLD_ENABLE);
  4447.  
  4448.     SetMovement(MOVE_UNROOT, 1);
  4449.     SetMovement(MOVE_WATER_WALK, 1);
  4450. }
  4451.  
  4452. void Player::RepopRequestedPlayer()
  4453. {
  4454.     sEventMgr.RemoveEvents(this, EVENT_PLAYER_CHECKFORCHEATS); // cebernic:-> Remove this first
  4455.     sEventMgr.RemoveEvents(this, EVENT_PLAYER_FORCED_RESURRECT);   //in case somebody resurrected us before this event happened
  4456.  
  4457.     if(myCorpseInstanceId != 0)
  4458.     {
  4459.         // Cebernic: wOOo dead+dead = undead ? :D just resurrect player
  4460.         Corpse* myCorpse = objmgr.GetCorpseByOwner(GetLowGUID());
  4461.         if(myCorpse != NULL)
  4462.             myCorpse->ResetDeathClock();
  4463.         ResurrectPlayer();
  4464.         RepopAtGraveyard(GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId());
  4465.         return;
  4466.     }
  4467.  
  4468.  
  4469.     if(m_CurrentTransporter != NULL)
  4470.     {
  4471.         m_CurrentTransporter->RemovePlayer(this);
  4472.         m_CurrentTransporter = NULL;
  4473.         transporter_info.guid = 0;
  4474.  
  4475.         //ResurrectPlayer();
  4476.         RepopAtGraveyard(GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId());
  4477.         return;
  4478.     }
  4479.  
  4480.     MapInfo* pMapinfo = NULL;
  4481.  
  4482.     // Set death state to corpse, that way players will lose visibility
  4483.     setDeathState(CORPSE);
  4484.  
  4485.     // Update visibility, that way people wont see running corpses :P
  4486.     UpdateVisibility();
  4487.  
  4488.     // If we're in battleground, remove the skinnable flag.. has bad effects heheh
  4489.     RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
  4490.  
  4491.     bool corpse = (m_bg != NULL) ? m_bg->CreateCorpse(this) : true;
  4492.  
  4493.     if(corpse)
  4494.         CreateCorpse();
  4495.  
  4496.  
  4497.     BuildPlayerRepop();
  4498.  
  4499.  
  4500.     // Cebernic: don't do this.
  4501.     if(!m_bg || (m_bg && m_bg->HasStarted()))
  4502.     {
  4503.         pMapinfo = WorldMapInfoStorage.LookupEntry(GetMapId());
  4504.         if(pMapinfo != NULL)
  4505.         {
  4506.             if(pMapinfo->type == INSTANCE_NULL || pMapinfo->type == INSTANCE_BATTLEGROUND)
  4507.             {
  4508.                 RepopAtGraveyard(GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId());
  4509.             }
  4510.             else
  4511.             {
  4512.                 RepopAtGraveyard(pMapinfo->repopx, pMapinfo->repopy, pMapinfo->repopz, pMapinfo->repopmapid);
  4513.             }
  4514.             switch(pMapinfo->mapid)
  4515.             {
  4516.                 case 533: // Naxx
  4517.                 case 550: // The Eye
  4518.                 case 552: // The Arcatraz
  4519.                 case 553: // The Botanica
  4520.                 case 554: // The Mechanar
  4521.                     ResurrectPlayer();
  4522.                     return;
  4523.             }
  4524.  
  4525.         }
  4526.         else
  4527.         {
  4528.             // RepopAtGraveyard( GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId() );
  4529.             // Cebernic: Mapinfo NULL? let's search from bindposition.
  4530.             RepopAtGraveyard(GetBindPositionX(), GetBindPositionY(), GetBindPositionZ(), GetBindMapId());
  4531.         }
  4532.     }
  4533.  
  4534.     if(corpse)
  4535.     {
  4536.         SpawnCorpseBody();
  4537.  
  4538.         if(myCorpseInstanceId != 0)
  4539.         {
  4540.             Corpse* myCorpse = objmgr.GetCorpseByOwner(GetLowGUID());
  4541.             if(myCorpse != NULL)
  4542.                 myCorpse->ResetDeathClock();
  4543.         }
  4544.  
  4545.         /* Send Spirit Healer Location */
  4546.         WorldPacket data(SMSG_DEATH_RELEASE_LOC, 16);
  4547.  
  4548.         data << m_mapId;
  4549.         data << m_position;
  4550.  
  4551.         m_session->SendPacket(&data);
  4552.  
  4553.         /* Corpse reclaim delay */
  4554.         WorldPacket data2(SMSG_CORPSE_RECLAIM_DELAY, 4);
  4555.         data2 << uint32(CORPSE_RECLAIM_TIME_MS);
  4556.         m_session->SendPacket(&data2);
  4557.     }
  4558.  
  4559. }
  4560.  
  4561. void Player::ResurrectPlayer()
  4562. {
  4563.     if(!sHookInterface.OnResurrect(this))
  4564.         return;
  4565.  
  4566.     sEventMgr.RemoveEvents(this, EVENT_PLAYER_FORCED_RESURRECT); // In case somebody resurrected us before this event happened
  4567.     if(m_resurrectHealth)
  4568.         SetHealth((uint32)min(m_resurrectHealth, m_uint32Values[UNIT_FIELD_MAXHEALTH]));
  4569.     if(m_resurrectMana)
  4570.         SetPower(POWER_TYPE_MANA, m_resurrectMana);
  4571.  
  4572.     m_resurrectHealth = m_resurrectMana = 0;
  4573.  
  4574.     SpawnCorpseBones();
  4575.  
  4576.     RemoveNegativeAuras();
  4577.     uint32 AuraIds[] = {20584, 9036, 8326, 0};
  4578.     RemoveAuras(AuraIds); // Cebernic: removeaura just remove once(bug?).
  4579.  
  4580.     RemoveFlag(PLAYER_FLAGS, PLAYER_FLAG_DEATH_WORLD_ENABLE);
  4581.     setDeathState(ALIVE);
  4582.     UpdateVisibility();
  4583.     if(m_resurrecter && IsInWorld()
  4584.             // Don't pull players inside instances with this trick. Also fixes the part where you were able to double item bonuses
  4585.             && m_resurrectInstanceID == static_cast<uint32>(GetInstanceID()))
  4586.     {
  4587.         SafeTeleport(m_resurrectMapId, m_resurrectInstanceID, m_resurrectPosition);
  4588.     }
  4589.     m_resurrecter = 0;
  4590.     SetMovement(MOVE_LAND_WALK, 1);
  4591.  
  4592.     // reinit
  4593.     m_lastRunSpeed = 0;
  4594.     m_lastRunBackSpeed = 0;
  4595.     m_lastSwimSpeed = 0;
  4596.     m_lastBackSwimSpeed = 0;
  4597.     m_lastFlySpeed = 0;
  4598.  
  4599.     // Zack : shit on grill. So auras should be removed on player death instead of making this :P
  4600.     // We can afford this bullshit atm since auras are lost upon death -> no immunities
  4601.     for(uint32 i = 0; i < 7; i++)
  4602.         SchoolImmunityList[i] = 0;
  4603.  
  4604.     SpawnActivePet();
  4605.  
  4606.     if( m_bg != NULL )
  4607.         m_bg->HookOnPlayerResurrect( this );
  4608. }
  4609.  
  4610. void Player::KillPlayer()
  4611. {
  4612.     if(getDeathState() != ALIVE) //You can't kill what has no life.   - amg south park references ftw :P
  4613.         return;
  4614.     setDeathState(JUST_DIED);
  4615.  
  4616.     // Battleground stuff
  4617.     if(m_bg)
  4618.         m_bg->HookOnPlayerDeath(this);
  4619.  
  4620.     EventDeath();
  4621.  
  4622.     m_session->OutPacket(SMSG_CANCEL_COMBAT);
  4623.     m_session->OutPacket(SMSG_CANCEL_AUTO_REPEAT);
  4624.  
  4625.     SetMovement(MOVE_ROOT, 0);
  4626.     StopMirrorTimer(0);
  4627.     StopMirrorTimer(1);
  4628.     StopMirrorTimer(2);
  4629.  
  4630.     SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); // Player death animation, also can be used with DYNAMIC_FLAGS <- huh???
  4631.     SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0x00);
  4632.  
  4633.     if(getClass() == WARRIOR)   // Rage resets on death
  4634.         SetPower(POWER_TYPE_RAGE, 0);
  4635.     else if(getClass() == DEATHKNIGHT)
  4636.         SetPower(POWER_TYPE_RUNIC_POWER, 0);
  4637.  
  4638.     summonhandler.RemoveAllSummons();
  4639.     DismissActivePets();
  4640.  
  4641.     // Player falls off vehicle on death
  4642.     if( currentvehicle != NULL )
  4643.         currentvehicle->EjectPassenger( this );
  4644.  
  4645.     sHookInterface.OnDeath(this);
  4646.  
  4647. }
  4648.  
  4649. void Player::CreateCorpse()
  4650. {
  4651.     Corpse* pCorpse;
  4652.     uint32 _pb, _pb2, _cfb1, _cfb2;
  4653.  
  4654.     objmgr.DelinkPlayerCorpses(this);
  4655.     if(!bCorpseCreateable)
  4656.     {
  4657.         bCorpseCreateable = true;   // For next time
  4658.         return; // No corpse allowed!
  4659.     }
  4660.  
  4661.     pCorpse = objmgr.CreateCorpse();
  4662.     pCorpse->SetInstanceID(GetInstanceID());
  4663.     pCorpse->Create(this, GetMapId(), GetPositionX(),
  4664.                     GetPositionY(), GetPositionZ(), GetOrientation());
  4665.  
  4666.     _pb = GetUInt32Value(PLAYER_BYTES);
  4667.     _pb2 = GetUInt32Value(PLAYER_BYTES_2);
  4668.  
  4669.     uint8 race     = getRace();
  4670.     uint8 skin     = (uint8)(_pb);
  4671.     uint8 face     = (uint8)(_pb >> 8);
  4672.     uint8 hairstyle  = (uint8)(_pb >> 16);
  4673.     uint8 haircolor  = (uint8)(_pb >> 24);
  4674.     uint8 facialhair = (uint8)(_pb2);
  4675.  
  4676.     _cfb1 = ((0x00) | (race << 8) | (0x00 << 16) | (skin << 24));
  4677.     _cfb2 = ((face) | (hairstyle << 8) | (haircolor << 16) | (facialhair << 24));
  4678.  
  4679.     pCorpse->SetZoneId(GetZoneId());
  4680.     pCorpse->SetUInt32Value(CORPSE_FIELD_BYTES_1, _cfb1);
  4681.     pCorpse->SetUInt32Value(CORPSE_FIELD_BYTES_2, _cfb2);
  4682.     pCorpse->SetUInt32Value(CORPSE_FIELD_FLAGS, 4);
  4683.     pCorpse->SetDisplayId(GetDisplayId());
  4684.  
  4685.     if(m_bg)
  4686.     {
  4687.         // Remove our lootable flags
  4688.         RemoveFlag(UNIT_DYNAMIC_FLAGS, U_DYN_FLAG_LOOTABLE);
  4689.         RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
  4690.  
  4691.         loot.gold = 0;
  4692.  
  4693.         pCorpse->generateLoot();
  4694.         if(bShouldHaveLootableOnCorpse)
  4695.         {
  4696.             pCorpse->SetUInt32Value(CORPSE_FIELD_DYNAMIC_FLAGS, 1); // sets it so you can loot the plyr
  4697.         }
  4698.         else
  4699.         {
  4700.             // Hope this works
  4701.             pCorpse->SetUInt32Value(CORPSE_FIELD_FLAGS, 60);
  4702.         }
  4703.  
  4704.         // Now that our corpse is created, don't do it again
  4705.         bShouldHaveLootableOnCorpse = false;
  4706.     }
  4707.     else
  4708.     {
  4709.         pCorpse->loot.gold = 0;
  4710.     }
  4711.  
  4712.     uint32 iDisplayID = 0;
  4713.     uint16 iIventoryType = 0;
  4714.     uint32 _cfi = 0;
  4715.     Item* pItem;
  4716.     for(int8 i = 0; i < EQUIPMENT_SLOT_END; i++)
  4717.     {
  4718.         if((pItem = GetItemInterface()->GetInventoryItem(i)) != 0)
  4719.         {
  4720.             iDisplayID = pItem->GetProto()->DisplayInfoID;
  4721.             iIventoryType = (uint16)pItem->GetProto()->InventoryType;
  4722.  
  4723.             _cfi = (uint16(iDisplayID)) | (iIventoryType) << 24;
  4724.             pCorpse->SetUInt32Value(CORPSE_FIELD_ITEM + i, _cfi);
  4725.         }
  4726.     }
  4727.     // Save corpse in db for future use
  4728.     pCorpse->SaveToDB();
  4729. }
  4730.  
  4731. void Player::SpawnCorpseBody()
  4732. {
  4733.     Corpse* pCorpse;
  4734.  
  4735.     pCorpse = objmgr.GetCorpseByOwner(this->GetLowGUID());
  4736.     if(pCorpse)
  4737.     {
  4738.         if(!pCorpse->IsInWorld())
  4739.         {
  4740.             if(bShouldHaveLootableOnCorpse && pCorpse->GetUInt32Value(CORPSE_FIELD_DYNAMIC_FLAGS) != 1)
  4741.                 pCorpse->SetUInt32Value(CORPSE_FIELD_DYNAMIC_FLAGS, 1); // sets it so you can loot the plyr
  4742.  
  4743.             if(m_mapMgr == 0)
  4744.                 pCorpse->AddToWorld();
  4745.             else
  4746.                 pCorpse->PushToWorld(m_mapMgr);
  4747.         }
  4748.         myCorpseLocation = pCorpse->GetPosition();
  4749.         myCorpseInstanceId = pCorpse->GetInstanceID();
  4750.     }
  4751.     else
  4752.     {
  4753.         myCorpseLocation.ChangeCoords(0, 0, 0, 0);
  4754.         myCorpseInstanceId = 0;
  4755.     }
  4756. }
  4757.  
  4758. void Player::SpawnCorpseBones()
  4759. {
  4760.     Corpse* pCorpse;
  4761.     pCorpse = objmgr.GetCorpseByOwner(GetLowGUID());
  4762.     myCorpseLocation.ChangeCoords(0, 0, 0, 0);
  4763.     myCorpseInstanceId = 0;
  4764.     if(pCorpse)
  4765.     {
  4766.         if(pCorpse->IsInWorld() && pCorpse->GetCorpseState() == CORPSE_STATE_BODY)
  4767.         {
  4768.             if(pCorpse->GetInstanceID() != GetInstanceID())
  4769.             {
  4770.                 sEventMgr.AddEvent(pCorpse, &Corpse::SpawnBones, EVENT_CORPSE_SPAWN_BONES, 100, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
  4771.             }
  4772.             else
  4773.                 pCorpse->SpawnBones();
  4774.         }
  4775.         else
  4776.         {
  4777.             //Cheater!
  4778.         }
  4779.     }
  4780. }
  4781.  
  4782. void Player::DeathDurabilityLoss(double percent)
  4783. {
  4784.     m_session->OutPacket(SMSG_DURABILITY_DAMAGE_DEATH);
  4785.     uint32 pDurability;
  4786.     uint32 pMaxDurability;
  4787.     int32 pNewDurability;
  4788.     Item* pItem;
  4789.  
  4790.     for(int8 i = 0; i < EQUIPMENT_SLOT_END; i++)
  4791.     {
  4792.         if((pItem = GetItemInterface()->GetInventoryItem(i)) != 0)
  4793.         {
  4794.             pMaxDurability = pItem->GetDurabilityMax();
  4795.             pDurability =  pItem->GetDurability();
  4796.             if(pDurability)
  4797.             {
  4798.                 pNewDurability = (uint32)(pMaxDurability * percent);
  4799.                 pNewDurability = (pDurability - pNewDurability);
  4800.                 if(pNewDurability < 0)
  4801.                     pNewDurability = 0;
  4802.  
  4803.                 if(pNewDurability <= 0)
  4804.                 {
  4805.                     ApplyItemMods(pItem, i, false, true);
  4806.                 }
  4807.  
  4808.                 pItem->SetDurability(static_cast< uint32 >(pNewDurability));
  4809.                 pItem->m_isDirty = true;
  4810.             }
  4811.         }
  4812.     }
  4813. }
  4814.  
  4815. void Player::RepopAtGraveyard(float ox, float oy, float oz, uint32 mapid)
  4816. {
  4817.     bool first = true;
  4818.     // float closestX = 0, closestY = 0, closestZ = 0, closestO = 0;
  4819.     StorageContainerIterator<GraveyardTeleport> * itr;
  4820.  
  4821.     LocationVector src(ox, oy, oz);
  4822.     LocationVector dest;
  4823.     LocationVector temp;
  4824.     float closest_dist = 999999.0f;
  4825.     float dist;
  4826.  
  4827.     if(m_bg && m_bg->HookHandleRepop(this))
  4828.     {
  4829.         return;
  4830.     }
  4831.     else
  4832.     {
  4833.         itr = GraveyardStorage.MakeIterator();
  4834.         GraveyardTeleport* pGrave = NULL;
  4835.         while(!itr->AtEnd())
  4836.         {
  4837.             pGrave = itr->Get();
  4838.             if(pGrave->MapId == mapid && (pGrave->FactionID == GetTeam() || pGrave->FactionID == 3))
  4839.             {
  4840.                 temp.ChangeCoords(pGrave->X, pGrave->Y, pGrave->Z);
  4841.                 dist = src.DistanceSq(temp);
  4842.                 if(first || dist < closest_dist)
  4843.                 {
  4844.                     first = false;
  4845.                     closest_dist = dist;
  4846.                     dest = temp;
  4847.                 }
  4848.             }
  4849.  
  4850.             if(!itr->Inc())
  4851.                 break;
  4852.         }
  4853.         /* Fix on 3/13/2010, defaults to last graveyard, if none fit the criteria.
  4854.         Keeps the player from hanging out to dry.*/
  4855.         if(first && pGrave != NULL)//crappy Databases with no graveyards.
  4856.         {
  4857.             dest.ChangeCoords(pGrave->X, pGrave->Y, pGrave->Z);
  4858.             first = false;
  4859.         }
  4860.  
  4861.         itr->Destruct();
  4862.     }
  4863.  
  4864.     if(sHookInterface.OnRepop(this) && !first)//dest has now always a value != {0,0,0,0}//but there may be DBs with no graveyards
  4865.     {
  4866.         SafeTeleport(mapid, 0, dest);
  4867.     }
  4868.  
  4869.     /* Todo: Generate error message here, compensate for failed teleport. */
  4870.  
  4871. //  //correct method as it works on official server, and does not require any damn sql
  4872. //  //no factions! no zones! no sqls! 1word: blizz-like
  4873. //  float closestX , closestY , closestZ ;
  4874. //  uint32 entries=sWorldSafeLocsStore.GetNumRows();
  4875. //  GraveyardEntry*g;
  4876. //  uint32 mymapid=mapid
  4877. //  float mx=ox,my=oy;
  4878. //  float last_distance=9e10;
  4879. //
  4880. //  for(uint32 x= 0;x<entries;x++)
  4881. //  {
  4882. //      g=sWorldSafeLocsStore.LookupEntry(x);
  4883. //      if(g->mapid!=mymapid)continue;
  4884. //      float distance=(mx-g->x)*(mx-g->x)+(my-g->y)*(my-g->y);
  4885. //      if(distance<last_distance)
  4886. //      {
  4887. //          closestX=g->x;
  4888. //          closestY=g->y;
  4889. //          closestZ=g->z;
  4890. //          last_distance=distance;
  4891. //      }
  4892. //
  4893. //
  4894. //  }
  4895. //  if(last_distance<1e10)
  4896. //#endif
  4897.  
  4898.  
  4899. }
  4900.  
  4901. void Player::JoinedChannel(Channel* c)
  4902. {
  4903.     if(c != NULL)
  4904.         m_channels.insert(c);
  4905. }
  4906.  
  4907. void Player::LeftChannel(Channel* c)
  4908. {
  4909.     if(c != NULL)
  4910.         m_channels.erase(c);
  4911. }
  4912.  
  4913. void Player::CleanupChannels()
  4914. {
  4915.     set<Channel*>::iterator i;
  4916.     Channel* c;
  4917.     for(i = m_channels.begin(); i != m_channels.end();)
  4918.     {
  4919.         c = *i;
  4920.         ++i;
  4921.  
  4922.         c->Part(this);
  4923.     }
  4924. }
  4925.  
  4926. void Player::SendInitialActions()
  4927. {
  4928.     WorldPacket data(SMSG_ACTION_BUTTONS, PLAYER_ACTION_BUTTON_SIZE + 1);
  4929.  
  4930.     data << uint8(0);         // VLack: 3.1, some bool - 0 or 1. seems to work both ways
  4931.  
  4932.     for(uint32 i = 0; i < PLAYER_ACTION_BUTTON_COUNT; ++i)
  4933.     {
  4934.         data << m_specs[m_talentActiveSpec].mActions[i].Action;
  4935.         data << m_specs[m_talentActiveSpec].mActions[i].Type;
  4936.         data << m_specs[m_talentActiveSpec].mActions[i].Misc; //VLack: on 3.1.3, despite the format of CMSG_SET_ACTION_BUTTON, here Type have to be sent before Misc
  4937.     }
  4938.     m_session->SendPacket(&data);
  4939. }
  4940.  
  4941. void Player::setAction(uint8 button, uint16 action, uint8 type, uint8 misc)
  4942. {
  4943.     if(button >= PLAYER_ACTION_BUTTON_COUNT)
  4944.         return;
  4945.  
  4946.     m_specs[m_talentActiveSpec].mActions[button].Action = action;
  4947.     m_specs[m_talentActiveSpec].mActions[button].Type = type;
  4948.     m_specs[m_talentActiveSpec].mActions[button].Misc = misc;
  4949. }
  4950.  
  4951. // Groupcheck
  4952. bool Player::IsGroupMember(Player* plyr)
  4953. {
  4954.     if(m_playerInfo->m_Group != NULL)
  4955.         return m_playerInfo->m_Group->HasMember(plyr->m_playerInfo);
  4956.  
  4957.     return false;
  4958. }
  4959.  
  4960. int32 Player::GetOpenQuestSlot()
  4961. {
  4962.     for(uint32 i = 0; i < 25; ++i)
  4963.         if(m_questlog[i] == NULL)
  4964.             return i;
  4965.  
  4966.     return -1;
  4967. }
  4968.  
  4969. void Player::AddToFinishedQuests(uint32 quest_id)
  4970. {
  4971.     if(m_finishedQuests.find(quest_id) != m_finishedQuests.end())
  4972.         return;
  4973.  
  4974.     m_finishedQuests.insert(quest_id);
  4975. }
  4976.  
  4977. bool Player::HasFinishedQuest(uint32 quest_id)
  4978. {
  4979.     return (m_finishedQuests.find(quest_id) != m_finishedQuests.end());
  4980. }
  4981.  
  4982.  
  4983. bool Player::HasTimedQuest(){
  4984.     for( uint32 i = 0; i < 25; i++ )
  4985.         if( ( m_questlog[ i ] != NULL ) && ( m_questlog[ i ]->GetQuest()->time != 0 ) )
  4986.             return true;
  4987.  
  4988.     return false;
  4989. }
  4990.  
  4991.  
  4992. void Player::ClearQuest(uint32 id)
  4993. {
  4994.     m_finishedQuests.erase(id);
  4995.     m_finishedDailies.erase(id);
  4996. }
  4997.  
  4998.  
  4999. bool Player::GetQuestRewardStatus(uint32 quest_id)
  5000. {
  5001.     return HasFinishedQuest(quest_id);
  5002. }
  5003.  
  5004. // From Mangos Project
  5005. void Player::_LoadTutorials(QueryResult* result)
  5006. {
  5007.     if(result)
  5008.     {
  5009.         Field* fields = result->Fetch();
  5010.         for(int iI = 0; iI < 8; iI++)
  5011.             m_Tutorials[iI] = fields[iI + 1].GetUInt32();
  5012.     }
  5013.     tutorialsDirty = false;
  5014. }
  5015.  
  5016. void Player::_SaveTutorials(QueryBuffer* buf)
  5017. {
  5018.     if(tutorialsDirty)
  5019.     {
  5020.         if(buf == NULL)
  5021.         {
  5022.             CharacterDatabase.Execute("DELETE FROM tutorials WHERE playerid = %u;", GetLowGUID());
  5023.             CharacterDatabase.Execute("INSERT INTO tutorials VALUES('%u','%u','%u','%u','%u','%u','%u','%u','%u');", GetLowGUID(), m_Tutorials[0], m_Tutorials[1], m_Tutorials[2], m_Tutorials[3], m_Tutorials[4], m_Tutorials[5], m_Tutorials[6], m_Tutorials[7]);
  5024.         }
  5025.         else
  5026.         {
  5027.             buf->AddQuery("DELETE FROM tutorials WHERE playerid = %u;", GetLowGUID());
  5028.             buf->AddQuery("INSERT INTO tutorials VALUES('%u','%u','%u','%u','%u','%u','%u','%u','%u');", GetLowGUID(), m_Tutorials[0], m_Tutorials[1], m_Tutorials[2], m_Tutorials[3], m_Tutorials[4], m_Tutorials[5], m_Tutorials[6], m_Tutorials[7]);
  5029.         }
  5030.  
  5031.         tutorialsDirty = false;
  5032.     }
  5033. }
  5034.  
  5035. uint32 Player::GetTutorialInt(uint32 intId)
  5036. {
  5037.     ARCEMU_ASSERT(intId < 8);
  5038.     return m_Tutorials[intId];
  5039. }
  5040.  
  5041. void Player::SetTutorialInt(uint32 intId, uint32 value)
  5042. {
  5043.     if(intId >= 8)
  5044.         return;
  5045.  
  5046.     ARCEMU_ASSERT(intId < 8);
  5047.     m_Tutorials[intId] = value;
  5048.     tutorialsDirty = true;
  5049. }
  5050.  
  5051. float Player::GetDefenseChance(uint32 opLevel)
  5052. {
  5053.     float chance = _GetSkillLineCurrent(SKILL_DEFENSE, true) - (opLevel * 5.0f);
  5054.     chance += CalcRating(PLAYER_RATING_MODIFIER_DEFENCE);
  5055.     chance = floorf(chance) * 0.04f;   // defense skill is treated as an integer on retail
  5056.  
  5057.     return chance;
  5058. }
  5059.  
  5060. #define BASE_BLOCK_CHANCE 5.0f
  5061. #define BASE_PARRY_CHANCE 5.0f
  5062.  
  5063. // Gets dodge chances before defense skill is applied
  5064. float Player::GetDodgeChance()
  5065. {
  5066.     uint32 pClass = (uint32)getClass();
  5067.     float chance = 0.0f;
  5068.     uint32 level = getLevel();
  5069.  
  5070.     if(level > sWorld.m_genLevelCap)
  5071.         level = sWorld.m_genLevelCap;
  5072.  
  5073.     if( level > PLAYER_LEVEL_CAP )
  5074.         level = PLAYER_LEVEL_CAP;
  5075.  
  5076.     // Base dodge + dodge from agility
  5077.    
  5078.     gtFloat *baseCrit = dbcMeleeCritBase.LookupEntry( pClass - 1 );
  5079.     gtFloat *CritPerAgi = dbcMeleeCrit.LookupEntry( level - 1 + ( pClass - 1 ) * 100 );
  5080.     uint32 agi = GetStat( STAT_AGILITY );
  5081.    
  5082.     float tmp = 100.0f * ( baseCrit->val + agi * CritPerAgi->val );
  5083.     tmp *= crit_to_dodge[ pClass ];
  5084.     chance += tmp;
  5085.  
  5086.     // Dodge from dodge rating
  5087.     chance += CalcRating(PLAYER_RATING_MODIFIER_DODGE);
  5088.  
  5089.     // Dodge from spells
  5090.     chance += GetDodgeFromSpell();
  5091.  
  5092.     return max(chance, 0.0f);   // Make sure we don't have a negative chance
  5093. }
  5094.  
  5095. // Gets block chances before defense skill is applied
  5096. // Assumes the caller will check for shields
  5097. float Player::GetBlockChance()
  5098. {
  5099.     float chance;
  5100.  
  5101.     // Base block chance
  5102.     chance = BASE_BLOCK_CHANCE;
  5103.  
  5104.     // Block rating
  5105.     chance += CalcRating(PLAYER_RATING_MODIFIER_BLOCK);
  5106.  
  5107.     // Block chance from spells
  5108.     chance += GetBlockFromSpell();
  5109.  
  5110.     return max(chance, 0.0f);   // Make sure we don't have a negative chance
  5111. }
  5112.  
  5113. // Get parry chances before defense skill is applied
  5114. float Player::GetParryChance()
  5115. {
  5116.     float chance;
  5117.  
  5118.     // Base parry chance
  5119.     chance = BASE_PARRY_CHANCE;
  5120.  
  5121.     // Parry rating
  5122.     chance += CalcRating(PLAYER_RATING_MODIFIER_PARRY);
  5123.  
  5124.     // Parry chance from spells
  5125.     chance += GetParryFromSpell();
  5126.  
  5127.     return max(chance, 0.0f);   // Make sure we don't have a negative chance
  5128. }
  5129.  
  5130. void Player::UpdateChances()
  5131. {
  5132.     uint32 pClass = (uint32)getClass();
  5133.     uint32 pLevel = (getLevel() > PLAYER_LEVEL_CAP) ? PLAYER_LEVEL_CAP : getLevel();
  5134.  
  5135.     float tmp = 0;
  5136.     float defence_contribution = 0;
  5137.  
  5138.     // Avoidance from defense skill
  5139.     defence_contribution = GetDefenseChance(pLevel);
  5140.  
  5141.     // Dodge
  5142.     tmp = GetDodgeChance();
  5143.     tmp += defence_contribution;
  5144.     tmp = min(max(tmp, 0.0f), 95.0f);
  5145.     SetFloatValue(PLAYER_DODGE_PERCENTAGE, tmp);
  5146.  
  5147.     // Block
  5148.     Item* it = this->GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_OFFHAND);
  5149.     if(it != NULL && it->GetProto()->InventoryType == INVTYPE_SHIELD)
  5150.     {
  5151.         tmp = GetBlockChance();
  5152.         tmp += defence_contribution;
  5153.         tmp = min(max(tmp, 0.0f), 95.0f);
  5154.     }
  5155.     else
  5156.         tmp = 0.0f;
  5157.  
  5158.     SetFloatValue(PLAYER_BLOCK_PERCENTAGE, tmp);
  5159.  
  5160.     // Parry (can only parry with something in main hand)
  5161.     it = this->GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_MAINHAND);
  5162.     if(it != NULL)
  5163.     {
  5164.         tmp = GetParryChance();
  5165.         tmp += defence_contribution;
  5166.         tmp = min(max(tmp, 0.0f), 95.0f);
  5167.     }
  5168.     else
  5169.         tmp = 0.0f;
  5170.  
  5171.     SetFloatValue(PLAYER_PARRY_PERCENTAGE, tmp);
  5172.  
  5173.     // Critical
  5174.     gtFloat* baseCrit = dbcMeleeCritBase.LookupEntry(pClass - 1);
  5175.     gtFloat* CritPerAgi = dbcMeleeCrit.LookupEntry(pLevel - 1 + (pClass - 1) * 100);
  5176.  
  5177.     tmp = 100 * (baseCrit->val + GetStat(STAT_AGILITY) * CritPerAgi->val);
  5178.  
  5179.     float melee_bonus = 0;
  5180.     float ranged_bonus = 0;
  5181.  
  5182.     if(tocritchance.size() > 0)    // Crashfix by Cebernic
  5183.     {
  5184.         map< uint32, WeaponModifier >::iterator itr = tocritchance.begin();
  5185.  
  5186.         Item* tItemMelee = GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_MAINHAND);
  5187.         Item* tItemRanged = GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_RANGED);
  5188.  
  5189.         //-1 = any weapon
  5190.  
  5191.         for(; itr != tocritchance.end(); ++itr)
  5192.         {
  5193.             if(itr->second.wclass == (uint32) - 1 || (tItemMelee != NULL && (1 << tItemMelee->GetProto()->SubClass & itr->second.subclass)))
  5194.             {
  5195.                 melee_bonus += itr->second.value;
  5196.             }
  5197.             if(itr->second.wclass == (uint32) - 1 || (tItemRanged != NULL && (1 << tItemRanged->GetProto()->SubClass & itr->second.subclass)))
  5198.             {
  5199.                 ranged_bonus += itr->second.value;
  5200.             }
  5201.         }
  5202.     }
  5203.  
  5204.     float cr = tmp + CalcRating(PLAYER_RATING_MODIFIER_MELEE_CRIT) + melee_bonus;
  5205.     SetFloatValue(PLAYER_CRIT_PERCENTAGE, min(cr, 95.0f));
  5206.  
  5207.     float rcr = tmp + CalcRating(PLAYER_RATING_MODIFIER_RANGED_CRIT) + ranged_bonus;
  5208.     SetFloatValue(PLAYER_RANGED_CRIT_PERCENTAGE, min(rcr, 95.0f));
  5209.  
  5210.     gtFloat* SpellCritBase  = dbcSpellCritBase.LookupEntry(pClass - 1);
  5211.     gtFloat* SpellCritPerInt = dbcSpellCrit.LookupEntry(pLevel - 1 + (pClass - 1) * 100);
  5212.  
  5213.     spellcritperc = 100 * (SpellCritBase->val + GetStat(STAT_INTELLECT) * SpellCritPerInt->val) +
  5214.                     this->GetSpellCritFromSpell() +
  5215.                     this->CalcRating(PLAYER_RATING_MODIFIER_SPELL_CRIT);
  5216.     UpdateChanceFields();
  5217. }
  5218.  
  5219. void Player::UpdateChanceFields()
  5220. {
  5221.     // Update spell crit values in fields
  5222.     for(uint32 i = 0; i < 7; ++i)
  5223.     {
  5224.         SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1 + i, SpellCritChanceSchool[i] + spellcritperc);
  5225.     }
  5226. }
  5227.  
  5228. void Player::ModAttackSpeed(int32 mod, ModType type)
  5229. {
  5230.     if(mod == 0)
  5231.         return;
  5232.  
  5233.     if(mod > 0)
  5234.         m_attack_speed[ type ] *= 1.0f + ((float)mod / 100.0f);
  5235.     else
  5236.         m_attack_speed[ type ] /= 1.0f + ((float)(- mod) / 100.0f);
  5237.  
  5238.     if(type == MOD_SPELL)
  5239.         SetCastSpeedMod(1.0f / (m_attack_speed[ MOD_SPELL ] * SpellHasteRatingBonus));
  5240. }
  5241.  
  5242. void Player::UpdateAttackSpeed()
  5243. {
  5244.     uint32 speed = 2000;
  5245.     Item* weap ;
  5246.  
  5247.     if(GetShapeShift() == FORM_CAT)
  5248.     {
  5249.         speed = 1000;
  5250.     }
  5251.     else if(GetShapeShift() == FORM_BEAR || GetShapeShift() == FORM_DIREBEAR)
  5252.     {
  5253.         speed = 2500;
  5254.     }
  5255.     else if(!disarmed)  // Regular
  5256.     {
  5257.         weap = GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_MAINHAND) ;
  5258.         if(weap != NULL)
  5259.             speed = weap->GetProto()->Delay;
  5260.     }
  5261.     SetBaseAttackTime(MELEE,
  5262.                       (uint32)((float) speed / (m_attack_speed[ MOD_MELEE ] * (1.0f + CalcRating(PLAYER_RATING_MODIFIER_MELEE_HASTE) / 100.0f))));
  5263.  
  5264.     weap = GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_OFFHAND);
  5265.     if(weap != NULL && weap->GetProto()->Class == ITEM_CLASS_WEAPON)
  5266.     {
  5267.         speed = weap->GetProto()->Delay;
  5268.         SetBaseAttackTime(OFFHAND,
  5269.                           (uint32)((float) speed / (m_attack_speed[ MOD_MELEE ] * (1.0f + CalcRating(PLAYER_RATING_MODIFIER_MELEE_HASTE) / 100.0f))));
  5270.     }
  5271.  
  5272.     weap = GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_RANGED);
  5273.     if(weap != NULL)
  5274.     {
  5275.         speed = weap->GetProto()->Delay;
  5276.         SetBaseAttackTime(RANGED,
  5277.                           (uint32)((float) speed / (m_attack_speed[ MOD_RANGED ] * (1.0f + CalcRating(PLAYER_RATING_MODIFIER_RANGED_HASTE) / 100.0f))));
  5278.     }
  5279. }
  5280.  
  5281. void Player::UpdateStats()
  5282. {
  5283.     UpdateAttackSpeed();
  5284.  
  5285.     // Formulas from wowwiki
  5286.  
  5287.     int32 AP = 0;
  5288.     int32 RAP = 0;
  5289.     int32 hpdelta = 128;
  5290.     int32 manadelta = 128;
  5291.  
  5292.     uint32 str = GetStat(STAT_STRENGTH);
  5293.     uint32 agi = GetStat(STAT_AGILITY);
  5294.     uint32 lev = getLevel();
  5295.  
  5296.     // Attack power
  5297.     uint32 cl = getClass();
  5298.     switch(cl)
  5299.     {
  5300.         case DRUID:
  5301.             //(Strength x 2) - 20
  5302.             AP = str * 2 - 20;
  5303.             //Agility - 10
  5304.             RAP = agi - 10;
  5305.  
  5306.             if(GetShapeShift() == FORM_MOONKIN)
  5307.             {
  5308.                 //(Strength x 2) + (Character Level x 1.5) - 20
  5309.                 AP += float2int32(static_cast<float>(lev) * 1.5f);
  5310.             }
  5311.             if(GetShapeShift() == FORM_CAT)
  5312.             {
  5313.                 //(Strength x 2) + Agility + (Character Level x 2) - 20
  5314.                 AP += agi + (lev * 2);
  5315.             }
  5316.             if(GetShapeShift() == FORM_BEAR || GetShapeShift() == FORM_DIREBEAR)
  5317.             {
  5318.                 //(Strength x 2) + (Character Level x 3) - 20
  5319.                 AP += (lev * 3);
  5320.             }
  5321.             break;
  5322.  
  5323.  
  5324.         case ROGUE:
  5325.             //Strength + Agility + (Character Level x 2) - 20
  5326.             AP = str + agi + (lev * 2) - 20;
  5327.             //Character Level + Agility - 10
  5328.             RAP = lev + agi - 10;
  5329.  
  5330.             break;
  5331.  
  5332.  
  5333.         case HUNTER:
  5334.             //Strength + Agility + (Character Level x 2) - 20
  5335.             AP = str + agi + (lev * 2) - 20;
  5336.             //(Character Level x 2) + Agility - 10
  5337.             RAP = (lev * 2) + agi - 10;
  5338.  
  5339.             break;
  5340.  
  5341.         case SHAMAN:
  5342.             //(Strength) + (Agility) + (Character Level x 2) - 20
  5343.             AP = str + agi + (lev * 2) - 20;
  5344.             //Agility - 10
  5345.             RAP = agi - 10;
  5346.  
  5347.             break;
  5348.  
  5349.         case PALADIN:
  5350.             //(Strength x 2) + (Character Level x 3) - 20
  5351.             AP = (str * 2) + (lev * 3) - 20;
  5352.             //Agility - 10
  5353.             RAP = agi - 10;
  5354.  
  5355.             break;
  5356.  
  5357.  
  5358.         case WARRIOR:
  5359.         case DEATHKNIGHT:
  5360.             //(Strength x 2) + (Character Level x 3) - 20
  5361.             AP = (str * 2) + (lev * 3) - 20;
  5362.             //Character Level + Agility - 10
  5363.             RAP = lev + agi - 10;
  5364.  
  5365.             break;
  5366.  
  5367.         default:    //mage,priest,warlock
  5368.             AP = agi - 10;
  5369.     }
  5370.  
  5371.     /* modifiers */
  5372.     RAP += m_rap_mod_pct * m_uint32Values[UNIT_FIELD_STAT3] / 100;
  5373.  
  5374.     if(RAP < 0)RAP = 0;
  5375.     if(AP < 0)AP = 0;
  5376.  
  5377.     SetAttackPower(AP);
  5378.     SetRangedAttackPower(RAP);
  5379.  
  5380.     LevelInfo* lvlinfo = objmgr.GetLevelInfo(this->getRace(), this->getClass(), lev);
  5381.  
  5382.     if(lvlinfo != NULL)
  5383.     {
  5384.         hpdelta = lvlinfo->Stat[2] * 10;
  5385.         manadelta = lvlinfo->Stat[3] * 15;
  5386.     }
  5387.  
  5388.     lvlinfo = objmgr.GetLevelInfo(this->getRace(), this->getClass(), 1);
  5389.  
  5390.     if(lvlinfo != NULL)
  5391.     {
  5392.         hpdelta -= lvlinfo->Stat[2] * 10;
  5393.         manadelta -= lvlinfo->Stat[3] * 15;
  5394.     }
  5395.  
  5396.     uint32 hp = GetBaseHealth();
  5397.  
  5398.     int32 stat_bonus = GetUInt32Value(UNIT_FIELD_POSSTAT2) - GetUInt32Value(UNIT_FIELD_NEGSTAT2);
  5399.     if(stat_bonus < 0)
  5400.         stat_bonus = 0; // Avoid of having negative health
  5401.     int32 bonus = stat_bonus * 10 + m_healthfromspell + m_healthfromitems;
  5402.  
  5403.     uint32 res = hp + bonus + hpdelta;
  5404.     uint32 oldmaxhp = GetUInt32Value(UNIT_FIELD_MAXHEALTH);
  5405.  
  5406.     if(res < hp)
  5407.         res = hp;
  5408.     if(sWorld.m_limits.enable && (sWorld.m_limits.healthCap > 0) && (res > sWorld.m_limits.healthCap) && GetSession()->GetPermissionCount() <= 0)   //hacker?
  5409.     {
  5410.         char logmsg[256];
  5411.         snprintf(logmsg, 256, "has over %u health (%i)", sWorld.m_limits.healthCap, res);
  5412.         sCheatLog.writefromsession(GetSession(), logmsg);
  5413.         if(sWorld.m_limits.broadcast) // send info to online GM
  5414.         {
  5415.             string gm_ann = MSG_COLOR_GREEN;
  5416.             gm_ann += "|Hplayer:";
  5417.             gm_ann += GetName();
  5418.             gm_ann += "|h[";
  5419.             gm_ann += GetName();
  5420.             gm_ann += "]|h: ";
  5421.             gm_ann += MSG_COLOR_YELLOW;
  5422.             gm_ann += logmsg;
  5423.             sWorld.SendGMWorldText(gm_ann.c_str());
  5424.         }
  5425.         if(sWorld.m_limits.disconnect)
  5426.         {
  5427.             GetSession()->Disconnect();
  5428.         }
  5429.         else // no disconnect, set it to the cap instead
  5430.         {
  5431.             res = sWorld.m_limits.healthCap;
  5432.         }
  5433.     }
  5434.     SetUInt32Value(UNIT_FIELD_MAXHEALTH, res);
  5435.  
  5436.     if(GetUInt32Value(UNIT_FIELD_HEALTH) > res)
  5437.         SetHealth(res);
  5438.     else if((cl == DRUID) && (GetShapeShift() == FORM_BEAR || GetShapeShift() == FORM_DIREBEAR))
  5439.     {
  5440.         res = GetUInt32Value(UNIT_FIELD_MAXHEALTH) * GetUInt32Value(UNIT_FIELD_HEALTH) / oldmaxhp;
  5441.         SetHealth(res);
  5442.     }
  5443.  
  5444.     if(cl != WARRIOR && cl != ROGUE && cl != DEATHKNIGHT)
  5445.     {
  5446.         // MP
  5447.         uint32 mana = GetBaseMana();
  5448.  
  5449.         stat_bonus = GetUInt32Value(UNIT_FIELD_POSSTAT3) - GetUInt32Value(UNIT_FIELD_NEGSTAT3);
  5450.         if(stat_bonus < 0)
  5451.             stat_bonus = 0; // Avoid of having negative mana
  5452.         bonus = stat_bonus * 15 + m_manafromspell + m_manafromitems ;
  5453.  
  5454.         res = mana + bonus + manadelta;
  5455.         if(res < mana)
  5456.             res = mana;
  5457.         if(sWorld.m_limits.enable && (sWorld.m_limits.manaCap > 0) && (res > sWorld.m_limits.manaCap) && GetSession()->GetPermissionCount() <= 0)   //hacker?
  5458.         {
  5459.             char logmsg[256];
  5460.             snprintf(logmsg, 256, "has over %u mana (%i)", sWorld.m_limits.manaCap, res);
  5461.             sCheatLog.writefromsession(GetSession(), logmsg);
  5462.             if(sWorld.m_limits.broadcast) // send info to online GM
  5463.             {
  5464.                 string gm_ann = MSG_COLOR_GREEN;
  5465.                 gm_ann += "|Hplayer:";
  5466.                 gm_ann += GetName();
  5467.                 gm_ann += "|h[";
  5468.                 gm_ann += GetName();
  5469.                 gm_ann += "]|h: ";
  5470.                 gm_ann += MSG_COLOR_YELLOW;
  5471.                 gm_ann += logmsg;
  5472.                 sWorld.SendGMWorldText(gm_ann.c_str());
  5473.             }
  5474.             if(sWorld.m_limits.disconnect)
  5475.             {
  5476.                 GetSession()->Disconnect();
  5477.             }
  5478.             else // no disconnect, set it to the cap instead
  5479.             {
  5480.                 res = sWorld.m_limits.manaCap;
  5481.             }
  5482.         }
  5483.         SetMaxPower(POWER_TYPE_MANA, res);
  5484.  
  5485.         if(GetPower(POWER_TYPE_MANA) > res)
  5486.             SetPower(POWER_TYPE_MANA, res);
  5487.  
  5488.         //Manaregen
  5489.         // table from http://www.wowwiki.com/Mana_regeneration
  5490.         const static float BaseRegen[80] = {0.034965f, 0.034191f, 0.033465f, 0.032526f, 0.031661f, 0.031076f, 0.030523f, 0.029994f, 0.029307f, 0.028661f, 0.027584f, 0.026215f, 0.025381f, 0.024300f, 0.023345f, 0.022748f, 0.021958f, 0.021386f, 0.020790f, 0.020121f, 0.019733f, 0.019155f, 0.018819f, 0.018316f, 0.017936f, 0.017576f, 0.017201f, 0.016919f, 0.016581f, 0.016233f, 0.015994f, 0.015707f, 0.015464f, 0.015204f, 0.014956f, 0.014744f, 0.014495f, 0.014302f, 0.014094f, 0.013895f, 0.013724f, 0.013522f, 0.013363f, 0.013175f, 0.012996f, 0.012853f, 0.012687f, 0.012539f, 0.012384f, 0.012233f, 0.012113f, 0.011973f, 0.011859f, 0.011714f, 0.011575f, 0.011473f, 0.011342f, 0.011245f, 0.011110f, 0.010999f, 0.010700f, 0.010522f, 0.010290f, 0.010119f, 0.009968f, 0.009808f, 0.009651f, 0.009553f, 0.009445f, 0.009327f, 0.008859f, 0.008415f, 0.007993f, 0.007592f, 0.007211f, 0.006849f, 0.006506f, 0.006179f, 0.005869f, 0.005575f };
  5491.         uint32 level = getLevel();
  5492.         if(level > 80) level = 80;
  5493.         //float amt = ( 0.001f + sqrt((float)Intellect) * Spirit * BaseRegen[level-1] )*PctPowerRegenModifier[POWER_TYPE_MANA];
  5494.  
  5495.         // Mesmer: new Manaregen formula.
  5496.         uint32 Spirit = GetStat(STAT_SPIRIT);
  5497.         uint32 Intellect = GetStat(STAT_INTELLECT);
  5498.         float amt = (0.001f + sqrt((float)Intellect) * Spirit * BaseRegen[level - 1]) * PctPowerRegenModifier[POWER_TYPE_MANA];
  5499.         SetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER, amt + m_ModInterrMRegen * 0.2f);
  5500.         SetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER, amt * m_ModInterrMRegenPCT / 100.0f + m_ModInterrMRegen * 0.2f);
  5501.     }
  5502.  
  5503.     // Spell haste rating
  5504.     float haste = 1.0f + CalcRating(PLAYER_RATING_MODIFIER_SPELL_HASTE) / 100.0f;
  5505.     if(haste != SpellHasteRatingBonus)
  5506.     {
  5507.         float value = GetCastSpeedMod() * SpellHasteRatingBonus / haste; // remove previous mod and apply current
  5508.  
  5509.         SetCastSpeedMod(value);
  5510.         SpellHasteRatingBonus = haste;  // keep value for next run
  5511.     }
  5512.  
  5513.  
  5514.     // Shield Block
  5515.     Item* shield = GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_OFFHAND);
  5516.     if(shield != NULL && shield->GetProto()->InventoryType == INVTYPE_SHIELD)
  5517.     {
  5518.         float block_multiplier = (100.0f + m_modblockabsorbvalue) / 100.0f;
  5519.         if(block_multiplier < 1.0f)block_multiplier = 1.0f;
  5520.  
  5521.         int32 blockable_damage = float2int32((shield->GetProto()->Block + m_modblockvaluefromspells + GetUInt32Value(PLAYER_RATING_MODIFIER_BLOCK) + (str / 2.0f) - 1.0f) * block_multiplier);
  5522.         SetUInt32Value(PLAYER_SHIELD_BLOCK, blockable_damage);
  5523.     }
  5524.     else
  5525.     {
  5526.         SetUInt32Value(PLAYER_SHIELD_BLOCK, 0);
  5527.     }
  5528.  
  5529.     // Dynamic aura application, auras 212, 268
  5530.     for(uint32 x = MAX_TOTAL_AURAS_START; x < MAX_TOTAL_AURAS_END; x++)
  5531.         if(m_auras[x] != NULL)
  5532.         {
  5533.             if(m_auras[x]->HasModType(SPELL_AURA_MOD_ATTACK_POWER_BY_STAT_PCT) ||
  5534.                     m_auras[x]->HasModType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_BY_STAT_PCT))
  5535.                 m_auras[x]->UpdateModifiers();
  5536.         }
  5537.  
  5538.     UpdateChances();
  5539.     CalcDamage();
  5540. }
  5541.  
  5542. uint32 Player::SubtractRestXP(uint32 amount)
  5543. {
  5544.     if(getLevel() >= GetMaxLevel())     // Save CPU, don't waste time on this if you've reached max_level
  5545.         amount = 0;
  5546.  
  5547.     int32 restAmount = m_restAmount - (amount << 1);                                    // remember , we are dealing with xp without restbonus, so multiply by 2
  5548.  
  5549.     if(restAmount < 0)
  5550.         m_restAmount = 0;
  5551.     else
  5552.         m_restAmount = restAmount;
  5553.  
  5554.     Log.Debug("REST", "Subtracted %d rest XP to a total of %d", amount, m_restAmount);
  5555.     UpdateRestState();                                                                  // Update clients interface with new values.
  5556.     return amount;
  5557. }
  5558.  
  5559. void Player::AddCalculatedRestXP(uint32 seconds)
  5560. {
  5561.     // At level one, players will all start in the normal tier.
  5562.     // When a player rests in a city or at an inn they will gain rest bonus at a very slow rate.
  5563.     // Eight hours of rest will be needed for a player to gain one "bubble" of rest bonus.
  5564.     // At any given time, players will be able to accumulate a maximum of 30 "bubbles" worth of rest bonus which
  5565.     // translates into approximately 1.5 levels worth of rested play (before your character returns to normal rest state).
  5566.     // Thanks to the comforts of a warm bed and a hearty meal, players who rest or log out at an Inn will
  5567.     // accumulate rest credit four times faster than players logged off outside of an Inn or City.
  5568.     // Players who log out anywhere else in the world will earn rest credit four times slower.
  5569.     // http://www.worldofwarcraft.com/info/basics/resting.html
  5570.  
  5571.  
  5572.     // Define xp for a full bar ( = 20 bubbles)
  5573.     uint32 xp_to_lvl = uint32(lvlinfo->XPToNextLevel);
  5574.  
  5575.     // get RestXP multiplier from config.
  5576.     float bubblerate = sWorld.getRate(RATE_RESTXP);
  5577.  
  5578.     // One bubble (5% of xp_to_level) for every 8 hours logged out.
  5579.     // if multiplier RestXP (from ascent.config) is f.e 2, you only need 4hrs/bubble.
  5580.     uint32 rested_xp = uint32(0.05f * xp_to_lvl * (seconds / (3600 * (8 / bubblerate))));
  5581.  
  5582.     // if we are at a resting area rest_XP goes 4 times faster (making it 1 bubble every 2 hrs)
  5583.     if(m_isResting)
  5584.         rested_xp <<= 2;
  5585.  
  5586.     // Add result to accumulated rested XP
  5587.     m_restAmount += uint32(rested_xp);
  5588.  
  5589.     // and set limit to be max 1.5 * 20 bubbles * multiplier (1.5 * xp_to_level * multiplier)
  5590.     if(m_restAmount > xp_to_lvl + (uint32)((float)(xp_to_lvl >> 1) * bubblerate))
  5591.         m_restAmount = xp_to_lvl + (uint32)((float)(xp_to_lvl >> 1) * bubblerate);
  5592.  
  5593.     Log.Debug("REST", "Add %d rest XP to a total of %d, RestState %d", rested_xp, m_restAmount, m_isResting);
  5594.  
  5595.     // Update clients interface with new values.
  5596.     UpdateRestState();
  5597. }
  5598.  
  5599. void Player::UpdateRestState()
  5600. {
  5601.     if(m_restAmount && getLevel() < GetMaxLevel())
  5602.         m_restState = RESTSTATE_RESTED;
  5603.     else
  5604.         m_restState = RESTSTATE_NORMAL;
  5605.  
  5606.     // Update RestState 100%/200%
  5607.     SetUInt32Value(PLAYER_BYTES_2, ((GetUInt32Value(PLAYER_BYTES_2) & 0x00FFFFFF) | (m_restState << 24)));
  5608.  
  5609.     //update needle (weird, works at 1/2 rate)
  5610.     SetUInt32Value(PLAYER_REST_STATE_EXPERIENCE, m_restAmount >> 1);
  5611. }
  5612.  
  5613. void Player::ApplyPlayerRestState(bool apply)
  5614. {
  5615.     if(apply)
  5616.     {
  5617.         m_restState = RESTSTATE_RESTED;
  5618.         m_isResting = true;
  5619.         SetFlag(PLAYER_FLAGS, PLAYER_FLAG_RESTING); //put zZz icon
  5620.     }
  5621.     else
  5622.     {
  5623.         m_isResting = false;
  5624.         RemoveFlag(PLAYER_FLAGS, PLAYER_FLAG_RESTING);  //remove zZz icon
  5625.     }
  5626.     UpdateRestState();
  5627. }
  5628.  
  5629. #define CORPSE_VIEW_DISTANCE 1600 // 40*40
  5630.  
  5631. bool Player::CanSee(Object* obj) // * Invisibility & Stealth Detection - Partha *
  5632. {
  5633.     if(obj == this)
  5634.         return true;
  5635.  
  5636.     uint32 object_type = obj->GetTypeId();
  5637.  
  5638.     if(getDeathState() == CORPSE) // we are dead and we have released our spirit
  5639.     {
  5640.         if(obj->IsPlayer())
  5641.         {
  5642.             Player* pObj = TO< Player* >(obj);
  5643.  
  5644.             if(myCorpseInstanceId == GetInstanceID() && obj->GetDistanceSq(myCorpseLocation) <= CORPSE_VIEW_DISTANCE)
  5645.                 return !pObj->m_isGmInvisible; // we can see all players within range of our corpse except invisible GMs
  5646.  
  5647.             if(m_deathVision) // if we have arena death-vision we can see all players except invisible GMs
  5648.                 return !pObj->m_isGmInvisible;
  5649.  
  5650.             return (pObj->getDeathState() == CORPSE); // we can only see players that are spirits
  5651.         }
  5652.  
  5653.         if(myCorpseInstanceId == GetInstanceID())
  5654.         {
  5655.             if(obj->IsCorpse() && TO< Corpse* >(obj)->GetOwner() == GetGUID())
  5656.                 return true;
  5657.  
  5658.             if(obj->GetDistanceSq(myCorpseLocation) <= CORPSE_VIEW_DISTANCE)
  5659.                 return true; // we can see everything within range of our corpse
  5660.         }
  5661.  
  5662.         if(m_deathVision) // if we have arena death-vision we can see everything
  5663.             return true;
  5664.  
  5665.         if(obj->IsCreature())
  5666.         {
  5667.             Creature* uObj = TO_CREATURE(obj);
  5668.  
  5669.             return uObj->IsSpiritHealer(); // we can't see any NPCs except spirit-healers
  5670.         }
  5671.  
  5672.         return false;
  5673.     }
  5674.     //------------------------------------------------------------------
  5675.  
  5676.     if(!(m_phase & obj->m_phase))  //What you can't see, you can't see, no need to check things further.
  5677.         return false;
  5678.  
  5679.     switch(object_type) // we are alive or we haven't released our spirit yet
  5680.     {
  5681.         case TYPEID_PLAYER:
  5682.             {
  5683.                 Player* pObj = TO< Player* >(obj);
  5684.  
  5685.                 if(pObj->m_invisible) // Invisibility - Detection of Players
  5686.                 {
  5687.                     if(pObj->getDeathState() == CORPSE)
  5688.                         return (HasFlag(PLAYER_FLAGS, PLAYER_FLAG_GM) != 0); // only GM can see players that are spirits
  5689.  
  5690.                     if(GetGroup() && pObj->GetGroup() == GetGroup() // can see invisible group members except when dueling them
  5691.                             && DuelingWith != pObj)
  5692.                         return true;
  5693.  
  5694.                     if(pObj->stalkedby == GetGUID()) // Hunter's Mark / MindVision is visible to the caster
  5695.                         return true;
  5696.  
  5697.                     if(m_invisDetect[INVIS_FLAG_NORMAL] < 1 // can't see invisible without proper detection
  5698.                             || pObj->m_isGmInvisible) // can't see invisible GM
  5699.                         return (HasFlag(PLAYER_FLAGS, PLAYER_FLAG_GM) != 0); // GM can see invisible players
  5700.                 }
  5701.  
  5702.                 if(m_invisible && pObj->m_invisDetect[m_invisFlag] < 1)   // Invisible - can see those that detect, but not others
  5703.                     return m_isGmInvisible;
  5704.  
  5705.                 if(pObj->IsStealth()) // Stealth Detection (  I Hate Rogues :P  )
  5706.                 {
  5707.                     if(GetGroup() && pObj->GetGroup() == GetGroup() // can see stealthed group members except when dueling them
  5708.                             && DuelingWith != pObj)
  5709.                         return true;
  5710.  
  5711.                     if(pObj->stalkedby == GetGUID()) // Hunter's Mark / MindVision is visible to the caster
  5712.                         return true;
  5713.  
  5714.                     if(isInFront(pObj)) // stealthed player is in front of us
  5715.                     {
  5716.                         // Detection Range = 5yds + (Detection Skill - Stealth Skill)/5
  5717.                         if(getLevel() < PLAYER_LEVEL_CAP)
  5718.                             detectRange = 5.0f + getLevel() + 0.2f * (float)(GetStealthDetectBonus() - pObj->GetStealthLevel());
  5719.                         else
  5720.                             detectRange = 85.0f + 0.2f * (float)(GetStealthDetectBonus() - pObj->GetStealthLevel());
  5721.                         // Hehe... stealth skill is increased by 5 each level and detection skill is increased by 5 each level too.
  5722.                         // This way, a level 70 should easily be able to detect a level 4 rogue (level 4 because that's when you get stealth)
  5723.                         //  detectRange += 0.2f * ( getLevel() - pObj->getLevel() );
  5724.                         if(detectRange < 1.0f) detectRange = 1.0f; // Minimum Detection Range = 1yd
  5725.                     }
  5726.                     else // stealthed player is behind us
  5727.                     {
  5728.                         if(GetStealthDetectBonus() > 1000) return true; // immune to stealth
  5729.                         else detectRange = 0.0f;
  5730.                     }
  5731.  
  5732.                     detectRange += GetBoundingRadius(); // adjust range for size of player
  5733.                     detectRange += pObj->GetBoundingRadius(); // adjust range for size of stealthed player
  5734.                     //sLog.outString( "Player::CanSee(%s): detect range = %f yards (%f ingame units), cansee = %s , distance = %f" , pObj->GetName() , detectRange , detectRange * detectRange , ( GetDistance2dSq(pObj) > detectRange * detectRange ) ? "yes" : "no" , GetDistanceSq(pObj) );
  5735.                     if(GetDistanceSq(pObj) > detectRange * detectRange)
  5736.                         return (HasFlag(PLAYER_FLAGS, PLAYER_FLAG_GM) != 0); // GM can see stealthed players
  5737.                 }
  5738.  
  5739.                 return !pObj->m_isGmInvisible;
  5740.             }
  5741.             //------------------------------------------------------------------
  5742.  
  5743.         case TYPEID_UNIT:
  5744.             {
  5745.                 Unit* uObj = TO< Unit* >(obj);
  5746.  
  5747.                 if(uObj->IsSpiritHealer())  // can't see spirit-healers when alive
  5748.                     return false;
  5749.  
  5750.                 // always see our units
  5751.                 if(GetGUID() == uObj->GetCreatedByGUID())
  5752.                     return true;
  5753.  
  5754.                 if(uObj->m_invisible  // Invisibility - Detection of Units
  5755.                         && m_invisDetect[uObj->m_invisFlag] < 1) // can't see invisible without proper detection
  5756.                     return (HasFlag(PLAYER_FLAGS, PLAYER_FLAG_GM) != 0); // GM can see invisible units
  5757.  
  5758.                 if(m_invisible && uObj->m_invisDetect[m_invisFlag] < 1)   // Invisible - can see those that detect, but not others
  5759.                     return m_isGmInvisible;
  5760.  
  5761.                 return true;
  5762.             }
  5763.             //------------------------------------------------------------------
  5764.  
  5765.         case TYPEID_GAMEOBJECT:
  5766.             {
  5767.                 GameObject* gObj = TO< GameObject* >(obj);
  5768.  
  5769.                 if(gObj->invisible) // Invisibility - Detection of GameObjects
  5770.                 {
  5771.                     uint64 owner = gObj->GetUInt64Value(OBJECT_FIELD_CREATED_BY);
  5772.  
  5773.                     if(GetGUID() == owner) // the owner of an object can always see it
  5774.                         return true;
  5775.  
  5776.                     if(GetGroup())
  5777.                     {
  5778.                         PlayerInfo* inf = objmgr.GetPlayerInfo((uint32)owner);
  5779.                         if(inf && GetGroup()->HasMember(inf))
  5780.                             return true;
  5781.                     }
  5782.  
  5783.                     if(m_invisDetect[gObj->invisibilityFlag] < 1) // can't see invisible without proper detection
  5784.                         return (HasFlag(PLAYER_FLAGS, PLAYER_FLAG_GM) != 0); // GM can see invisible objects
  5785.                 }
  5786.  
  5787.                 return true;
  5788.             }
  5789.             //------------------------------------------------------------------
  5790.  
  5791.         default:
  5792.             return true;
  5793.     }
  5794. }
  5795.  
  5796. void Player::AddInRangeObject(Object* pObj)
  5797. {
  5798.     //Send taxi move if we're on a taxi
  5799.     if(m_CurrentTaxiPath && pObj->IsPlayer())
  5800.     {
  5801.         uint32 ntime = getMSTime();
  5802.  
  5803.         if(ntime > m_taxi_ride_time)
  5804.             m_CurrentTaxiPath->SendMoveForTime(this, TO< Player* >(pObj), ntime - m_taxi_ride_time);
  5805.         /*else
  5806.             m_CurrentTaxiPath->SendMoveForTime( this, TO< Player* >( pObj ), m_taxi_ride_time - ntime);*/
  5807.     }
  5808.  
  5809.     Unit::AddInRangeObject(pObj);
  5810.  
  5811.     //if the object is a unit send a move packet if they have a destination
  5812.     if(pObj->IsCreature())
  5813.     {
  5814.         TO< Creature* >(pObj)->GetAIInterface()->SendCurrentMove(this);
  5815.     }
  5816. }
  5817. void Player::OnRemoveInRangeObject(Object* pObj)
  5818. {
  5819.     //object was deleted before reaching here
  5820.     if(pObj == NULL)
  5821.         return;
  5822.  
  5823.     if(IsVisible(pObj->GetGUID()))
  5824.         PushOutOfRange(pObj->GetNewGUID());
  5825.  
  5826.     m_visibleObjects.erase(pObj->GetGUID());
  5827.     Unit::OnRemoveInRangeObject(pObj);
  5828.  
  5829.     if(pObj->GetGUID() == m_CurrentCharm)
  5830.     {
  5831.         Unit* p = GetMapMgr()->GetUnit(m_CurrentCharm);
  5832.         if(!p)
  5833.             return;
  5834.  
  5835.         UnPossess();
  5836.         if(m_currentSpell)
  5837.             m_currentSpell->cancel();      // cancel the spell
  5838.         m_CurrentCharm = 0;
  5839.  
  5840.     }
  5841.  
  5842.     // We've just gone out of range of our pet :(
  5843.     std::list<Pet*> summons = GetSummons();
  5844.     for(std::list<Pet*>::iterator itr = summons.begin(); itr != summons.end();)
  5845.     {
  5846.         Pet* summon = (*itr);
  5847.         ++itr;
  5848.         if(pObj == summon)
  5849.         {
  5850.             summon->DelayedRemove(false, false, 1);//delayed otherwise Object::RemoveInRangeObject() will remove twice the Pet from inrangeset. Refer to r3199
  5851.             return;
  5852.         }
  5853.     }
  5854.  
  5855.     if(pObj->GetGUID() == GetSummonedUnitGUID())
  5856.         sEventMgr.AddEvent(TO_UNIT(this), &Unit::RemoveFieldSummon, EVENT_SUMMON_EXPIRE, 1, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);//otherwise Creature::Update() will access free'd memory
  5857. }
  5858.  
  5859. void Player::ClearInRangeSet()
  5860. {
  5861.     m_visibleObjects.clear();
  5862.     Unit::ClearInRangeSet();
  5863. }
  5864.  
  5865. void Player::EventCannibalize(uint32 amount)
  5866. {
  5867.     if(GetChannelSpellId() != 20577)
  5868.     {
  5869.         sEventMgr.RemoveEvents(this, EVENT_CANNIBALIZE);
  5870.         cannibalize = false;
  5871.         cannibalizeCount = 0;
  5872.         return;
  5873.     }
  5874.     uint32 amt = (GetMaxHealth() * amount) / 100;
  5875.  
  5876.     uint32 newHealth = GetHealth() + amt;
  5877.  
  5878.     if(newHealth <= GetMaxHealth())
  5879.         SetHealth(newHealth);
  5880.     else
  5881.         SetHealth(GetMaxHealth());
  5882.  
  5883.     cannibalizeCount++;
  5884.     if(cannibalizeCount == 5)
  5885.         SetEmoteState(0);
  5886.  
  5887.     SendPeriodicHealAuraLog(GetNewGUID(), GetNewGUID(), 20577, amt, 0, false);
  5888. }
  5889.  
  5890. ///The player sobers by 256 every 10 seconds
  5891. void Player::HandleSobering()
  5892. {
  5893.     m_drunkTimer = 0;
  5894.  
  5895.     SetDrunkValue((m_drunk <= 256) ? 0 : (m_drunk - 256));
  5896. }
  5897.  
  5898. DrunkenState Player::GetDrunkenstateByValue(uint16 value)
  5899. {
  5900.     if(value >= 23000)
  5901.         return DRUNKEN_SMASHED;
  5902.     if(value >= 12800)
  5903.         return DRUNKEN_DRUNK;
  5904.     if(value & 0xFFFE)
  5905.         return DRUNKEN_TIPSY;
  5906.     return DRUNKEN_SOBER;
  5907. }
  5908.  
  5909. void Player::SetDrunkValue(uint16 newDrunkenValue, uint32 itemId)
  5910. {
  5911.     uint32 oldDrunkenState = Player::GetDrunkenstateByValue(m_drunk);
  5912.  
  5913.     m_drunk = newDrunkenValue;
  5914.     SetUInt32Value(PLAYER_BYTES_3, (GetUInt32Value(PLAYER_BYTES_3) & 0xFFFF0001) | (m_drunk & 0xFFFE));
  5915.  
  5916.     uint32 newDrunkenState = Player::GetDrunkenstateByValue(m_drunk);
  5917.  
  5918.     if(newDrunkenState == oldDrunkenState)
  5919.         return;
  5920.  
  5921.     // special drunk invisibility detection
  5922.     if(newDrunkenState >= DRUNKEN_DRUNK)
  5923.         m_invisDetect[ INVIS_FLAG_UNKNOWN6 ] = 100;
  5924.     else
  5925.         m_invisDetect[ INVIS_FLAG_UNKNOWN6 ] = 0;
  5926.  
  5927.     UpdateVisibility();
  5928.  
  5929.     SendNewDrunkState(newDrunkenState, itemId);
  5930. }
  5931.  
  5932. void Player::LoadTaxiMask(const char* data)
  5933. {
  5934.     vector<string> tokens = StrSplit(data, " ");
  5935.  
  5936.     int index;
  5937.     vector<string>::iterator iter;
  5938.  
  5939.     for(iter = tokens.begin(), index = 0;
  5940.             (index < 12) && (iter != tokens.end()); ++iter, ++index)
  5941.     {
  5942.         m_taximask[index] = atol((*iter).c_str());
  5943.     }
  5944. }
  5945.  
  5946. bool Player::HasQuestForItem(uint32 itemid)
  5947. {
  5948.     Quest* qst;
  5949.     for(uint32 i = 0; i < 25; ++i)
  5950.     {
  5951.         if(m_questlog[i] != NULL)
  5952.         {
  5953.             qst = m_questlog[i]->GetQuest();
  5954.  
  5955.             // Check the item_quest_association table for an entry related to this item
  5956.             QuestAssociationList* tempList = QuestMgr::getSingleton().GetQuestAssociationListForItemId(itemid);
  5957.             if(tempList != NULL)
  5958.             {
  5959.                 QuestAssociationList::iterator it;
  5960.                 for(it = tempList->begin(); it != tempList->end(); ++it)
  5961.                 {
  5962.                     if(((*it)->qst == qst) && (GetItemInterface()->GetItemCount(itemid) < (*it)->item_count))
  5963.                     {
  5964.                         return true;
  5965.                     } // end if
  5966.                 } // end for
  5967.             } // end if
  5968.  
  5969.             // No item_quest association found, check the quest requirements
  5970.             if(!qst->count_required_item)
  5971.                 continue;
  5972.  
  5973.             for(uint32 j = 0; j < MAX_REQUIRED_QUEST_ITEM; ++j)
  5974.                 if(qst->required_item[j] == itemid && (GetItemInterface()->GetItemCount(itemid) < qst->required_itemcount[j]))
  5975.                     return true;
  5976.         }
  5977.     }
  5978.     return false;
  5979. }
  5980.  
  5981.  
  5982. //scriptdev2
  5983. bool Player::HasItemCount(uint32 item, uint32 count, bool inBankAlso) const
  5984. {
  5985.     return (m_ItemInterface->GetItemCount(item, inBankAlso) == count);
  5986. }
  5987.  
  5988.  
  5989. void Player::EventAllowTiggerPort(bool enable)
  5990. {
  5991.     m_AllowAreaTriggerPort = enable;
  5992. }
  5993.  
  5994. uint32 Player::CalcTalentResetCost(uint32 resetnum)
  5995. {
  5996.  
  5997.     if(resetnum == 0)
  5998.         return  10000;
  5999.     else
  6000.     {
  6001.         if(resetnum > 10)
  6002.             return  500000;
  6003.         else return resetnum * 50000;
  6004.     }
  6005. }
  6006.  
  6007. int32 Player::CanShootRangedWeapon(uint32 spellid, Unit* target, bool autoshot)
  6008. {
  6009.     SpellEntry* spellinfo = dbcSpell.LookupEntryForced(spellid);
  6010.  
  6011.     if(spellinfo == NULL)
  6012.         return -1;
  6013.     //sLog.outString( "Canshootwithrangedweapon!?!? spell: [%u] %s" , spellinfo->Id , spellinfo->Name );
  6014.  
  6015.     // Check if Morphed
  6016.     if(polySpell > 0)
  6017.         return SPELL_FAILED_NOT_SHAPESHIFT;
  6018.  
  6019.     // Check ammo
  6020.     Item* itm = GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_RANGED);
  6021.     ItemPrototype* iprot = ItemPrototypeStorage.LookupEntry(GetAmmoId());
  6022.     if(itm == NULL || disarmed) //Disarmed means disarmed, we shouldn't be able to cast Auto Shot while disarmed
  6023.         return SPELL_FAILED_NO_AMMO; //In proper language means "Requires Ranged Weapon to be equipped"
  6024.     if(!m_requiresNoAmmo) //Thori'dal, Wild Quiver, but it still requires to have a weapon equipped
  6025.     {
  6026.         // Check ammo level
  6027.         if(iprot && getLevel() < iprot->RequiredLevel)
  6028.             return SPELL_FAILED_LOWLEVEL;
  6029.  
  6030.         // Check ammo type
  6031.         ItemPrototype* iprot1 = ItemPrototypeStorage.LookupEntry(itm->GetEntry());
  6032.         if(iprot && iprot1 && iprot->SubClass != iprot1->AmmoType)
  6033.             return SPELL_FAILED_NEED_AMMO;
  6034.     }
  6035.  
  6036.     // Player has clicked off target. Fail spell.
  6037.     if(m_curSelection != m_AutoShotTarget)
  6038.         return SPELL_FAILED_INTERRUPTED;
  6039.  
  6040.     // Check if target is already dead
  6041.     if(target->IsDead())
  6042.         return SPELL_FAILED_TARGETS_DEAD;
  6043.  
  6044.     // Check if in line of sight (need collision detection).
  6045.     if(sWorld.Collision)
  6046.     {
  6047.         if(GetMapId() == target->GetMapId() && !CollideInterface.CheckLOS(GetMapId(), GetPositionNC(), target->GetPositionNC()))
  6048.             return SPELL_FAILED_LINE_OF_SIGHT;
  6049.     }
  6050.  
  6051.     // Check if we aren't casting another spell already
  6052.     if(GetCurrentSpell())
  6053.         return -1;
  6054.  
  6055.     // Supalosa - The hunter ability Auto Shot is using Shoot range, which is 5 yards shorter.
  6056.     // So we'll use 114, which is the correct 35 yard range used by the other Hunter abilities (arcane shot, concussive shot...)
  6057.     uint8 fail = 0;
  6058.     uint32 rIndex = autoshot ? 114 : spellinfo->rangeIndex;
  6059.     SpellRange* range = dbcSpellRange.LookupEntry(rIndex);
  6060.     float minrange = GetMinRange(range);
  6061.     float dist = CalcDistance(this, target);
  6062.     float maxr = GetMaxRange(range) + 2.52f;
  6063.  
  6064.     if(spellinfo->SpellGroupType)
  6065.     {
  6066.         SM_FFValue(this->SM_FRange, &maxr, spellinfo->SpellGroupType);
  6067.         SM_PFValue(this->SM_PRange, &maxr, spellinfo->SpellGroupType);
  6068.     }
  6069.  
  6070.     //float bonusRange = 0;
  6071.     // another hackfix: bonus range from hunter talent hawk eye: +2/4/6 yard range to ranged weapons
  6072.     //if(autoshot)
  6073.     //SM_FFValue( SM_FRange, &bonusRange, dbcSpell.LookupEntry( 75 )->SpellGroupType ); // HORRIBLE hackfixes :P
  6074.     // Partha: +2.52yds to max range, this matches the range the client is calculating.
  6075.     // see extra/supalosa_range_research.txt for more info
  6076.     //bonusRange = 2.52f;
  6077.     //sLog.outString( "Bonus range = %f" , bonusRange );
  6078.  
  6079.     // check if facing target
  6080.     if(!isInFront(target))
  6081.     {
  6082.         fail = SPELL_FAILED_UNIT_NOT_INFRONT;
  6083.     }
  6084.  
  6085.     // Check ammo count
  6086.     if(!m_requiresNoAmmo && iprot && itm->GetProto()->SubClass != ITEM_SUBCLASS_WEAPON_WAND)
  6087.     {
  6088.         uint32 ammocount = GetItemInterface()->GetItemCount(iprot->ItemId);
  6089.         if(ammocount == 0)
  6090.             fail = SPELL_FAILED_NO_AMMO;
  6091.     }
  6092.  
  6093.     // Check for too close
  6094.     if(spellid != SPELL_RANGED_WAND)  //no min limit for wands
  6095.         if(minrange > dist)
  6096.             fail = SPELL_FAILED_TOO_CLOSE;
  6097.     if(sWorld.Collision && GetMapId() == target->GetMapId() && !CollideInterface.CheckLOS(GetMapId(), GetPositionNC(), target->GetPositionNC()))
  6098.         fail = SPELL_FAILED_LINE_OF_SIGHT ;
  6099.     if(dist > maxr)
  6100.     {
  6101.         //  sLog.outString( "Auto shot failed: out of range (Maxr: %f, Dist: %f)" , maxr , dist );
  6102.         fail = SPELL_FAILED_OUT_OF_RANGE;
  6103.     }
  6104.  
  6105.     if(spellid == SPELL_RANGED_THROW)
  6106.     {
  6107.         if(itm != NULL)   // no need for this
  6108.             if(GetItemInterface()->GetItemCount(itm->GetProto()->ItemId) == 0)
  6109.                 fail = SPELL_FAILED_NO_AMMO;
  6110.     }
  6111.  
  6112.     if(fail > 0)  // && fail != SPELL_FAILED_OUT_OF_RANGE)
  6113.     {
  6114.         SendCastResult(autoshot ? 75 : spellid, fail, 0, 0);
  6115.  
  6116.         if(fail != SPELL_FAILED_OUT_OF_RANGE)
  6117.         {
  6118.             uint32 spellid2 = autoshot ? 75 : spellid;
  6119.             m_session->OutPacket(SMSG_CANCEL_AUTO_REPEAT, 4, &spellid2);
  6120.         }
  6121.         //sLog.outString( "Result for CanShootWIthRangedWeapon: %u" , fail );
  6122.         //LOG_DEBUG( "Can't shoot with ranged weapon: %u (Timer: %u)" , fail , m_AutoShotAttackTimer );
  6123.         return fail;
  6124.     }
  6125.  
  6126.     return 0;
  6127. }
  6128.  
  6129. void Player::EventRepeatSpell()
  6130. {
  6131.     if(!m_curSelection || !IsInWorld())
  6132.         return;
  6133.  
  6134.     Unit* target = GetMapMgr()->GetUnit(m_curSelection);
  6135.     if(target == NULL)
  6136.     {
  6137.         m_AutoShotAttackTimer = 0; //avoid flooding client with error messages
  6138.         m_onAutoShot = false;
  6139.         //LOG_DEBUG( "Can't cast Autoshot: Target changed! (Timer: %u)" , m_AutoShotAttackTimer );
  6140.         return;
  6141.     }
  6142.  
  6143.     m_AutoShotDuration = m_uint32Values[UNIT_FIELD_RANGEDATTACKTIME];
  6144.  
  6145.     if(m_isMoving)
  6146.     {
  6147.         //LOG_DEBUG( "HUNTER AUTOSHOT 2) %i, %i", m_AutoShotAttackTimer, m_AutoShotDuration );
  6148.         //m_AutoShotAttackTimer = m_AutoShotDuration;//avoid flooding client with error messages
  6149.         //LOG_DEBUG( "Can't cast Autoshot: You're moving! (Timer: %u)" , m_AutoShotAttackTimer );
  6150.         m_AutoShotAttackTimer = 100; // shoot when we can
  6151.         return;
  6152.     }
  6153.  
  6154.     int32 f = this->CanShootRangedWeapon(m_AutoShotSpell->Id, target, true);
  6155.  
  6156.     if(f != 0)
  6157.     {
  6158.         if(f != SPELL_FAILED_OUT_OF_RANGE)
  6159.         {
  6160.             m_AutoShotAttackTimer = 0;
  6161.             m_onAutoShot = false;
  6162.         }
  6163.         else if(m_isMoving)
  6164.         {
  6165.             m_AutoShotAttackTimer = 100;
  6166.         }
  6167.         else
  6168.         {
  6169.             m_AutoShotAttackTimer = m_AutoShotDuration;//avoid flooding client with error messages
  6170.         }
  6171.         return;
  6172.     }
  6173.     else
  6174.     {
  6175.         m_AutoShotAttackTimer = m_AutoShotDuration;
  6176.  
  6177.         ARCEMU_ASSERT(m_AutoShotSpell != NULL);
  6178.         Spell* sp = sSpellFactoryMgr.NewSpell(this, m_AutoShotSpell, true, NULL);
  6179.         SpellCastTargets tgt;
  6180.         tgt.m_unitTarget = m_curSelection;
  6181.         tgt.m_targetMask = TARGET_FLAG_UNIT;
  6182.         sp->prepare(&tgt);
  6183.     }
  6184. }
  6185.  
  6186. bool Player::HasSpell(uint32 spell)
  6187. {
  6188.     return mSpells.find(spell) != mSpells.end();
  6189. }
  6190.  
  6191. bool Player::HasSpellwithNameHash(uint32 hash)
  6192. {
  6193.     SpellSet::iterator it, iter;
  6194.     for(iter = mSpells.begin(); iter != mSpells.end();)
  6195.     {
  6196.         it = iter++;
  6197.         uint32 SpellID = *it;
  6198.         SpellEntry* e = dbcSpell.LookupEntry(SpellID);
  6199.         if(e->NameHash == hash)
  6200.             return true;
  6201.     }
  6202.     return false;
  6203. }
  6204.  
  6205. bool Player::HasDeletedSpell(uint32 spell)
  6206. {
  6207.     return (mDeletedSpells.count(spell) > 0);
  6208. }
  6209.  
  6210. void Player::removeSpellByHashName(uint32 hash)
  6211. {
  6212.     SpellSet::iterator it, iter;
  6213.  
  6214.     for(iter = mSpells.begin(); iter != mSpells.end();)
  6215.     {
  6216.         it = iter++;
  6217.         uint32 SpellID = *it;
  6218.         SpellEntry* e = dbcSpell.LookupEntry(SpellID);
  6219.         if(e->NameHash == hash)
  6220.         {
  6221.             if(info->spell_list.find(e->Id) != info->spell_list.end())
  6222.                 continue;
  6223.  
  6224.             RemoveAura(SpellID, GetGUID());
  6225.  
  6226.             m_session->OutPacket(SMSG_REMOVED_SPELL, 4, &SpellID);
  6227.  
  6228.             mSpells.erase(it);
  6229.         }
  6230.     }
  6231.  
  6232.     for(iter = mDeletedSpells.begin(); iter != mDeletedSpells.end();)
  6233.     {
  6234.         it = iter++;
  6235.         uint32 SpellID = *it;
  6236.         SpellEntry* e = dbcSpell.LookupEntry(SpellID);
  6237.         if(e->NameHash == hash)
  6238.         {
  6239.             if(info->spell_list.find(e->Id) != info->spell_list.end())
  6240.                 continue;
  6241.  
  6242.             RemoveAura(SpellID, GetGUID());
  6243.  
  6244.             m_session->OutPacket(SMSG_REMOVED_SPELL, 4, &SpellID);
  6245.  
  6246.             mDeletedSpells.erase(it);
  6247.         }
  6248.     }
  6249. }
  6250.  
  6251. bool Player::removeSpell(uint32 SpellID, bool MoveToDeleted, bool SupercededSpell, uint32 SupercededSpellID)
  6252. {
  6253.     SpellSet::iterator it, iter = mSpells.find(SpellID);
  6254.     if(iter != mSpells.end())
  6255.     {
  6256.         mSpells.erase(iter);
  6257.         RemoveAura(SpellID, GetGUID());
  6258.     }
  6259.     else
  6260.     {
  6261.         iter = mDeletedSpells.find(SpellID);
  6262.         if(iter != mDeletedSpells.end())
  6263.         {
  6264.             mDeletedSpells.erase(iter);
  6265.         }
  6266.         else
  6267.         {
  6268.             return false;
  6269.         }
  6270.     }
  6271.  
  6272.     if(MoveToDeleted)
  6273.         mDeletedSpells.insert(SpellID);
  6274.  
  6275.     if(!IsInWorld())
  6276.         return true;
  6277.  
  6278.     if(SupercededSpell)
  6279.     {
  6280.         WorldPacket data(SMSG_SUPERCEDED_SPELL, 8);
  6281.         data << SpellID << SupercededSpellID;
  6282.         m_session->SendPacket(&data);
  6283.     }
  6284.     else
  6285.     {
  6286.         m_session->OutPacket(SMSG_REMOVED_SPELL, 4, &SpellID);
  6287.     }
  6288.  
  6289.     return true;
  6290. }
  6291.  
  6292. bool Player::removeDeletedSpell(uint32 SpellID)
  6293. {
  6294.     SpellSet::iterator it = mDeletedSpells.find(SpellID);
  6295.     if(it == mDeletedSpells.end())
  6296.         return false;
  6297.  
  6298.     mDeletedSpells.erase(it);
  6299.     return true;
  6300. }
  6301.  
  6302. void Player::EventActivateGameObject(GameObject* obj)
  6303. {
  6304.     obj->BuildFieldUpdatePacket(this, GAMEOBJECT_DYNAMIC, 1 | 8);
  6305. }
  6306.  
  6307. void Player::EventDeActivateGameObject(GameObject* obj)
  6308. {
  6309.     obj->BuildFieldUpdatePacket(this, GAMEOBJECT_DYNAMIC, 0);
  6310. }
  6311.  
  6312. void Player::EventTimedQuestExpire( uint32 questid ){
  6313.     QuestLogEntry *qle = this->GetQuestLogForEntry( questid );
  6314.     if( qle == NULL )
  6315.         return;
  6316.  
  6317.     Quest *qst = qle->GetQuest();
  6318.  
  6319.     sQuestMgr.SendQuestUpdateFailedTimer( qst, this );
  6320.     CALL_QUESTSCRIPT_EVENT(qle, OnQuestCancel)(this);
  6321.     qle->Fail( true );
  6322. }
  6323.  
  6324. //scriptdev2
  6325.  
  6326. void Player::AreaExploredOrEventHappens(uint32 questId)
  6327. {
  6328.     sQuestMgr.AreaExplored(this, questId);
  6329. }
  6330.  
  6331. void Player::Reset_Spells()
  6332. {
  6333.     PlayerCreateInfo* info = objmgr.GetPlayerCreateInfo(getRace(), getClass());
  6334.     ARCEMU_ASSERT(info != NULL);
  6335.  
  6336.     std::list<uint32> spelllist;
  6337.  
  6338.     for(SpellSet::iterator itr = mSpells.begin(); itr != mSpells.end(); itr++)
  6339.     {
  6340.         spelllist.push_back((*itr));
  6341.     }
  6342.  
  6343.     for(std::list<uint32>::iterator itr = spelllist.begin(); itr != spelllist.end(); ++itr)
  6344.     {
  6345.         removeSpell((*itr), false, false, 0);
  6346.     }
  6347.  
  6348.     for(std::set<uint32>::iterator sp = info->spell_list.begin(); sp != info->spell_list.end(); sp++)
  6349.     {
  6350.         if(*sp)
  6351.         {
  6352.             addSpell(*sp);
  6353.         }
  6354.     }
  6355.  
  6356.     // cebernic ResetAll ? don't forget DeletedSpells
  6357.     mDeletedSpells.clear();
  6358. }
  6359.  
  6360. void Player::ResetDualWield2H()
  6361. {
  6362.     DualWield2H = false;
  6363.  
  6364.     Item* mainhand = GetItemInterface()->GetInventoryItem(INVENTORY_SLOT_NOT_SET, EQUIPMENT_SLOT_MAINHAND);
  6365.     Item* offhand = GetItemInterface()->GetInventoryItem(INVENTORY_SLOT_NOT_SET, EQUIPMENT_SLOT_OFFHAND);
  6366.     if(offhand && (offhand->GetProto()->InventoryType == INVTYPE_2HWEAPON ||
  6367.                    (mainhand && mainhand->GetProto()->InventoryType == INVTYPE_2HWEAPON)))
  6368.     {
  6369.         // we need to de-equip this
  6370.         offhand = GetItemInterface()->SafeRemoveAndRetreiveItemFromSlot(INVENTORY_SLOT_NOT_SET, EQUIPMENT_SLOT_OFFHAND, false);
  6371.         SlotResult result = GetItemInterface()->FindFreeInventorySlot(offhand->GetProto());
  6372.         if(!result.Result)
  6373.         {
  6374.             // no free slots for this item, try to send it by mail
  6375.             offhand->RemoveFromWorld();
  6376.             offhand->SetOwner(NULL);
  6377.             offhand->SaveToDB(INVENTORY_SLOT_NOT_SET, 0, true, NULL);
  6378.             sMailSystem.SendAutomatedMessage(NORMAL, GetGUID(), GetGUID(), "Your offhand item", "", 0, 0, offhand->GetLowGUID(), MAIL_STATIONERY_GM);
  6379.             offhand->DeleteMe();
  6380.             offhand = NULL;
  6381.         }
  6382.         else if(!GetItemInterface()->SafeAddItem(offhand, result.ContainerSlot, result.Slot) && !GetItemInterface()->AddItemToFreeSlot(offhand))      // shouldn't happen either.
  6383.         {
  6384.             offhand->DeleteMe();
  6385.             offhand = NULL;
  6386.         }
  6387.     }
  6388. }
  6389.  
  6390. void Player::Reset_Talents()
  6391. {
  6392.     unsigned int numRows = dbcTalent.GetNumRows();
  6393.     uint8 playerClass = getClass();
  6394.     SpellEntry* spellInfo;
  6395.     SpellEntry* spellInfo2;
  6396.     uint32 i;
  6397.     uint8 j, k;
  6398.  
  6399.     // Loop through all talents.
  6400.     for(i = 0; i < numRows; ++i)
  6401.     {
  6402.         TalentEntry* tmpTalent = dbcTalent.LookupRowForced(i);
  6403.         if(tmpTalent == NULL)
  6404.         {
  6405.             // should not occur
  6406.             continue;
  6407.         }
  6408.         if(tmpTalent->TalentTree != TalentTreesPerClass[playerClass][0] &&
  6409.                 tmpTalent->TalentTree != TalentTreesPerClass[playerClass][1] &&
  6410.                 tmpTalent->TalentTree != TalentTreesPerClass[playerClass][2])
  6411.         {
  6412.             // Not a talent for this class
  6413.             continue;
  6414.         }
  6415.  
  6416.         // this is a normal talent (i hope)
  6417.         for(j = 0; j < 5; ++j)
  6418.         {
  6419.             if(tmpTalent->RankID[j] != 0)
  6420.             {
  6421.                 spellInfo = dbcSpell.LookupEntryForced(tmpTalent->RankID[j]);
  6422.                 if(spellInfo != NULL)
  6423.                 {
  6424.                     for(k = 0; k < 3; ++k)
  6425.                     {
  6426.                         if(spellInfo->Effect[k] == SPELL_EFFECT_LEARN_SPELL)
  6427.                         {
  6428.                             // removeSpell(spellInfo->EffectTriggerSpell[k], false, 0, 0);
  6429.                             // remove higher ranks of this spell too (like earth shield lvl 1 is talent and the rest is taught from trainer)
  6430.                             spellInfo2 = dbcSpell.LookupEntryForced(spellInfo->EffectTriggerSpell[k]);
  6431.                             if(spellInfo2 != NULL)
  6432.                             {
  6433.                                 removeSpellByHashName(spellInfo2->NameHash);
  6434.                             }
  6435.                         }
  6436.                     }
  6437.                     // remove them all in 1 shot
  6438.                     removeSpellByHashName(spellInfo->NameHash);
  6439.                 }
  6440.             }
  6441.             else
  6442.             {
  6443.                 break;
  6444.             }
  6445.         }
  6446.     }
  6447.     uint32 l = getLevel();
  6448.     if(l > 9)
  6449.     {
  6450.         SetCurrentTalentPoints(l - 9);
  6451.     }
  6452.     else
  6453.     {
  6454.         SetCurrentTalentPoints(0);
  6455.     }
  6456.  
  6457.     if(DualWield2H)
  6458.     {
  6459.         ResetDualWield2H();
  6460.     }
  6461.  
  6462.     m_specs[m_talentActiveSpec].talents.clear();
  6463.     smsg_TalentsInfo(false); //VLack: should we send this as Aspire? Yes...
  6464. }
  6465.  
  6466. void Player::Reset_AllTalents(){
  6467.     uint32 originalspec = m_talentActiveSpec;
  6468.     Reset_Talents();
  6469.    
  6470.     if( originalspec == SPEC_PRIMARY )
  6471.         ActivateSpec( SPEC_SECONDARY );
  6472.     else
  6473.         ActivateSpec( SPEC_PRIMARY );
  6474.  
  6475.     Reset_Talents();
  6476.     ActivateSpec( originalspec );
  6477. }
  6478.  
  6479. void Player::CalcResistance(uint32 type)
  6480. {
  6481.     int32 res;
  6482.     int32 pos;
  6483.     int32 neg;
  6484.     ARCEMU_ASSERT(type < 7);
  6485.     pos = (BaseResistance[type] * BaseResistanceModPctPos[type]) / 100;
  6486.     neg = (BaseResistance[type] * BaseResistanceModPctNeg[type]) / 100;
  6487.  
  6488.     pos += FlatResistanceModifierPos[type];
  6489.     neg += FlatResistanceModifierNeg[type];
  6490.     res = BaseResistance[type] + pos - neg;
  6491.     if(type == 0)res += m_uint32Values[UNIT_FIELD_STAT1] * 2; //fix armor from agi
  6492.     if(res < 0)res = 0;
  6493.     pos += (res * ResistanceModPctPos[type]) / 100;
  6494.     neg += (res * ResistanceModPctNeg[type]) / 100;
  6495.     res = pos - neg + BaseResistance[type];
  6496.     if(type == 0)res += m_uint32Values[UNIT_FIELD_STAT1] * 2; //fix armor from agi
  6497.  
  6498.     // Dynamic aura 285 application, removing bonus
  6499.     for(uint32 x = MAX_TOTAL_AURAS_START; x < MAX_TOTAL_AURAS_END; x++)
  6500.     {
  6501.         if(m_auras[x] != NULL)
  6502.         {
  6503.             if(m_auras[x]->HasModType(SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR))
  6504.                 m_auras[x]->SpellAuraModAttackPowerOfArmor(false);
  6505.         }
  6506.     }
  6507.  
  6508.     if(res < 0)
  6509.         res = 1;
  6510.  
  6511.     SetUInt32Value(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + type, pos);
  6512.     SetUInt32Value(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + type, -neg);
  6513.     SetResistance(type, res > 0 ? res : 0);
  6514.  
  6515.     std::list<Pet*> summons = GetSummons();
  6516.     for(std::list<Pet*>::iterator itr = summons.begin(); itr != summons.end(); ++itr)
  6517.     {
  6518.         (*itr)->CalcResistance(type);  //Re-calculate pet's too.
  6519.     }
  6520.  
  6521.     // Dynamic aura 285 application, adding bonus
  6522.     for(uint32 x = MAX_TOTAL_AURAS_START; x < MAX_TOTAL_AURAS_END; x++)
  6523.     {
  6524.         if(m_auras[x] != NULL)
  6525.         {
  6526.             if(m_auras[x]->HasModType(SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR))
  6527.                 m_auras[x]->SpellAuraModAttackPowerOfArmor(true);
  6528.         }
  6529.     }
  6530. }
  6531.  
  6532.  
  6533. void Player::UpdateNearbyGameObjects()
  6534. {
  6535.  
  6536.     for(Object::InRangeSet::iterator itr = m_objectsInRange.begin(); itr != m_objectsInRange.end(); ++itr)
  6537.     {
  6538.         Object* obj = (*itr);
  6539.         if(obj->IsGameObject())
  6540.         {
  6541.             bool activate_quest_object = false;
  6542.             GameObject* go = TO_GAMEOBJECT(obj);
  6543.             QuestLogEntry* qle = NULL;
  6544.             GameObjectInfo* info = go->GetInfo();
  6545.  
  6546.             bool deactivate = false;
  6547.             if(info &&
  6548.                     (info->goMap.size() || info->itemMap.size()))
  6549.             {
  6550.                 for(GameObjectGOMap::iterator GOitr = go->GetInfo()->goMap.begin();
  6551.                         GOitr != go->GetInfo()->goMap.end();
  6552.                         ++GOitr)
  6553.                 {
  6554.                     if((qle = GetQuestLogForEntry(GOitr->first->id)) != 0)
  6555.                     {
  6556.                         for(uint32 i = 0; i < qle->GetQuest()->count_required_mob; ++i)
  6557.                         {
  6558.                             if(qle->GetQuest()->required_mob[i] == static_cast<int32>(go->GetEntry()) &&
  6559.                                     qle->GetMobCount(i) < qle->GetQuest()->required_mobcount[i])
  6560.                             {
  6561.                                 activate_quest_object = true;
  6562.                                 break;
  6563.                             }
  6564.                         }
  6565.                         if(activate_quest_object)
  6566.                             break;
  6567.                     }
  6568.                 }
  6569.  
  6570.                 if(!activate_quest_object)
  6571.                 {
  6572.                     for(GameObjectItemMap::iterator GOitr = go->GetInfo()->itemMap.begin();
  6573.                             GOitr != go->GetInfo()->itemMap.end();
  6574.                             ++GOitr)
  6575.                     {
  6576.                         for(std::map<uint32, uint32>::iterator it2 = GOitr->second.begin();
  6577.                                 it2 != GOitr->second.end();
  6578.                                 ++it2)
  6579.                         {
  6580.                             if(GetItemInterface()->GetItemCount(it2->first) < it2->second)
  6581.                             {
  6582.                                 activate_quest_object = true;
  6583.                                 break;
  6584.                             }
  6585.                         }
  6586.                         if(activate_quest_object)
  6587.                             break;
  6588.                     }
  6589.                 }
  6590.  
  6591.                 if(!activate_quest_object)
  6592.                 {
  6593.                     deactivate = true;
  6594.                 }
  6595.             }
  6596.             bool bPassed = !deactivate;
  6597.             if(go->isQuestGiver())
  6598.             {
  6599.                 if(go->HasQuests() && go->NumOfQuests() > 0)
  6600.                 {
  6601.                     std::list<QuestRelation*>::iterator itr2 = go->QuestsBegin();
  6602.                     for(; itr2 != go->QuestsEnd(); ++itr2)
  6603.                     {
  6604.                         QuestRelation* qr = (*itr2);
  6605.  
  6606.                         uint32 status = sQuestMgr.CalcQuestStatus(NULL, this, qr->qst, qr->type, false);
  6607.                         if(status == QMGR_QUEST_CHAT
  6608.                                 || (qr->type & QUESTGIVER_QUEST_START && (status == QMGR_QUEST_AVAILABLE || status == QMGR_QUEST_REPEATABLE))
  6609.                                 || (qr->type & QUESTGIVER_QUEST_END && status == QMGR_QUEST_FINISHED)
  6610.                           )
  6611.                         {
  6612.                             // Activate gameobject
  6613.                             EventActivateGameObject(go);
  6614.                             bPassed = true;
  6615.                             break;
  6616.                         }
  6617.                     }
  6618.                 }
  6619.             }
  6620.             if(!bPassed)
  6621.                 EventDeActivateGameObject(TO_GAMEOBJECT(*itr));
  6622.         }
  6623.     }
  6624. }
  6625.  
  6626.  
  6627. void Player::EventTaxiInterpolate()
  6628. {
  6629.     if(!m_CurrentTaxiPath || m_mapMgr == NULL) return;
  6630.  
  6631.     float x = 0.0f;
  6632.     float y = 0.0f;
  6633.     float z = 0.0f;
  6634.  
  6635.     uint32 ntime = getMSTime();
  6636.  
  6637.     if(ntime > m_taxi_ride_time)
  6638.         m_CurrentTaxiPath->SetPosForTime(x, y, z, ntime - m_taxi_ride_time, &lastNode, m_mapId);
  6639.     /*else
  6640.         m_CurrentTaxiPath->SetPosForTime(x, y, z, m_taxi_ride_time - ntime, &lastNode);*/
  6641.  
  6642.     if(x < _minX || x > _maxX || y < _minY || y > _maxX)
  6643.         return;
  6644.  
  6645.     SetPosition(x, y, z, 0);
  6646. }
  6647.  
  6648. void Player::TaxiStart(TaxiPath* path, uint32 modelid, uint32 start_node)
  6649. {
  6650.     int32 mapchangeid = -1;
  6651.     float mapchangex = 0.0f, mapchangey = 0.0f, mapchangez = 0.0f;
  6652.     uint32 cn = m_taxiMapChangeNode;
  6653.  
  6654.     m_taxiMapChangeNode = 0;
  6655.  
  6656.     Dismount();
  6657.  
  6658.     if( currentvehicle != NULL )
  6659.         currentvehicle->EjectPassenger( this );
  6660.  
  6661.     //also remove morph spells
  6662.     if(GetDisplayId() != GetNativeDisplayId())
  6663.     {
  6664.         RemoveAllAuraType(SPELL_AURA_TRANSFORM);
  6665.         RemoveAllAuraType(SPELL_AURA_MOD_SHAPESHIFT);
  6666.     }
  6667.  
  6668.     DismissActivePets();
  6669.  
  6670.     SetMount(modelid);
  6671.     SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNTED_TAXI);
  6672.     SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOCK_PLAYER);
  6673.  
  6674.     SetTaxiPath(path);
  6675.     SetTaxiPos();
  6676.     SetTaxiState(true);
  6677.     m_taxi_ride_time = getMSTime();
  6678.  
  6679.     //uint32 traveltime = uint32(path->getLength() * TAXI_TRAVEL_SPEED); // 36.7407
  6680.     float traveldist = 0;
  6681.  
  6682.     float lastx = 0, lasty = 0, lastz = 0;
  6683.     TaxiPathNode* firstNode = path->GetPathNode(start_node);
  6684.     uint32 add_time = 0;
  6685.  
  6686.     // temporary workaround for taximodes with changing map
  6687.     if(path->GetID() == 766 || path->GetID() == 767 || path->GetID() == 771 || path->GetID() == 772)
  6688.     {
  6689.         JumpToEndTaxiNode(path);
  6690.         return;
  6691.     }
  6692.  
  6693.     if(start_node)
  6694.     {
  6695.         TaxiPathNode* pn = path->GetPathNode(0);
  6696.         float dist = 0;
  6697.         lastx = pn->x;
  6698.         lasty = pn->y;
  6699.         lastz = pn->z;
  6700.         for(uint32 i = 1; i <= start_node; ++i)
  6701.         {
  6702.             pn = path->GetPathNode(i);
  6703.             if(!pn)
  6704.             {
  6705.                 JumpToEndTaxiNode(path);
  6706.                 return;
  6707.             }
  6708.  
  6709.             dist += CalcDistance(lastx, lasty, lastz, pn->x, pn->y, pn->z);
  6710.             lastx = pn->x;
  6711.             lasty = pn->y;
  6712.             lastz = pn->z;
  6713.         }
  6714.         add_time = uint32(dist * TAXI_TRAVEL_SPEED);
  6715.         lastx = lasty = lastz = 0;
  6716.     }
  6717.     size_t endn = path->GetNodeCount();
  6718.     if(m_taxiPaths.size())
  6719.         endn -= 2;
  6720.  
  6721.     for(uint32 i = start_node; i < endn; ++i)
  6722.     {
  6723.         TaxiPathNode* pn = path->GetPathNode(i);
  6724.  
  6725.         // temporary workaround for taximodes with changing map
  6726.         if(!pn || path->GetID() == 766 || path->GetID() == 767 || path->GetID() == 771 || path->GetID() == 772)
  6727.         {
  6728.             JumpToEndTaxiNode(path);
  6729.             return;
  6730.         }
  6731.  
  6732.         if(pn->mapid != m_mapId)
  6733.         {
  6734.             endn = (i - 1);
  6735.             m_taxiMapChangeNode = i;
  6736.  
  6737.             mapchangeid = (int32)pn->mapid;
  6738.             mapchangex = pn->x;
  6739.             mapchangey = pn->y;
  6740.             mapchangez = pn->z;
  6741.             break;
  6742.         }
  6743.  
  6744.         if(!lastx || !lasty || !lastz)
  6745.         {
  6746.             lastx = pn->x;
  6747.             lasty = pn->y;
  6748.             lastz = pn->z;
  6749.         }
  6750.         else
  6751.         {
  6752.             float dist = CalcDistance(lastx, lasty, lastz,
  6753.                                       pn->x, pn->y, pn->z);
  6754.             traveldist += dist;
  6755.             lastx = pn->x;
  6756.             lasty = pn->y;
  6757.             lastz = pn->z;
  6758.         }
  6759.     }
  6760.  
  6761.     uint32 traveltime = uint32(traveldist * TAXI_TRAVEL_SPEED);
  6762.  
  6763.     if(start_node > endn || (endn - start_node) > 200)
  6764.         return;
  6765.  
  6766.     WorldPacket data(SMSG_MONSTER_MOVE, 38 + ((endn - start_node) * 12));
  6767.     data << GetNewGUID();
  6768.     data << uint8(0); //VLack: it seems we have a 1 byte stuff after the new GUID
  6769.     data << firstNode->x << firstNode->y << firstNode->z;
  6770.     data << m_taxi_ride_time;
  6771.     data << uint8(0);
  6772. //  data << uint32( 0x00000300 );
  6773.     data << uint32(0x00003000);
  6774.     data << uint32(traveltime);
  6775.  
  6776.     if(!cn)
  6777.         m_taxi_ride_time -= add_time;
  6778.  
  6779.     data << uint32(endn - start_node);
  6780. //  uint32 timer = 0, nodecount = 0;
  6781. //  TaxiPathNode *lastnode = NULL;
  6782.  
  6783.     for(uint32 i = start_node; i < endn; i++)
  6784.     {
  6785.         TaxiPathNode* pn = path->GetPathNode(i);
  6786.         if(!pn)
  6787.         {
  6788.             JumpToEndTaxiNode(path);
  6789.             return;
  6790.         }
  6791.  
  6792.         data << pn->x << pn->y << pn->z;
  6793.     }
  6794.  
  6795.     SendMessageToSet(&data, true);
  6796.  
  6797.     sEventMgr.AddEvent(this, &Player::EventTaxiInterpolate,
  6798.                        EVENT_PLAYER_TAXI_INTERPOLATE, 900, 0, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
  6799.  
  6800.     if(mapchangeid < 0)
  6801.     {
  6802.         TaxiPathNode* pn = path->GetPathNode((uint32)path->GetNodeCount() - 1);
  6803.         sEventMgr.AddEvent(this, &Player::EventDismount, path->GetPrice(),
  6804.                            pn->x, pn->y, pn->z, EVENT_PLAYER_TAXI_DISMOUNT, traveltime, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
  6805.     }
  6806.     else
  6807.     {
  6808.         sEventMgr.AddEvent(this, &Player::EventTeleportTaxi, (uint32)mapchangeid, mapchangex, mapchangey, mapchangez, EVENT_PLAYER_TELEPORT, traveltime, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
  6809.     }
  6810. }
  6811.  
  6812. void Player::JumpToEndTaxiNode(TaxiPath* path)
  6813. {
  6814.     // this should *always* be safe in case it cant build your position on the path!
  6815.     TaxiPathNode* pathnode = path->GetPathNode((uint32)path->GetNodeCount() - 1);
  6816.     if(!pathnode) return;
  6817.  
  6818.     ModGold(-(int32)path->GetPrice());
  6819.  
  6820.     SetTaxiState(false);
  6821.     SetTaxiPath(NULL);
  6822.     UnSetTaxiPos();
  6823.     m_taxi_ride_time = 0;
  6824.  
  6825.     SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID , 0);
  6826.     RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNTED_TAXI);
  6827.     RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOCK_PLAYER);
  6828.  
  6829.     SetSpeeds(RUN, m_runSpeed);
  6830.  
  6831.     SafeTeleport(pathnode->mapid, 0, LocationVector(pathnode->x, pathnode->y, pathnode->z));
  6832.  
  6833.     // Start next path if any remaining
  6834.     if(m_taxiPaths.size())
  6835.     {
  6836.         TaxiPath* p = *m_taxiPaths.begin();
  6837.         m_taxiPaths.erase(m_taxiPaths.begin());
  6838.         TaxiStart(p, taxi_model_id, 0);
  6839.     }
  6840. }
  6841.  
  6842. void Player::RemoveSpellsFromLine(uint32 skill_line)
  6843. {
  6844.     uint32 cnt = dbcSkillLineSpell.GetNumRows();
  6845.     for(uint32 i = 0; i < cnt; i++)
  6846.     {
  6847.         skilllinespell* sp = dbcSkillLineSpell.LookupRowForced(i);
  6848.         if(sp)
  6849.         {
  6850.             if(sp->skilline == skill_line)
  6851.             {
  6852.                 // Check ourselves for this spell, and remove it..
  6853.                 if(!removeSpell(sp->spell, 0, 0, 0))
  6854.                     // if we didn't unlearned spell check deleted spells
  6855.                     removeDeletedSpell(sp->spell);
  6856.             }
  6857.         }
  6858.     }
  6859. }
  6860.  
  6861. void Player::CalcStat(uint32 type)
  6862. {
  6863.     int32 res;
  6864.     ARCEMU_ASSERT(type < 5);
  6865.  
  6866.     int32 pos = (int32)((int32)BaseStats[type] * (int32)StatModPctPos[type]) / 100 + (int32)FlatStatModPos[type];
  6867.     int32 neg = (int32)((int32)BaseStats[type] * (int32)StatModPctNeg[type]) / 100 + (int32)FlatStatModNeg[type];
  6868.     res = pos + (int32)BaseStats[type] - neg;
  6869.     if(res <= 0)
  6870.         res = 1;
  6871.     pos += (res * (int32) TO< Player* >(this)->TotalStatModPctPos[type]) / 100;
  6872.     neg += (res * (int32) TO< Player* >(this)->TotalStatModPctNeg[type]) / 100;
  6873.     res = pos + BaseStats[type] - neg;
  6874.     if(res <= 0)
  6875.         res = 1;
  6876.  
  6877.     SetUInt32Value(UNIT_FIELD_POSSTAT0 + type, pos);
  6878.  
  6879.     if( neg < 0 )
  6880.         SetUInt32Value(UNIT_FIELD_NEGSTAT0 + type, -neg);
  6881.     else
  6882.         SetUInt32Value(UNIT_FIELD_NEGSTAT0 + type, neg);
  6883.  
  6884.     SetStat(type, res > 0 ? res : 0);
  6885.     if(type == STAT_AGILITY)
  6886.         CalcResistance(0);
  6887.  
  6888.     if(type == STAT_STAMINA || type == STAT_INTELLECT)
  6889.     {
  6890.         std::list<Pet*> summons = GetSummons();
  6891.         for(std::list<Pet*>::iterator itr = summons.begin(); itr != summons.end(); ++itr)
  6892.         {
  6893.             (*itr)->CalcStat(type);  //Re-calculate pet's too
  6894.         }
  6895.     }
  6896. }
  6897.  
  6898. void Player::RegenerateMana(bool is_interrupted)
  6899. {
  6900.     uint32 cur = GetPower(POWER_TYPE_MANA);
  6901.     uint32 mm = GetMaxPower(POWER_TYPE_MANA);
  6902.     if(cur >= mm)
  6903.         return;
  6904.     float wrate = sWorld.getRate(RATE_POWER1); // config file regen rate
  6905.     float amt = (is_interrupted) ? GetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER) : GetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER);
  6906.     amt *= wrate * 2.0f;
  6907.  
  6908.     if((amt <= 1.0) && (amt > 0)) //this fixes regen like 0.98
  6909.     {
  6910.         if(is_interrupted)
  6911.             return;
  6912.         ++cur;
  6913.     }
  6914.     else
  6915.         cur += float2int32(amt);
  6916. //  Unit::SetPower() will call Object::SetUInt32Value(), which will (for players) call SendPowerUpdate(),
  6917. //  which can be slightly out-of-sync with client regeneration [with latency] (and wastes packets since client can handle this on its own)
  6918.     if(wrate != 1.0) // our config has custom regen rate, so send new amount to player's client
  6919.     {
  6920.         SetPower(POWER_TYPE_MANA, cur);
  6921.     }
  6922.     else // let player's own client handle normal regen rates.
  6923.     {
  6924.         SetPower(POWER_TYPE_MANA, ((cur >= mm) ? mm : cur));
  6925.         SendPowerUpdate(false); // send update to other in-range players
  6926.     }
  6927. }
  6928.  
  6929. void Player::RegenerateHealth(bool inCombat)
  6930. {
  6931.     uint32 cur = GetHealth();
  6932.     uint32 mh = GetMaxHealth();
  6933.  
  6934.     if(cur == 0) return;   // cebernic: bugfix dying but regenerated?
  6935.  
  6936.     if(cur >= mh)
  6937.         return;
  6938.  
  6939.     gtFloat* HPRegenBase = dbcHPRegenBase.LookupEntry(getLevel() - 1 + (getClass() - 1) * 100);
  6940.     gtFloat* HPRegen =  dbcHPRegen.LookupEntry(getLevel() - 1 + (getClass() - 1) * 100);
  6941.  
  6942.     uint32 basespirit = m_uint32Values[ UNIT_FIELD_SPIRIT ];
  6943.     uint32 extraspirit = 0;
  6944.  
  6945.     if(basespirit > 50)
  6946.     {
  6947.         extraspirit = basespirit - 50;
  6948.         basespirit = 50;
  6949.     }
  6950.  
  6951.     float amt = basespirit * HPRegen->val + extraspirit * HPRegenBase->val;
  6952.  
  6953.     if(PctRegenModifier)
  6954.         amt += (amt * PctRegenModifier) / 100;
  6955.  
  6956.     amt *= sWorld.getRate(RATE_HEALTH);//Apply conf file rate
  6957.     //Near values from official
  6958.     // wowwiki: Health Regeneration is increased by 33% while sitting.
  6959.     if(m_isResting)
  6960.         amt = amt * 1.33f;
  6961.  
  6962.     if(inCombat)
  6963.         amt *= PctIgnoreRegenModifier;
  6964.  
  6965.     if(amt != 0)
  6966.     {
  6967.         if(amt > 0)
  6968.         {
  6969.             if(amt <= 1.0f)//this fixes regen like 0.98
  6970.                 cur++;
  6971.             else
  6972.                 cur += float2int32(amt);
  6973.             SetHealth((cur >= mh) ? mh : cur);
  6974.         }
  6975.         else
  6976.             DealDamage(this, float2int32(-amt), 0, 0, 0);
  6977.     }
  6978. }
  6979.  
  6980. void Player::LooseRage(int32 decayValue)
  6981. {
  6982.     //Rage is lost at a rate of 3 rage every 3 seconds.
  6983.     //The Anger Management talent changes this to 2 rage every 3 seconds.
  6984.     uint32 cur = GetPower(POWER_TYPE_RAGE);
  6985.     uint32 newrage = ((int)cur <= decayValue) ? 0 : cur - decayValue;
  6986.     if(newrage > 1000)
  6987.         newrage = 1000;
  6988. // Object::SetUInt32Value() will (for players) call SendPowerUpdate(),
  6989. // which can be slightly out-of-sync with client rage loss
  6990. // config file rage rate is rage gained, not lost, so we don't need that here
  6991. //  SetUInt32Value(UNIT_FIELD_POWER2,newrage);
  6992.     SetPower(POWER_TYPE_RAGE, newrage);
  6993.     SendPowerUpdate(false); // send update to other in-range players
  6994. }
  6995.  
  6996. void Player::RegenerateEnergy()
  6997. {
  6998.     uint32 cur = GetPower(POWER_TYPE_ENERGY);
  6999.     uint32 mh = GetMaxPower(POWER_TYPE_ENERGY);
  7000.     if(cur >= mh)
  7001.         return;
  7002.  
  7003.     float wrate = sWorld.getRate(RATE_POWER4);
  7004.     float amt = PctPowerRegenModifier[POWER_TYPE_ENERGY];
  7005.     amt *= wrate * 20.0f;
  7006.  
  7007.     cur += float2int32(amt);
  7008. //  Object::SetUInt32Value() will (for players) call SendPowerUpdate(),
  7009. //  which can be slightly out-of-sync with client regeneration [latency] (and wastes packets since client can handle this on its own)
  7010.     if(wrate != 1.0f) // our config has custom regen rate, so send new amount to player's client
  7011.     {
  7012.         SetPower(GetPowerType(), (cur >= mh) ? mh : cur);
  7013.     }
  7014.     else // let player's own client handle normal regen rates.
  7015.     {
  7016.         m_uint32Values[UNIT_FIELD_POWER4] = (cur >= mh) ? mh : cur;
  7017.         SendPowerUpdate(false); // send update to other in-range players
  7018.     }
  7019. }
  7020.  
  7021. uint32 Player::GeneratePetNumber()
  7022. {
  7023.     uint32 val = m_PetNumberMax + 1;
  7024.     for(uint32 i = 1; i < m_PetNumberMax; i++)
  7025.         if(m_Pets.find(i) == m_Pets.end())
  7026.             return i;                      // found a free one
  7027.  
  7028.     return val;
  7029. }
  7030.  
  7031. void Player::RemovePlayerPet(uint32 pet_number)
  7032. {
  7033.     std::map<uint32, PlayerPet*>::iterator itr = m_Pets.find(pet_number);
  7034.     if(itr != m_Pets.end())
  7035.     {
  7036.         delete itr->second;
  7037.         m_Pets.erase(itr);
  7038.     }
  7039.     CharacterDatabase.Execute("DELETE FROM playerpetspells WHERE ownerguid=%u AND petnumber=%u", GetLowGUID(), pet_number);
  7040. }
  7041.  
  7042. void Player::_Relocate(uint32 mapid, const LocationVector & v, bool sendpending, bool force_new_world, uint32 instance_id)
  7043. {
  7044.     //this func must only be called when switching between maps!
  7045.     WorldPacket data(41);
  7046.     if(sendpending && mapid != m_mapId && force_new_world)
  7047.     {
  7048.         data.SetOpcode(SMSG_TRANSFER_PENDING);
  7049.  
  7050.         data << mapid;
  7051.  
  7052.         m_session->SendPacket(&data);
  7053.     }
  7054.  
  7055.     //Dismount before teleport and before being removed from world,
  7056.     //otherwise we may spawn the active pet while not being in world.
  7057.     Dismount();
  7058.  
  7059.     if(m_mapId != mapid || force_new_world)
  7060.     {
  7061.         uint32 status = sInstanceMgr.PreTeleport(mapid, this, instance_id);
  7062.         if(status != INSTANCE_OK)
  7063.         {
  7064.             data.Initialize(SMSG_TRANSFER_ABORTED);
  7065.  
  7066.             data << uint32(mapid);
  7067.             data << uint32(status);
  7068.  
  7069.             m_session->SendPacket(&data);
  7070.  
  7071.             return;
  7072.         }
  7073.  
  7074.         if(instance_id)
  7075.             m_instanceId = instance_id;
  7076.  
  7077.         if(IsInWorld())
  7078.         {
  7079.             RemoveFromWorld();
  7080.         }
  7081.  
  7082.         data.Initialize(SMSG_NEW_WORLD);
  7083.  
  7084.         data << uint32(mapid);
  7085.         data << v;
  7086.         data << float(v.o);
  7087.  
  7088.         m_session->SendPacket(&data);
  7089.  
  7090.         SetMapId(mapid);
  7091.  
  7092.     }
  7093.     else
  7094.     {
  7095.         // via teleport ack msg
  7096.         SendTeleportAckMsg(v);
  7097.     }
  7098.     SetPlayerStatus(TRANSFER_PENDING);
  7099.     m_sentTeleportPosition = v;
  7100.     SetPosition(v);
  7101.     SpeedCheatReset();
  7102.  
  7103.     z_axisposition = 0.0f;
  7104. }
  7105.  
  7106.  
  7107. // Player::AddItemsToWorld
  7108. // Adds all items to world, applies any modifiers for them.
  7109.  
  7110. void Player::AddItemsToWorld()
  7111. {
  7112.     Item* pItem;
  7113.     for(uint8 i = 0; i < CURRENCYTOKEN_SLOT_END; i++)
  7114.     {
  7115.         pItem = GetItemInterface()->GetInventoryItem(i);
  7116.         if(pItem != NULL)
  7117.         {
  7118.             pItem->PushToWorld(m_mapMgr);
  7119.  
  7120.             if(i < INVENTORY_SLOT_BAG_END)    // only equipment slots get mods.
  7121.             {
  7122.                 _ApplyItemMods(pItem, i, true, false, true);
  7123.             }
  7124.  
  7125.             if(i >= CURRENCYTOKEN_SLOT_START && i < CURRENCYTOKEN_SLOT_END)
  7126.             {
  7127.                 UpdateKnownCurrencies(pItem->GetEntry(), true);
  7128.             }
  7129.  
  7130.             if(pItem->IsContainer() && GetItemInterface()->IsBagSlot(i))
  7131.             {
  7132.                 for(uint32 e = 0; e < pItem->GetProto()->ContainerSlots; e++)
  7133.                 {
  7134.                     Item* item = (TO< Container* >(pItem))->GetItem(static_cast<int16>(e));
  7135.                     if(item)
  7136.                     {
  7137.                         item->PushToWorld(m_mapMgr);
  7138.                     }
  7139.                 }
  7140.             }
  7141.         }
  7142.     }
  7143.  
  7144.     UpdateStats();
  7145. }
  7146.  
  7147. // Player::RemoveItemsFromWorld
  7148. // Removes all items from world, reverses any modifiers.
  7149.  
  7150. void Player::RemoveItemsFromWorld()
  7151. {
  7152.     Item* pItem;
  7153.     for(uint32 i = 0; i < CURRENCYTOKEN_SLOT_END; i++)
  7154.     {
  7155.         pItem = m_ItemInterface->GetInventoryItem((int8)i);
  7156.         if(pItem)
  7157.         {
  7158.             if(pItem->IsInWorld())
  7159.             {
  7160.                 if(i < INVENTORY_SLOT_BAG_END)    // only equipment+bags slots get mods.
  7161.                 {
  7162.                     _ApplyItemMods(pItem, static_cast<int16>(i), false, false, true);
  7163.                 }
  7164.                 pItem->RemoveFromWorld();
  7165.             }
  7166.  
  7167.             if(pItem->IsContainer() && GetItemInterface()->IsBagSlot(static_cast<int16>(i)))
  7168.             {
  7169.                 for(uint32 e = 0; e < pItem->GetProto()->ContainerSlots; e++)
  7170.                 {
  7171.                     Item* item = (TO< Container* >(pItem))->GetItem(static_cast<int16>(e));
  7172.                     if(item && item->IsInWorld())
  7173.                     {
  7174.                         item->RemoveFromWorld();
  7175.                     }
  7176.                 }
  7177.             }
  7178.         }
  7179.     }
  7180.  
  7181.     UpdateStats();
  7182. }
  7183.  
  7184. uint32 Player::BuildCreateUpdateBlockForPlayer(ByteBuffer* data, Player* target)
  7185. {
  7186.     int count = 0;
  7187.     if(target == this)
  7188.     {
  7189.         // we need to send create objects for all items.
  7190.         count += GetItemInterface()->m_CreateForPlayer(data);
  7191.     }
  7192.     count += Unit::BuildCreateUpdateBlockForPlayer(data, target);
  7193.     return count;
  7194. }
  7195.  
  7196. void Player::Kick(uint32 delay /* = 0 */)
  7197. {
  7198.     if(!delay)
  7199.     {
  7200.         m_KickDelay = 0;
  7201.         _Kick();
  7202.     }
  7203.     else
  7204.     {
  7205.         m_KickDelay = delay;
  7206.         sEventMgr.AddEvent(this, &Player::_Kick, EVENT_PLAYER_KICK, 1000, 0, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
  7207.     }
  7208. }
  7209.  
  7210. void Player::_Kick()
  7211. {
  7212.     if(!m_KickDelay)
  7213.     {
  7214.         sEventMgr.RemoveEvents(this, EVENT_PLAYER_KICK);
  7215.         // remove now
  7216.         GetSession()->LogoutPlayer(true);
  7217.     }
  7218.     else
  7219.     {
  7220.         if(m_KickDelay < 1500)
  7221.         {
  7222.             m_KickDelay = 0;
  7223.         }
  7224.         else
  7225.         {
  7226.             m_KickDelay -= 1000;
  7227.         }
  7228.         sChatHandler.BlueSystemMessageToPlr(this, "You will be removed from the server in %u seconds.", (uint32)(m_KickDelay / 1000));
  7229.     }
  7230. }
  7231.  
  7232. void Player::ClearCooldownForSpell(uint32 spell_id)
  7233. {
  7234.     WorldPacket data(12);
  7235.     data.SetOpcode(SMSG_CLEAR_COOLDOWN);
  7236.     data << spell_id << GetGUID();
  7237.     GetSession()->SendPacket(&data);
  7238.  
  7239.     // remove cooldown data from Server side lists
  7240.     uint32 i;
  7241.     PlayerCooldownMap::iterator itr, itr2;
  7242.     SpellEntry* spe = dbcSpell.LookupEntryForced(spell_id);
  7243.     if(!spe) return;
  7244.  
  7245.     for(i = 0; i < NUM_COOLDOWN_TYPES; ++i)
  7246.     {
  7247.         for(itr = m_cooldownMap[i].begin(); itr != m_cooldownMap[i].end();)
  7248.         {
  7249.             itr2 = itr++;
  7250.             if((i == COOLDOWN_TYPE_CATEGORY && itr2->first == spe->Category) ||
  7251.                     (i == COOLDOWN_TYPE_SPELL && itr2->first == spe->Id))
  7252.             {
  7253.                 m_cooldownMap[i].erase(itr2);
  7254.             }
  7255.         }
  7256.     }
  7257. }
  7258.  
  7259. void Player::ClearCooldownsOnLine(uint32 skill_line, uint32 called_from)
  7260. {
  7261.     // found an easier way.. loop spells, check skill line
  7262.     SpellSet::const_iterator itr = mSpells.begin();
  7263.     skilllinespell* sk;
  7264.     for(; itr != mSpells.end(); ++itr)
  7265.     {
  7266.         if((*itr) == called_from)      // skip calling spell.. otherwise spammies! :D
  7267.             continue;
  7268.  
  7269.         sk = objmgr.GetSpellSkill((*itr));
  7270.         if(sk && sk->skilline == skill_line)
  7271.             ClearCooldownForSpell((*itr));
  7272.     }
  7273. }
  7274.  
  7275. void Player::ResetAllCooldowns()
  7276. {
  7277.     uint32 guid = (uint32)GetSelection();
  7278.  
  7279.     switch(getClass())
  7280.     {
  7281.         case WARRIOR:
  7282.             {
  7283.                 ClearCooldownsOnLine(26, guid);
  7284.                 ClearCooldownsOnLine(256, guid);
  7285.                 ClearCooldownsOnLine(257 , guid);
  7286.             }
  7287.             break;
  7288.         case PALADIN:
  7289.             {
  7290.                 ClearCooldownsOnLine(594, guid);
  7291.                 ClearCooldownsOnLine(267, guid);
  7292.                 ClearCooldownsOnLine(184, guid);
  7293.             }
  7294.             break;
  7295.         case HUNTER:
  7296.             {
  7297.                 ClearCooldownsOnLine(50, guid);
  7298.                 ClearCooldownsOnLine(51, guid);
  7299.                 ClearCooldownsOnLine(163, guid);
  7300.             }
  7301.             break;
  7302.         case ROGUE:
  7303.             {
  7304.                 ClearCooldownsOnLine(253, guid);
  7305.                 ClearCooldownsOnLine(38, guid);
  7306.                 ClearCooldownsOnLine(39, guid);
  7307.             }
  7308.             break;
  7309.         case PRIEST:
  7310.             {
  7311.                 ClearCooldownsOnLine(56, guid);
  7312.                 ClearCooldownsOnLine(78, guid);
  7313.                 ClearCooldownsOnLine(613, guid);
  7314.             }
  7315.             break;
  7316.  
  7317.         case DEATHKNIGHT:
  7318.             {
  7319.                 ClearCooldownsOnLine(770, guid);
  7320.                 ClearCooldownsOnLine(771, guid);
  7321.                 ClearCooldownsOnLine(772, guid);
  7322.             }
  7323.             break;
  7324.  
  7325.         case SHAMAN:
  7326.             {
  7327.                 ClearCooldownsOnLine(373, guid);
  7328.                 ClearCooldownsOnLine(374, guid);
  7329.                 ClearCooldownsOnLine(375, guid);
  7330.             }
  7331.             break;
  7332.         case MAGE:
  7333.             {
  7334.                 ClearCooldownsOnLine(6, guid);
  7335.                 ClearCooldownsOnLine(8, guid);
  7336.                 ClearCooldownsOnLine(237, guid);
  7337.             }
  7338.             break;
  7339.         case WARLOCK:
  7340.             {
  7341.                 ClearCooldownsOnLine(355, guid);
  7342.                 ClearCooldownsOnLine(354, guid);
  7343.                 ClearCooldownsOnLine(593, guid);
  7344.             }
  7345.             break;
  7346.         case DRUID:
  7347.             {
  7348.                 ClearCooldownsOnLine(573, guid);
  7349.                 ClearCooldownsOnLine(574, guid);
  7350.                 ClearCooldownsOnLine(134, guid);
  7351.             }
  7352.             break;
  7353.  
  7354.         default:
  7355.             return;
  7356.             break;
  7357.     }
  7358. }
  7359.  
  7360. void Player::PushUpdateData(ByteBuffer* data, uint32 updatecount)
  7361. {
  7362.     // imagine the bytebuffer getting appended from 2 threads at once! :D
  7363.     _bufferS.Acquire();
  7364.  
  7365.     // unfortunately there is no guarantee that all data will be compressed at a ratio
  7366.     // that will fit into 2^16 bytes ( stupid client limitation on server packets )
  7367.     // so if we get more than 63KB of update data, force an update and then append it
  7368.     // to the clean buffer.
  7369.     if((data->size() + bUpdateBuffer.size()) >= 63000)
  7370.         ProcessPendingUpdates();
  7371.  
  7372.     mUpdateCount += updatecount;
  7373.     bUpdateBuffer.append(*data);
  7374.  
  7375.     // add to process queue
  7376.     if(m_mapMgr && !bProcessPending)
  7377.     {
  7378.         bProcessPending = true;
  7379.         m_mapMgr->PushToProcessed(this);
  7380.     }
  7381.  
  7382.     _bufferS.Release();
  7383. }
  7384.  
  7385. void Player::PushOutOfRange(const WoWGuid & guid)
  7386. {
  7387.     _bufferS.Acquire();
  7388.     mOutOfRangeIds << guid;
  7389.     ++mOutOfRangeIdCount;
  7390.  
  7391.     // add to process queue
  7392.     if(m_mapMgr && !bProcessPending)
  7393.     {
  7394.         bProcessPending = true;
  7395.         m_mapMgr->PushToProcessed(this);
  7396.     }
  7397.     _bufferS.Release();
  7398. }
  7399.  
  7400. void Player::PushCreationData(ByteBuffer* data, uint32 updatecount)
  7401. {
  7402.     // imagine the bytebuffer getting appended from 2 threads at once! :D
  7403.     _bufferS.Acquire();
  7404.  
  7405.     // unfortunately there is no guarantee that all data will be compressed at a ratio
  7406.     // that will fit into 2^16 bytes ( stupid client limitation on server packets )
  7407.     // so if we get more than 63KB of update data, force an update and then append it
  7408.     // to the clean buffer.
  7409.     if((data->size() + bCreationBuffer.size() + mOutOfRangeIds.size()) >= 63000)
  7410.         ProcessPendingUpdates();
  7411.  
  7412.     mCreationCount += updatecount;
  7413.     bCreationBuffer.append(*data);
  7414.  
  7415.     // add to process queue
  7416.     if(m_mapMgr && !bProcessPending)
  7417.     {
  7418.         bProcessPending = true;
  7419.         m_mapMgr->PushToProcessed(this);
  7420.     }
  7421.  
  7422.     _bufferS.Release();
  7423.  
  7424. }
  7425.  
  7426. void Player::ProcessPendingUpdates()
  7427. {
  7428.     _bufferS.Acquire();
  7429.     if(!bUpdateBuffer.size() && !mOutOfRangeIds.size() && !bCreationBuffer.size())
  7430.     {
  7431.         _bufferS.Release();
  7432.         return;
  7433.     }
  7434.  
  7435.     size_t bBuffer_size = (bCreationBuffer.size() > bUpdateBuffer.size() ? bCreationBuffer.size() : bUpdateBuffer.size()) + 10 + (mOutOfRangeIds.size() * 9);
  7436.     uint8* update_buffer = new uint8[bBuffer_size];
  7437.     size_t c = 0;
  7438.  
  7439.     //build out of range updates if creation updates are queued
  7440.     if(bCreationBuffer.size() || mOutOfRangeIdCount)
  7441.     {
  7442.         *(uint32*)&update_buffer[c] = ((mOutOfRangeIds.size() > 0) ? (mCreationCount + 1) : mCreationCount);
  7443.         c += 4;
  7444.  
  7445.         // append any out of range updates
  7446.         if(mOutOfRangeIdCount)
  7447.         {
  7448.             update_buffer[c]                = UPDATETYPE_OUT_OF_RANGE_OBJECTS;
  7449.             ++c;
  7450.  
  7451.             *(uint32*)&update_buffer[c]  = mOutOfRangeIdCount;
  7452.             c += 4;
  7453.  
  7454.             memcpy(&update_buffer[c], mOutOfRangeIds.contents(), mOutOfRangeIds.size());
  7455.             c += mOutOfRangeIds.size();
  7456.             mOutOfRangeIds.clear();
  7457.             mOutOfRangeIdCount = 0;
  7458.         }
  7459.  
  7460.         if(bCreationBuffer.size())
  7461.             memcpy(&update_buffer[c], bCreationBuffer.contents(), bCreationBuffer.size());
  7462.         c += bCreationBuffer.size();
  7463.  
  7464.         // clear our update buffer
  7465.         bCreationBuffer.clear();
  7466.         mCreationCount = 0;
  7467.  
  7468.         // compress update packet
  7469.         // while we said 350 before, I'm gonna make it 500 :D
  7470.         if(c < (size_t)sWorld.compression_threshold || !CompressAndSendUpdateBuffer((uint32)c, update_buffer))
  7471.         {
  7472.             // send uncompressed packet -> because we failed
  7473.             m_session->OutPacket(SMSG_UPDATE_OBJECT, (uint16)c, update_buffer);
  7474.         }
  7475.     }
  7476.  
  7477.     if(bUpdateBuffer.size())
  7478.     {
  7479.         c = 0;
  7480.  
  7481.         *(uint32*)&update_buffer[c] = ((mOutOfRangeIds.size() > 0) ? (mUpdateCount + 1) : mUpdateCount);
  7482.         c += 4;
  7483.  
  7484.         //update_buffer[c] = 1;                                                                            ++c;
  7485.         memcpy(&update_buffer[c], bUpdateBuffer.contents(), bUpdateBuffer.size());
  7486.         c += bUpdateBuffer.size();
  7487.  
  7488.         // clear our update buffer
  7489.         bUpdateBuffer.clear();
  7490.         mUpdateCount = 0;
  7491.  
  7492.         // compress update packet
  7493.         // while we said 350 before, I'm gonna make it 500 :D
  7494.         if(c < (size_t)sWorld.compression_threshold || !CompressAndSendUpdateBuffer((uint32)c, update_buffer))
  7495.         {
  7496.             // send uncompressed packet -> because we failed
  7497.             m_session->OutPacket(SMSG_UPDATE_OBJECT, (uint16)c, update_buffer);
  7498.         }
  7499.     }
  7500.  
  7501.     bProcessPending = false;
  7502.     _bufferS.Release();
  7503.     delete [] update_buffer;
  7504.  
  7505.     // send any delayed packets
  7506.     WorldPacket* pck;
  7507.     while(delayedPackets.size())
  7508.     {
  7509.         pck = delayedPackets.next();
  7510.         //printf("Delayed packet opcode %u sent.\n", pck->GetOpcode());
  7511.         m_session->SendPacket(pck);
  7512.         delete pck;
  7513.     }
  7514.  
  7515.     // resend speed if needed
  7516.     if(resend_speed)
  7517.     {
  7518.         SetSpeeds(RUN, m_runSpeed);
  7519.         SetSpeeds(FLY, m_flySpeed);
  7520.         resend_speed = false;
  7521.     }
  7522. }
  7523.  
  7524. bool Player::CompressAndSendUpdateBuffer(uint32 size, const uint8* update_buffer)
  7525. {
  7526.     uint32 destsize = size + size / 10 + 16;
  7527.     int rate = sWorld.getIntRate(INTRATE_COMPRESSION);
  7528.     if(size >= 40000 && rate < 6)
  7529.         rate = 6;
  7530.  
  7531.     // set up stream
  7532.     z_stream stream;
  7533.     stream.zalloc = 0;
  7534.     stream.zfree  = 0;
  7535.     stream.opaque = 0;
  7536.  
  7537.     if(deflateInit(&stream, rate) != Z_OK)
  7538.     {
  7539.         LOG_ERROR("deflateInit failed.");
  7540.         return false;
  7541.     }
  7542.  
  7543.     uint8* buffer = new uint8[destsize];
  7544.     //memset(buffer,0,destsize);    /* fix umr - burlex */
  7545.  
  7546.     // set up stream pointers
  7547.     stream.next_out  = (Bytef*)buffer + 4;
  7548.     stream.avail_out = destsize;
  7549.     stream.next_in   = (Bytef*)update_buffer;
  7550.     stream.avail_in  = size;
  7551.  
  7552.     // call the actual process
  7553.     if(deflate(&stream, Z_NO_FLUSH) != Z_OK ||
  7554.             stream.avail_in != 0)
  7555.     {
  7556.         LOG_ERROR("deflate failed.");
  7557.         delete [] buffer;
  7558.         return false;
  7559.     }
  7560.  
  7561.     // finish the deflate
  7562.     if(deflate(&stream, Z_FINISH) != Z_STREAM_END)
  7563.     {
  7564.         LOG_ERROR("deflate failed: did not end stream");
  7565.         delete [] buffer;
  7566.         return false;
  7567.     }
  7568.  
  7569.     // finish up
  7570.     if(deflateEnd(&stream) != Z_OK)
  7571.     {
  7572.         LOG_ERROR("deflateEnd failed.");
  7573.         delete [] buffer;
  7574.         return false;
  7575.     }
  7576.  
  7577.     // fill in the full size of the compressed stream
  7578.  
  7579.     *(uint32*)&buffer[0] = size;
  7580.  
  7581.     // send it
  7582.     m_session->OutPacket(SMSG_COMPRESSED_UPDATE_OBJECT, (uint16)stream.total_out + 4, buffer);
  7583.  
  7584.     // cleanup memory
  7585.     delete [] buffer;
  7586.  
  7587.     return true;
  7588. }
  7589.  
  7590. void Player::ClearAllPendingUpdates()
  7591. {
  7592.     _bufferS.Acquire();
  7593.     bProcessPending = false;
  7594.     mUpdateCount = 0;
  7595.     bUpdateBuffer.clear();
  7596.     _bufferS.Release();
  7597. }
  7598.  
  7599. void Player::AddSplinePacket(uint64 guid, ByteBuffer* packet)
  7600. {
  7601.     SplineMap::iterator itr = _splineMap.find(guid);
  7602.     if(itr != _splineMap.end())
  7603.     {
  7604.         delete itr->second;
  7605.         _splineMap.erase(itr);
  7606.     }
  7607.     _splineMap.insert(SplineMap::value_type(guid, packet));
  7608. }
  7609.  
  7610. ByteBuffer* Player::GetAndRemoveSplinePacket(uint64 guid)
  7611. {
  7612.     SplineMap::iterator itr = _splineMap.find(guid);
  7613.     if(itr != _splineMap.end())
  7614.     {
  7615.         ByteBuffer* buf = itr->second;
  7616.         _splineMap.erase(itr);
  7617.         return buf;
  7618.     }
  7619.     return NULL;
  7620. }
  7621.  
  7622. void Player::ClearSplinePackets()
  7623. {
  7624.     SplineMap::iterator it2;
  7625.     for(SplineMap::iterator itr = _splineMap.begin(); itr != _splineMap.end();)
  7626.     {
  7627.         it2 = itr;
  7628.         ++itr;
  7629.         delete it2->second;
  7630.         _splineMap.erase(it2);
  7631.     }
  7632.     _splineMap.clear();
  7633. }
  7634.  
  7635.  
  7636.  
  7637. bool Player::ExitInstance()
  7638. {
  7639.     if(!m_bgEntryPointX)
  7640.         return false;
  7641.  
  7642.     RemoveFromWorld();
  7643.  
  7644.     SafeTeleport(m_bgEntryPointMap, m_bgEntryPointInstance, LocationVector(
  7645.                      m_bgEntryPointX, m_bgEntryPointY, m_bgEntryPointZ, m_bgEntryPointO));
  7646.  
  7647.     return true;
  7648. }
  7649.  
  7650. void Player::SaveEntryPoint(uint32 mapId)
  7651. {
  7652.     if(IS_INSTANCE(GetMapId()))
  7653.         return; // don't save if we're not on the main continent.
  7654.     //otherwise we could end up in an endless loop :P
  7655.     MapInfo* pMapinfo = WorldMapInfoStorage.LookupEntry(mapId);
  7656.  
  7657.     if(pMapinfo)
  7658.     {
  7659.         m_bgEntryPointX = pMapinfo->repopx;
  7660.         m_bgEntryPointY = pMapinfo->repopy;
  7661.         m_bgEntryPointZ = pMapinfo->repopz;
  7662.         m_bgEntryPointO = GetOrientation();
  7663.         m_bgEntryPointMap = pMapinfo->repopmapid;
  7664.         m_bgEntryPointInstance = GetInstanceID();
  7665.     }
  7666.     else
  7667.     {
  7668.         m_bgEntryPointMap    = 0;
  7669.         m_bgEntryPointX      = 0;
  7670.         m_bgEntryPointY      = 0;
  7671.         m_bgEntryPointZ      = 0;
  7672.         m_bgEntryPointO      = 0;
  7673.         m_bgEntryPointInstance  = 0;
  7674.     }
  7675. }
  7676.  
  7677. void Player::CleanupGossipMenu()
  7678. {
  7679.     if(CurrentGossipMenu)
  7680.     {
  7681.         delete CurrentGossipMenu;
  7682.         CurrentGossipMenu = NULL;
  7683.     }
  7684. }
  7685.  
  7686. void Player::Gossip_Complete()
  7687. {
  7688.     GetSession()->OutPacket(SMSG_GOSSIP_COMPLETE, 0, NULL);
  7689.     CleanupGossipMenu();
  7690. }
  7691.  
  7692.  
  7693. void Player::CloseGossip()
  7694. {
  7695.     Gossip_Complete();
  7696. }
  7697.  
  7698. void Player::PrepareQuestMenu(uint64 guid)
  7699. {
  7700.     uint32 TextID = 820;
  7701.     objmgr.CreateGossipMenuForPlayer(&PlayerTalkClass, guid, TextID, this);
  7702. }
  7703.  
  7704. void Player::SendGossipMenu(uint32 TitleTextId, uint64 npcGUID)
  7705. {
  7706.     PlayerTalkClass->SetTextID(TitleTextId);
  7707.     PlayerTalkClass->SendTo(this);
  7708. }
  7709.  
  7710. bool Player::IsInCity()
  7711. {
  7712.     AreaTable* at = GetMapMgr()->GetArea(GetPositionX(), GetPositionY(), GetPositionZ());
  7713.     AreaTable* zt = NULL;
  7714.     if(at->ZoneId)
  7715.         zt = dbcArea.LookupEntry(at->ZoneId);
  7716.  
  7717.     bool areaIsCity = at->AreaFlags & AREA_CITY_AREA || at->AreaFlags & AREA_CITY;
  7718.     bool zoneIsCity = zt && (zt->AreaFlags & AREA_CITY_AREA || zt->AreaFlags & AREA_CITY);
  7719.  
  7720.     return (areaIsCity || zoneIsCity);
  7721. }
  7722.  
  7723. void Player::ZoneUpdate(uint32 ZoneId)
  7724. {
  7725.     uint32 oldzone = m_zoneId;
  7726.     if(m_zoneId != ZoneId)
  7727.     {
  7728.         SetZoneId(ZoneId);
  7729.         RemoveAurasByInterruptFlag(AURA_INTERRUPT_ON_LEAVE_AREA);
  7730.     }
  7731.  
  7732.     /* how the f*ck is this happening */
  7733.     if(m_playerInfo == NULL)
  7734.     {
  7735.         m_playerInfo = objmgr.GetPlayerInfo(GetLowGUID());
  7736.         if(m_playerInfo == NULL)
  7737.         {
  7738.             m_session->Disconnect();
  7739.             return;
  7740.         }
  7741.     }
  7742.  
  7743.     m_playerInfo->lastZone = ZoneId;
  7744.     sHookInterface.OnZone(this, ZoneId, oldzone);
  7745.     CALL_INSTANCE_SCRIPT_EVENT(m_mapMgr, OnZoneChange)(this, ZoneId, oldzone);
  7746.  
  7747.     AreaTable* at = GetMapMgr()->GetArea(GetPositionX(), GetPositionY(), GetPositionZ());
  7748.     if(at && (at->category == AREAC_SANCTUARY || at->AreaFlags & AREA_SANCTUARY))
  7749.     {
  7750.         Unit* pUnit = (GetSelection() == 0) ? 0 : (m_mapMgr ? m_mapMgr->GetUnit(GetSelection()) : 0);
  7751.         if(pUnit && DuelingWith != pUnit)
  7752.         {
  7753.             EventAttackStop();
  7754.             smsg_AttackStop(pUnit);
  7755.         }
  7756.  
  7757.         if(m_currentSpell)
  7758.         {
  7759.             Unit* target = m_currentSpell->GetUnitTarget();
  7760.             if(target && target != DuelingWith && target != this)
  7761.                 m_currentSpell->cancel();
  7762.         }
  7763.     }
  7764.  
  7765.     at = dbcArea.LookupEntryForced(ZoneId);
  7766.  
  7767.     if(!m_channels.empty() && at)
  7768.     {
  7769.         // change to zone name, not area name
  7770.         for(std::set<Channel*>::iterator itr = m_channels.begin(), nextitr ; itr != m_channels.end() ; itr = nextitr)
  7771.         {
  7772.             nextitr = itr;
  7773.             ++nextitr;
  7774.             Channel* chn;
  7775.             chn = (*itr);
  7776.             // Check if this is a custom channel (i.e. global)
  7777.             if(!((*itr)->m_flags & 0x10))
  7778.                 continue;
  7779.  
  7780.             if(chn->m_flags & 0x40)   // LookingForGroup - constant among all zones
  7781.                 continue;
  7782.  
  7783.             char updatedName[95];
  7784.             ChatChannelDBC* pDBC;
  7785.             pDBC = dbcChatChannels.LookupEntryForced(chn->m_id);
  7786.             if(!pDBC)
  7787.             {
  7788.                 Log.Error("ChannelMgr" , "Invalid channel entry %u for %s" , chn->m_id , chn->m_name.c_str());
  7789.                 return;
  7790.             }
  7791.             //for( int i = 0 ; i <= 15 ; i ++ )
  7792.             //  Log.Notice( "asfssdf" , "%u %s" , i , pDBC->name_pattern[i] );
  7793.             snprintf(updatedName , 95 , pDBC->name_pattern[0] , at->name);
  7794.             Channel* newChannel = channelmgr.GetCreateChannel(updatedName , NULL , chn->m_id);
  7795.             if(newChannel == NULL)
  7796.             {
  7797.                 Log.Error("ChannelMgr" , "Could not create channel %s!" , updatedName);
  7798.                 return; // whoops?
  7799.             }
  7800.             //Log.Notice( "ChannelMgr" , "LEAVING CHANNEL %s" , chn->m_name.c_str() );
  7801.             //Log.Notice( "ChannelMgr" , "JOINING CHANNEL %s" , newChannel->m_name.c_str() );
  7802.             if(chn != newChannel)   // perhaps there's no need
  7803.             {
  7804.                 // join new channel
  7805.                 newChannel->AttemptJoin(this , "");
  7806.                 // leave the old channel
  7807.  
  7808.                 chn->Part(this , false);
  7809.             }
  7810.         }
  7811.     }
  7812.  
  7813.     SendInitialWorldstates();
  7814.  
  7815.     UpdateChannels(static_cast<int16>(ZoneId));
  7816.     /*std::map<uint32, AreaTable*>::iterator iter = sWorld.mZoneIDToTable.find(ZoneId);
  7817.     if(iter == sWorld.mZoneIDToTable.end())
  7818.         return;
  7819.  
  7820.     AreaTable *p = iter->second;
  7821.     if(p->AreaId != m_AreaID)
  7822.     {
  7823.         m_AreaID = p->AreaId;
  7824.         UpdatePVPStatus(m_AreaID);
  7825.     }
  7826.  
  7827.     LOG_DETAIL("ZONE_UPDATE: Player %s entered zone %s", GetName(), sAreaStore.LookupString((int)p->name));*/
  7828.     //UpdatePvPArea();
  7829.  
  7830. }
  7831. void Player::UpdateChannels(uint16 AreaID)
  7832. {
  7833.     set<Channel*>::iterator i;
  7834.     Channel* c;
  7835.     string channelname, AreaName;
  7836.  
  7837.  
  7838.     if(GetMapId() == 450)
  7839.         AreaID = 2917;
  7840.     else if(GetMapId() == 449)
  7841.         AreaID = 2918;
  7842.  
  7843.     AreaTable* at2 = dbcArea.LookupEntryForced(AreaID);
  7844.  
  7845.     //Check for instances?
  7846.     if(!AreaID || AreaID == 0xFFFF)
  7847.     {
  7848.         MapInfo* pMapinfo = WorldMapInfoStorage.LookupEntry(GetMapId());
  7849.         if(IS_INSTANCE(GetMapId()))
  7850.             AreaName = pMapinfo->name;
  7851.         else
  7852.             return;//How'd we get here?
  7853.     }
  7854.     else
  7855.     {
  7856.         AreaName = at2->name;
  7857.         if(AreaName.length() < 2)
  7858.         {
  7859.             MapInfo* pMapinfo = WorldMapInfoStorage.LookupEntry(GetMapId());
  7860.             AreaName = pMapinfo->name;
  7861.         }
  7862.     }
  7863.  
  7864.     for(i = m_channels.begin(); i != m_channels.end();)
  7865.     {
  7866.         c = *i;
  7867.         i++;
  7868.  
  7869.         if(!c->m_general || c->m_name == "LookingForGroup")//Not an updatable channel.
  7870.             continue;
  7871.  
  7872.         if(strstr(c->m_name.c_str(), "General"))
  7873.             channelname = "General";
  7874.         else if(strstr(c->m_name.c_str(), "Trade"))
  7875.             channelname = "Trade";
  7876.         else if(strstr(c->m_name.c_str(), "LocalDefense"))
  7877.             channelname = "LocalDefense";
  7878.         else if(strstr(c->m_name.c_str(), "GuildRecruitment"))
  7879.             channelname = "GuildRecruitment";
  7880.         else
  7881.             continue;//Those 4 are the only ones we want updated.
  7882.         channelname += " - ";
  7883.         if((strstr(c->m_name.c_str(), "Trade") || strstr(c->m_name.c_str(), "GuildRecruitment")) && (at2->AreaFlags & AREA_CITY || at2->AreaFlags & AREA_CITY_AREA))
  7884.         {
  7885.             channelname += "City";
  7886.         }
  7887.         else
  7888.             channelname += AreaName;
  7889.  
  7890.         Channel* chn = channelmgr.GetCreateChannel(channelname.c_str(), this, c->m_id);
  7891.         if(chn != NULL && !chn->HasMember(this))
  7892.         {
  7893.             c->Part(this);
  7894.             chn->AttemptJoin(this, NULL);
  7895.         }
  7896.     }
  7897. }
  7898. void Player::SendTradeUpdate()
  7899. {
  7900.     Player* pTarget = GetTradeTarget();
  7901.     if(!pTarget)
  7902.         return;
  7903.  
  7904.     WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, 532);
  7905.  
  7906.     data << uint8(1);
  7907.     data << uint32(0x19);
  7908.     data << m_tradeSequence;
  7909.     data << m_tradeSequence++;
  7910.     data << mTradeGold;
  7911.     data << uint32(0);
  7912.  
  7913.     uint8 count = 0;
  7914.     // Items
  7915.     for(uint32 Index = 0; Index < 7; ++Index)
  7916.     {
  7917.         Item* pItem = mTradeItems[ Index ];
  7918.         if(pItem != 0)
  7919.         {
  7920.             count++;
  7921.             ItemPrototype* pProto = pItem->GetProto();
  7922.             ARCEMU_ASSERT(pProto != NULL);
  7923.  
  7924.             data << uint8(Index);
  7925.  
  7926.             data << uint32(pProto->ItemId);
  7927.             data << uint32(pProto->DisplayInfoID);
  7928.             data << uint32(pItem->GetStackCount()); // Amount          OK
  7929.  
  7930.             // Enchantment stuff
  7931.             data << uint32(0);                                          // unknown
  7932.             data << uint64(pItem->GetGiftCreatorGUID());    // gift creator  OK
  7933.             data << uint32(pItem->GetEnchantmentId(0)); // Item Enchantment OK
  7934.             for(uint8 i = 2; i < 5; i++)                                // Gem enchantments
  7935.             {
  7936.                 if(pItem->GetEnchantment(i) != NULL && pItem->GetEnchantment(i)->Enchantment != NULL)
  7937.                     data << uint32(pItem->GetEnchantment(i)->Enchantment->Id);
  7938.                 else
  7939.                     data << uint32(0);
  7940.             }
  7941.             data << uint64(pItem->GetCreatorGUID());        // item creator  OK
  7942.             data << uint32(pItem->GetCharges(0));   // Spell Charges    OK
  7943.             data << uint32(pItem->GetItemRandomSuffixFactor());                                         // seems like time stamp or something like that
  7944.             data << uint32(pItem->GetItemRandomPropertyId());
  7945.             data << uint32(pProto->LockId);                                     // lock ID        OK
  7946.             data << uint32(pItem->GetDurabilityMax());
  7947.             data << uint32(pItem->GetDurability());
  7948.         }
  7949.     }
  7950.     data.resize(21 + count * 73);
  7951.     pTarget->SendPacket(&data);
  7952. }
  7953.  
  7954. void Player::RequestDuel(Player* pTarget)
  7955. {
  7956.     // We Already Dueling or have already Requested a Duel
  7957.  
  7958.     if(DuelingWith != NULL)
  7959.         return;
  7960.  
  7961.     if(m_duelState != DUEL_STATE_FINISHED)
  7962.         return;
  7963.  
  7964.     SetDuelState(DUEL_STATE_REQUESTED);
  7965.  
  7966.     //Setup Duel
  7967.     pTarget->DuelingWith = this;
  7968.     DuelingWith = pTarget;
  7969.  
  7970.     //Get Flags position
  7971.     float dist = CalcDistance(pTarget);
  7972.     dist = dist * 0.5f; //half way
  7973.     float x = (GetPositionX() + pTarget->GetPositionX() * dist) / (1 + dist) + cos(GetOrientation() + (M_PI_FLOAT / 2)) * 2;
  7974.     float y = (GetPositionY() + pTarget->GetPositionY() * dist) / (1 + dist) + sin(GetOrientation() + (M_PI_FLOAT / 2)) * 2;
  7975.     float z = (GetPositionZ() + pTarget->GetPositionZ() * dist) / (1 + dist);
  7976.  
  7977.     //Create flag/arbiter
  7978.     GameObject* pGameObj = GetMapMgr()->CreateGameObject(21680);
  7979.     pGameObj->CreateFromProto(21680, GetMapId(), x, y, z, GetOrientation());
  7980.  
  7981.     //Spawn the Flag
  7982.     pGameObj->SetUInt64Value(OBJECT_FIELD_CREATED_BY, GetGUID());
  7983.     pGameObj->SetFaction(GetFaction());
  7984.     pGameObj->SetLevel(getLevel());
  7985.  
  7986.     //Assign the Flag
  7987.     SetDuelArbiter(pGameObj->GetGUID());
  7988.     pTarget->SetDuelArbiter(pGameObj->GetGUID());
  7989.  
  7990.     pGameObj->PushToWorld(m_mapMgr);
  7991.  
  7992.     WorldPacket data(SMSG_DUEL_REQUESTED, 16);
  7993.     data << pGameObj->GetGUID();
  7994.     data << GetGUID();
  7995.     pTarget->GetSession()->SendPacket(&data);
  7996. }
  7997.  
  7998. void Player::DuelCountdown()
  7999. {
  8000.     if(DuelingWith == NULL)
  8001.         return;
  8002.  
  8003.     m_duelCountdownTimer -= 1000;
  8004.  
  8005.     if(static_cast<int32>(m_duelCountdownTimer) < 0)
  8006.         m_duelCountdownTimer = 0;
  8007.  
  8008.     if(m_duelCountdownTimer == 0)
  8009.     {
  8010.         // Start Duel.
  8011.         SetPower(POWER_TYPE_RAGE, 0);
  8012.         DuelingWith->SetPower(POWER_TYPE_RAGE, 0);
  8013.  
  8014.         //Give the players a Team
  8015.         DuelingWith->SetDuelTeam(1);  // Duel Requester
  8016.         SetDuelTeam(2);
  8017.  
  8018.         SetDuelState(DUEL_STATE_STARTED);
  8019.         DuelingWith->SetDuelState(DUEL_STATE_STARTED);
  8020.  
  8021.         sEventMgr.AddEvent(this, &Player::DuelBoundaryTest, EVENT_PLAYER_DUEL_BOUNDARY_CHECK, 500, 0, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
  8022.         sEventMgr.AddEvent(DuelingWith, &Player::DuelBoundaryTest, EVENT_PLAYER_DUEL_BOUNDARY_CHECK, 500, 0, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
  8023.     }
  8024. }
  8025.  
  8026. void Player::DuelBoundaryTest()
  8027. {
  8028.     //check if in bounds
  8029.     if(!IsInWorld())
  8030.         return;
  8031.  
  8032.     GameObject* pGameObject = GetMapMgr()->GetGameObject(GET_LOWGUID_PART(GetDuelArbiter()));
  8033.     if(!pGameObject)
  8034.     {
  8035.         EndDuel(DUEL_WINNER_RETREAT);
  8036.         return;
  8037.     }
  8038.  
  8039.     float Dist = CalcDistance(pGameObject);
  8040.  
  8041.     if(Dist > 75.0f)
  8042.     {
  8043.         // Out of bounds
  8044.         if(m_duelStatus == DUEL_STATUS_OUTOFBOUNDS)
  8045.         {
  8046.             // we already know, decrease timer by 500
  8047.             m_duelCountdownTimer -= 500;
  8048.             if(m_duelCountdownTimer == 0)
  8049.             {
  8050.                 // Times up :p
  8051.                 DuelingWith->EndDuel(DUEL_WINNER_RETREAT);
  8052.             }
  8053.         }
  8054.         else
  8055.         {
  8056.             // we just went out of bounds
  8057.             // set timer
  8058.             m_duelCountdownTimer = 10000;
  8059.  
  8060.             // let us know
  8061.  
  8062.             m_session->OutPacket(SMSG_DUEL_OUTOFBOUNDS, 4, &m_duelCountdownTimer);
  8063.  
  8064.             m_duelStatus = DUEL_STATUS_OUTOFBOUNDS;
  8065.         }
  8066.     }
  8067.     else
  8068.     {
  8069.         // we're in range
  8070.         if(m_duelStatus == DUEL_STATUS_OUTOFBOUNDS)
  8071.         {
  8072.             // just came back in range
  8073.             m_session->OutPacket(SMSG_DUEL_INBOUNDS);
  8074.             m_duelStatus = DUEL_STATUS_INBOUNDS;
  8075.         }
  8076.     }
  8077. }
  8078.  
  8079. void Player::EndDuel(uint8 WinCondition)
  8080. {
  8081.     if(m_duelState == DUEL_STATE_FINISHED)
  8082.     {
  8083.         //if loggingout player requested a duel then we have to make the cleanups
  8084.         if(GET_LOWGUID_PART(GetDuelArbiter()))
  8085.         {
  8086.             GameObject* arbiter = m_mapMgr ? GetMapMgr()->GetGameObject(GET_LOWGUID_PART(GetDuelArbiter())) : 0;
  8087.  
  8088.             if(arbiter != NULL)
  8089.             {
  8090.                 arbiter->RemoveFromWorld(true);
  8091.                 delete arbiter;
  8092.             }
  8093.  
  8094.             //we do not wish to lock the other player in duel state
  8095.             DuelingWith->SetDuelArbiter(0);
  8096.             DuelingWith->SetDuelTeam(0);
  8097.             SetDuelArbiter(0);
  8098.             SetDuelTeam(0);
  8099.             sEventMgr.RemoveEvents(DuelingWith, EVENT_PLAYER_DUEL_BOUNDARY_CHECK);
  8100.             sEventMgr.RemoveEvents(DuelingWith, EVENT_PLAYER_DUEL_COUNTDOWN);
  8101.             DuelingWith->DuelingWith = NULL;
  8102.             DuelingWith = NULL;
  8103.             //the duel did not start so we are not in combat or cast any spells yet.
  8104.         }
  8105.         return;
  8106.     }
  8107.  
  8108.     // Remove the events
  8109.     sEventMgr.RemoveEvents(this, EVENT_PLAYER_DUEL_COUNTDOWN);
  8110.     sEventMgr.RemoveEvents(this, EVENT_PLAYER_DUEL_BOUNDARY_CHECK);
  8111.  
  8112.     for(uint32 x = MAX_POSITIVE_AURAS_EXTEDED_START; x < MAX_POSITIVE_AURAS_EXTEDED_END; ++x)
  8113.     {
  8114.         if(m_auras[x] == NULL)
  8115.             continue;
  8116.         if(m_auras[x]->WasCastInDuel())
  8117.             m_auras[x]->Remove();
  8118.     }
  8119.  
  8120.     m_duelState = DUEL_STATE_FINISHED;
  8121.  
  8122.     if(DuelingWith == NULL)
  8123.         return;
  8124.  
  8125.     sEventMgr.RemoveEvents(DuelingWith, EVENT_PLAYER_DUEL_BOUNDARY_CHECK);
  8126.     sEventMgr.RemoveEvents(DuelingWith, EVENT_PLAYER_DUEL_COUNTDOWN);
  8127.  
  8128.     for(uint32 x = MAX_POSITIVE_AURAS_EXTEDED_START; x < MAX_POSITIVE_AURAS_EXTEDED_END; ++x)
  8129.     {
  8130.         if(DuelingWith->m_auras[x] == NULL)
  8131.             continue;
  8132.         if(DuelingWith->m_auras[x]->WasCastInDuel())
  8133.             DuelingWith->m_auras[x]->Remove();
  8134.     }
  8135.  
  8136.     DuelingWith->m_duelState = DUEL_STATE_FINISHED;
  8137.  
  8138.     //Announce Winner
  8139.     WorldPacket data(SMSG_DUEL_WINNER, 500);
  8140.     data << uint8(WinCondition);
  8141.     data << GetName() << DuelingWith->GetName();
  8142.     SendMessageToSet(&data, true);
  8143.  
  8144.     data.Initialize(SMSG_DUEL_COMPLETE);
  8145.     data << uint8(1);
  8146.     SendMessageToSet(&data, true);
  8147.  
  8148.     //Send hook OnDuelFinished
  8149.  
  8150.     if(WinCondition != 0)
  8151.         sHookInterface.OnDuelFinished(DuelingWith, this);
  8152.     else
  8153.         sHookInterface.OnDuelFinished(this, DuelingWith);
  8154.  
  8155.     //Clear Duel Related Stuff
  8156.  
  8157.     GameObject* arbiter = m_mapMgr ? GetMapMgr()->GetGameObject(GET_LOWGUID_PART(GetDuelArbiter())) : 0;
  8158.  
  8159.     if(arbiter != NULL)
  8160.     {
  8161.         arbiter->RemoveFromWorld(true);
  8162.         delete arbiter;
  8163.     }
  8164.  
  8165.     SetDuelArbiter(0);
  8166.     SetDuelTeam(0);
  8167.     DuelingWith->SetDuelArbiter(0);
  8168.     DuelingWith->SetDuelTeam(0);
  8169.  
  8170.     EventAttackStop();
  8171.     DuelingWith->EventAttackStop();
  8172.  
  8173.     // Call off pet
  8174.     std::list<Pet*> summons = GetSummons();
  8175.     for(std::list<Pet*>::iterator itr = summons.begin(); itr != summons.end(); ++itr)
  8176.     {
  8177.         (*itr)->CombatStatus.Vanished();
  8178.         (*itr)->GetAIInterface()->SetUnitToFollow(this);
  8179.         (*itr)->GetAIInterface()->HandleEvent(EVENT_FOLLOWOWNER, *itr, 0);
  8180.         (*itr)->GetAIInterface()->WipeTargetList();
  8181.     }
  8182.  
  8183.     std::list<Pet*> duelingWithSummons = DuelingWith->GetSummons();
  8184.     for(std::list<Pet*>::iterator itr = duelingWithSummons.begin(); itr != duelingWithSummons.end(); ++itr)
  8185.     {
  8186.         (*itr)->CombatStatus.Vanished();
  8187.         (*itr)->GetAIInterface()->SetUnitToFollow(this);
  8188.         (*itr)->GetAIInterface()->HandleEvent(EVENT_FOLLOWOWNER, *itr, 0);
  8189.         (*itr)->GetAIInterface()->WipeTargetList();
  8190.     }
  8191.  
  8192.     // removing auras that kills players after if low HP
  8193.     /*RemoveNegativeAuras(); NOT NEEDED. External targets can always gank both duelers with DoTs. :D
  8194.     DuelingWith->RemoveNegativeAuras();*/
  8195.     //Same as above only cleaner.
  8196.     for(uint32 x = MAX_NEGATIVE_AURAS_EXTEDED_START; x < MAX_REMOVABLE_AURAS_END; x++)
  8197.     {
  8198.         if(DuelingWith->m_auras[x])
  8199.         {
  8200.             if(DuelingWith->m_auras[x]->WasCastInDuel())
  8201.                 DuelingWith->m_auras[x]->Remove();
  8202.         }
  8203.         if(m_auras[x])
  8204.         {
  8205.             if(m_auras[x]->WasCastInDuel())
  8206.                 m_auras[x]->Remove();
  8207.         }
  8208.     }
  8209.  
  8210.     //Stop Players attacking so they don't kill the other player
  8211.     m_session->OutPacket(SMSG_CANCEL_COMBAT);
  8212.     DuelingWith->m_session->OutPacket(SMSG_CANCEL_COMBAT);
  8213.  
  8214.     smsg_AttackStop(DuelingWith);
  8215.     DuelingWith->smsg_AttackStop(this);
  8216.  
  8217.     DuelingWith->m_duelCountdownTimer = 0;
  8218.     m_duelCountdownTimer = 0;
  8219.  
  8220.     DuelingWith->DuelingWith = NULL;
  8221.     DuelingWith = NULL;
  8222. }
  8223.  
  8224. void Player::StopMirrorTimer(uint32 Type)
  8225. {
  8226.     m_session->OutPacket(SMSG_STOP_MIRROR_TIMER, 4, &Type);
  8227. }
  8228.  
  8229. void Player::EventTeleport(uint32 mapid, float x, float y, float z)
  8230. {
  8231.     SafeTeleport(mapid, 0, LocationVector(x, y, z));
  8232. }
  8233.  
  8234. void Player::EventTeleportTaxi(uint32 mapid, float x, float y, float z)
  8235. {
  8236.     if(mapid == 530 && !m_session->HasFlag(ACCOUNT_FLAG_XPACK_01))
  8237.     {
  8238.         WorldPacket msg(CMSG_SERVER_BROADCAST, 50);
  8239.         msg << uint32(3) << "You must have The Burning Crusade Expansion to access this content." << uint8(0);
  8240.         m_session->SendPacket(&msg);
  8241.         RepopAtGraveyard(GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId());
  8242.         return;
  8243.     }
  8244.     _Relocate(mapid, LocationVector(x, y, z), (mapid == GetMapId() ? false : true), true, 0);
  8245.     ForceZoneUpdate();
  8246. }
  8247.  
  8248. void Player::ApplyLevelInfo(LevelInfo* Info, uint32 Level)
  8249. {
  8250.     ARCEMU_ASSERT(Info != NULL);
  8251.  
  8252.     // Apply level
  8253.     uint32 PreviousLevel = getLevel();
  8254.     setLevel(Level);
  8255.  
  8256.     // Set next level conditions
  8257.     SetNextLevelXp(Info->XPToNextLevel);
  8258.  
  8259.     // Set stats
  8260.     for(uint8 i = 0; i < 5; ++i)
  8261.     {
  8262.         BaseStats[i] = Info->Stat[i];
  8263.         CalcStat(i);
  8264.     }
  8265.  
  8266.     // Set health / mana
  8267.     SetHealth(Info->HP);
  8268.     SetMaxHealth(Info->HP);
  8269.     SetMaxPower(POWER_TYPE_MANA, Info->Mana);
  8270.     SetPower(POWER_TYPE_MANA, Info->Mana);
  8271.  
  8272.  
  8273.     if( Level > PreviousLevel ){
  8274.         if( Level > 9 )
  8275.             SetTalentPointsForAllSpec( Level - 9 );
  8276.     }else{
  8277.         if( Level != PreviousLevel )
  8278.             Reset_AllTalents();
  8279.     }
  8280.  
  8281.     // Set base fields
  8282.     SetBaseHealth(Info->HP);
  8283.     SetBaseMana(Info->Mana);
  8284.  
  8285.     _UpdateMaxSkillCounts();
  8286.     UpdateStats();
  8287.     //UpdateChances();
  8288.     UpdateGlyphs();
  8289.     m_playerInfo->lastLevel = Level;
  8290. #ifdef ENABLE_ACHIEVEMENTS
  8291.     GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL);
  8292. #endif
  8293.     //VLack: 3.1.3, as a final step, send the player's talents, this will set the talent points right too...
  8294.     smsg_TalentsInfo(false);
  8295.  
  8296.     LOG_DETAIL("Player %s set parameters to level %u", GetName(), Level);
  8297. }
  8298.  
  8299. void Player::BroadcastMessage(const char* Format, ...)
  8300. {
  8301.     va_list l;
  8302.     va_start(l, Format);
  8303.     char Message[1024];
  8304.     vsnprintf(Message, 1024, Format, l);
  8305.     va_end(l);
  8306.  
  8307.     WorldPacket* data = sChatHandler.FillSystemMessageData(Message);
  8308.     m_session->SendPacket(data);
  8309.     delete data;
  8310. }
  8311. /*
  8312. const double BaseRating []= {
  8313.     2.5,//weapon_skill_ranged!!!!
  8314.     1.5,//defense=comba_r_1
  8315.     12,//dodge
  8316.     20,//parry=3
  8317.     5,//block=4
  8318.     10,//melee hit
  8319.     10,//ranged hit
  8320.     8,//spell hit=7
  8321.     14,//melee critical strike=8
  8322.     14,//ranged critical strike=9
  8323.     14,//spell critical strike=10
  8324.     0,//
  8325.     0,
  8326.     0,
  8327.     25,//resilience=14
  8328.     25,//resil .... meaning unknown
  8329.     25,//resil .... meaning unknown
  8330.     10,//MELEE_HASTE_RATING=17
  8331.     10,//RANGED_HASTE_RATING=18
  8332.     10,//spell_haste_rating = 19???
  8333.     2.5,//melee weapon skill==20
  8334.     2.5,//melee second hand=21
  8335.  
  8336. };
  8337. */
  8338. float Player::CalcRating(uint32 index)
  8339. {
  8340.     uint32 relative_index = index - (PLAYER_FIELD_COMBAT_RATING_1);
  8341.     float rating = float(m_uint32Values[index]);
  8342.  
  8343.     uint32 level = getLevel();
  8344.     if(level > 100)
  8345.         level = 100;
  8346.  
  8347.     CombatRatingDBC* pDBCEntry = dbcCombatRating.LookupEntryForced(relative_index * 100 + level - 1);
  8348.     if(pDBCEntry == NULL)
  8349.         return rating;
  8350.     else
  8351.         return (rating / pDBCEntry->val);
  8352. }
  8353.  
  8354. bool Player::SafeTeleport(uint32 MapID, uint32 InstanceID, float X, float Y, float Z, float O)
  8355. {
  8356.     return SafeTeleport(MapID, InstanceID, LocationVector(X, Y, Z, O));
  8357. }
  8358.  
  8359. bool Player::SafeTeleport(uint32 MapID, uint32 InstanceID, const LocationVector & vec)
  8360. {
  8361.     // Checking if we have a unit whose waypoints are shown
  8362.     // If there is such, then we "unlink" it
  8363.     // Failing to do so leads to a crash if we try to show some other Unit's wps, after the map was shut down
  8364.     if(waypointunit != NULL)
  8365.         waypointunit->hideWayPoints(this);
  8366.     waypointunit = NULL;
  8367.  
  8368.     SpeedCheatDelay(10000);
  8369.  
  8370.     if(GetTaxiState())
  8371.     {
  8372.         sEventMgr.RemoveEvents(this, EVENT_PLAYER_TELEPORT);
  8373.         sEventMgr.RemoveEvents(this, EVENT_PLAYER_TAXI_DISMOUNT);
  8374.         sEventMgr.RemoveEvents(this, EVENT_PLAYER_TAXI_INTERPOLATE);
  8375.         SetTaxiState(false);
  8376.         SetTaxiPath(NULL);
  8377.         UnSetTaxiPos();
  8378.         m_taxi_ride_time = 0;
  8379.         SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID , 0);
  8380.         RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNTED_TAXI);
  8381.         RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOCK_PLAYER);
  8382.         SetSpeeds(RUN, m_runSpeed);
  8383.     }
  8384.     if(transporter_info.guid)
  8385.     {
  8386.         Transporter* pTrans = objmgr.GetTransporter(Arcemu::Util::GUID_LOPART(transporter_info.guid));
  8387.         if(pTrans)
  8388.         {
  8389.             pTrans->RemovePlayer(this);
  8390.             m_CurrentTransporter = NULL;
  8391.             transporter_info.guid = 0;
  8392.         }
  8393.     }
  8394.  
  8395.     bool instance = false;
  8396.     MapInfo* mi = WorldMapInfoStorage.LookupEntry(MapID);
  8397.  
  8398.     if(InstanceID && (uint32)m_instanceId != InstanceID)
  8399.     {
  8400.         instance = true;
  8401.         this->SetInstanceID(InstanceID);
  8402.     }
  8403.     else if(m_mapId != MapID)
  8404.     {
  8405.         instance = true;
  8406.     }
  8407.  
  8408.     // make sure player does not drown when teleporting from under water
  8409.     if(m_UnderwaterState & UNDERWATERSTATE_UNDERWATER)
  8410.         m_UnderwaterState &= ~UNDERWATERSTATE_UNDERWATER;
  8411.  
  8412.     if(flying_aura && ((m_mapId != 530) && (m_mapId != 571 || !HasSpellwithNameHash(SPELL_HASH_COLD_WEATHER_FLYING))))
  8413.         // can only fly in outlands or northrend (northrend requires cold weather flying)
  8414.     {
  8415.         RemoveAura(flying_aura);
  8416.         flying_aura = 0;
  8417.     }
  8418.  
  8419.     // Exit vehicle before teleporting
  8420.     if( GetVehicleBase() != NULL )
  8421.         GetVehicleBase()->GetVehicleComponent()->EjectPassenger( this );
  8422.  
  8423.     // Lookup map info
  8424.     if(mi && mi->flags & WMI_INSTANCE_XPACK_01 && !m_session->HasFlag(ACCOUNT_FLAG_XPACK_01) && !m_session->HasFlag(ACCOUNT_FLAG_XPACK_02))
  8425.     {
  8426.         WorldPacket msg(SMSG_MOTD, 50); // Need to be replaced with correct one !
  8427.         msg << uint32(3) << "You must have The Burning Crusade Expansion to access this content." << uint8(0);
  8428.         m_session->SendPacket(&msg);
  8429.         return false;
  8430.     }
  8431.     if(mi && mi->flags & WMI_INSTANCE_XPACK_02 && !m_session->HasFlag(ACCOUNT_FLAG_XPACK_02))
  8432.     {
  8433.         WorldPacket msg(SMSG_MOTD, 50); // Need to be replaced with correct one !
  8434.         msg << uint32(3) << "You must have Wrath of the Lich King Expansion to access this content." << uint8(0);
  8435.         m_session->SendPacket(&msg);
  8436.         return false;
  8437.     }
  8438.  
  8439.     // cebernic: cleanup before teleport
  8440.     // seems BFleaveOpcode was breakdown,that will be causing big BUG with player leaving from the BG
  8441.     // now this much better:D RemoveAura & BG_DESERTER going to well as you go out from BG.
  8442.     if(m_bg && m_bg->GetMapMgr() && GetMapMgr()->GetMapInfo()->mapid != MapID)
  8443.     {
  8444.         m_bg->RemovePlayer(this, false);
  8445.     }
  8446.  
  8447.     _Relocate(MapID, vec, true, instance, InstanceID);
  8448.     SpeedCheatReset();
  8449.     ForceZoneUpdate();
  8450.     return true;
  8451. }
  8452.  
  8453. void Player::ForceZoneUpdate()
  8454. {
  8455.     if(!GetMapMgr()) return;
  8456.  
  8457.     uint16 areaId = GetMapMgr()->GetAreaID(GetPositionX(), GetPositionY());
  8458.     AreaTable* at = dbcArea.LookupEntryForced(areaId);
  8459.     if(!at) return;
  8460.  
  8461.     if(at->ZoneId && at->ZoneId != m_zoneId)
  8462.         ZoneUpdate(at->ZoneId);
  8463.  
  8464.     SendInitialWorldstates();
  8465. }
  8466.  
  8467. void Player::SafeTeleport(MapMgr* mgr, const LocationVector & vec)
  8468. {
  8469.     if(mgr ==  NULL)
  8470.         return;
  8471.  
  8472.     SpeedCheatDelay(10000);
  8473.  
  8474.     if(flying_aura && ((m_mapId != 530) && (m_mapId != 571 || !HasSpellwithNameHash(SPELL_HASH_COLD_WEATHER_FLYING))))
  8475.         // can only fly in outlands or northrend (northrend requires cold weather flying)
  8476.     {
  8477.         RemoveAura(flying_aura);
  8478.         flying_aura = 0;
  8479.     }
  8480.  
  8481.     if(IsInWorld())
  8482.         RemoveFromWorld();
  8483.  
  8484.     m_mapId = mgr->GetMapId();
  8485.     m_instanceId = mgr->GetInstanceID();
  8486.     WorldPacket data(SMSG_TRANSFER_PENDING, 20);
  8487.     data << mgr->GetMapId();
  8488.     GetSession()->SendPacket(&data);
  8489.  
  8490.     data.Initialize(SMSG_NEW_WORLD);
  8491.     data << mgr->GetMapId() << vec << vec.o;
  8492.     GetSession()->SendPacket(&data);
  8493.  
  8494.     SetPlayerStatus(TRANSFER_PENDING);
  8495.     m_sentTeleportPosition = vec;
  8496.     SetPosition(vec);
  8497.     SpeedCheatReset();
  8498.     ForceZoneUpdate();
  8499. }
  8500.  
  8501. void Player::SetGuildId(uint32 guildId)
  8502. {
  8503.     if(IsInWorld())
  8504.     {
  8505.         const uint32 field = PLAYER_GUILDID;
  8506.         sEventMgr.AddEvent(TO_OBJECT(this), &Object::SetUInt32Value, field, guildId, EVENT_PLAYER_SEND_PACKET, 1,
  8507.                            1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
  8508.     }
  8509.     else
  8510.     {
  8511.         SetUInt32Value(PLAYER_GUILDID, guildId);
  8512.     }
  8513. }
  8514.  
  8515. void Player::SetGuildRank(uint32 guildRank)
  8516. {
  8517.     if(IsInWorld())
  8518.     {
  8519.         const uint32 field = PLAYER_GUILDRANK;
  8520.         sEventMgr.AddEvent(TO_OBJECT(this), &Object::SetUInt32Value, field, guildRank, EVENT_PLAYER_SEND_PACKET, 1,
  8521.                            1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
  8522.     }
  8523.     else
  8524.     {
  8525.         SetUInt32Value(PLAYER_GUILDRANK, guildRank);
  8526.     }
  8527. }
  8528.  
  8529. void Player::UpdatePvPArea()
  8530. {
  8531.     AreaTable* at = dbcArea.LookupEntryForced(m_AreaID);
  8532.     if(at == NULL)
  8533.         return;
  8534.  
  8535. #ifdef PVP_REALM_MEANS_CONSTANT_PVP
  8536.     //zack : This might be huge crap. I have no idea how it is on blizz but i think a pvp realm should alow me to gank anybody anywhere :(
  8537.     if(sWorld.GetRealmType() == REALM_PVP)
  8538.     {
  8539.         SetPvPFlag();
  8540.         return;
  8541.     }
  8542. #endif
  8543.  
  8544.     if(HasFlag(PLAYER_FLAGS, PLAYER_FLAG_GM))
  8545.     {
  8546.         if(IsPvPFlagged())
  8547.             RemovePvPFlag();
  8548.         else
  8549.             StopPvPTimer();
  8550.         RemoveFFAPvPFlag();
  8551.         return;
  8552.     }
  8553.  
  8554.     // This is where all the magic happens :P
  8555.     if((at->category == AREAC_ALLIANCE_TERRITORY && IsTeamAlliance()) || (at->category == AREAC_HORDE_TERRITORY && IsTeamHorde()))
  8556.     {
  8557.         if(!HasFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP_TOGGLE) && !m_pvpTimer)
  8558.         {
  8559.             // I'm flagged and I just walked into a zone of my type. Start the 5min counter.
  8560.             ResetPvPTimer();
  8561.         }
  8562.         return;
  8563.     }
  8564.     else
  8565.     {
  8566.         //Enemy city check
  8567.         if(at->AreaFlags & AREA_CITY_AREA || at->AreaFlags & AREA_CITY)
  8568.         {
  8569.             if((at->category == AREAC_ALLIANCE_TERRITORY && IsTeamHorde()) || (at->category == AREAC_HORDE_TERRITORY && IsTeamAlliance()))
  8570.             {
  8571.                 if(!IsPvPFlagged())
  8572.                     SetPvPFlag();
  8573.                 else
  8574.                     StopPvPTimer();
  8575.                 return;
  8576.             }
  8577.         }
  8578.  
  8579.         //fix for zone areas.
  8580.         if(at->ZoneId)
  8581.         {
  8582.             AreaTable* at2 = dbcArea.LookupEntryForced(at->ZoneId);
  8583.             if(at2 && ((at2->category == AREAC_ALLIANCE_TERRITORY && IsTeamAlliance()) || (at2->category == AREAC_HORDE_TERRITORY && IsTeamHorde())))
  8584.             {
  8585.                 if(!HasFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP_TOGGLE) && !m_pvpTimer)
  8586.                 {
  8587.                     // I'm flagged and I just walked into a zone of my type. Start the 5min counter.
  8588.                     ResetPvPTimer();
  8589.                 }
  8590.                 return;
  8591.             }
  8592.             //enemy territory check
  8593.             if(at2 && (at2->AreaFlags & AREA_CITY_AREA || at2->AreaFlags & AREA_CITY))
  8594.             {
  8595.                 if((at2->category == AREAC_ALLIANCE_TERRITORY && IsTeamHorde()) || (at2->category == AREAC_HORDE_TERRITORY && IsTeamAlliance()))
  8596.                 {
  8597.                     if(!IsPvPFlagged())
  8598.                         SetPvPFlag();
  8599.                     else
  8600.                         StopPvPTimer();
  8601.                     return;
  8602.                 }
  8603.             }
  8604.         }
  8605.  
  8606.         // I just walked into a sanctuary area
  8607.         // Force remove flag me if I'm not already.
  8608.         if(at->category == AREAC_SANCTUARY || at->AreaFlags & AREA_SANCTUARY)
  8609.         {
  8610.             if(IsPvPFlagged())
  8611.                 RemovePvPFlag();
  8612.             else
  8613.                 StopPvPTimer();
  8614.  
  8615.             RemoveFFAPvPFlag();
  8616.             SetSanctuaryFlag();
  8617.         }
  8618.         else
  8619.         {
  8620.             // if we are not in a sanctuary we don't need this flag
  8621.             RemoveSanctuaryFlag();
  8622.  
  8623.             //contested territory
  8624.             if(sWorld.GetRealmType() == REALM_PVP)
  8625.             {
  8626.                 //automatically sets pvp flag on contested territories.
  8627.                 if(!IsPvPFlagged())
  8628.                     SetPvPFlag();
  8629.                 else
  8630.                     StopPvPTimer();
  8631.             }
  8632.  
  8633.             if(sWorld.GetRealmType() == REALM_PVE)
  8634.             {
  8635.                 if(HasFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP_TOGGLE))
  8636.                 {
  8637.                     if(!IsPvPFlagged())
  8638.                         SetPvPFlag();
  8639.                 }
  8640.                 else if(!HasFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP_TOGGLE) && IsPvPFlagged() && !m_pvpTimer)
  8641.                 {
  8642.                     ResetPvPTimer();
  8643.                 }
  8644.             }
  8645.  
  8646.             if(at->AreaFlags & AREA_PVP_ARENA)          /* ffa pvp arenas will come later */
  8647.             {
  8648.                 if(!IsPvPFlagged())
  8649.                     SetPvPFlag();
  8650.                 SetFFAPvPFlag();
  8651.             }
  8652.             else
  8653.             {
  8654.                 RemoveFFAPvPFlag();
  8655.             }
  8656.         }
  8657.     }
  8658. }
  8659.  
  8660. void Player::BuildFlagUpdateForNonGroupSet(uint32 index, uint32 flag)
  8661. {
  8662.     Object* curObj;
  8663.     for(Object::InRangeSet::iterator iter = m_objectsInRange.begin(); iter != m_objectsInRange.end();)
  8664.     {
  8665.         curObj = *iter;
  8666.         iter++;
  8667.         if(curObj->IsPlayer())
  8668.         {
  8669.             Group* pGroup = TO< Player* >(curObj)->GetGroup();
  8670.             if(!pGroup && pGroup != GetGroup())
  8671.             {
  8672.                 BuildFieldUpdatePacket(TO< Player* >(curObj), index, flag);
  8673.             }
  8674.         }
  8675.     }
  8676. }
  8677.  
  8678. void Player::LoginPvPSetup()
  8679. {
  8680.     // Make sure we know our area ID.
  8681.     _EventExploration();
  8682.  
  8683.     AreaTable* at = dbcArea.LookupEntryForced((m_AreaID != 0) ? m_AreaID : m_zoneId);
  8684.  
  8685.     if(at != NULL && isAlive() && (at->category == AREAC_CONTESTED || (IsTeamAlliance() && at->category == AREAC_HORDE_TERRITORY) || (IsTeamHorde() && at->category == AREAC_ALLIANCE_TERRITORY)))
  8686.         CastSpell(this, PLAYER_HONORLESS_TARGET_SPELL, true);
  8687.  
  8688. #ifdef PVP_REALM_MEANS_CONSTANT_PVP
  8689.     //zack : This might be huge crap. I have no idea how it is on blizz but i think a pvp realm should allow me to gank anybody anywhere :(
  8690.     if(sWorld.GetRealmType() == REALM_PVP)
  8691.     {
  8692.         SetPvPFlag();
  8693.         return;
  8694.     }
  8695. #endif
  8696. }
  8697.  
  8698. void Player::PvPToggle()
  8699. {
  8700.     if(sWorld.GetRealmType() == REALM_PVE)
  8701.     {
  8702.         if(m_pvpTimer > 0)
  8703.         {
  8704.             // Means that we typed /pvp while we were "cooling down". Stop the timer.
  8705.             StopPvPTimer();
  8706.  
  8707.             SetFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP_TOGGLE);
  8708.             RemoveFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP);
  8709.  
  8710.             if(!IsPvPFlagged())
  8711.                 SetPvPFlag();
  8712.         }
  8713.         else
  8714.         {
  8715.             if(IsPvPFlagged())
  8716.             {
  8717.                 AreaTable* at = dbcArea.LookupEntryForced(m_AreaID);
  8718.                 if(at && (at->AreaFlags & AREA_CITY_AREA || at->AreaFlags & AREA_CITY))
  8719.                 {
  8720.                     if((at->category == AREAC_ALLIANCE_TERRITORY && IsTeamHorde()) || (at->category == AREAC_HORDE_TERRITORY && IsTeamAlliance()))
  8721.                     {
  8722.                     }
  8723.                     else
  8724.                     {
  8725.                         // Start the "cooldown" timer.
  8726.                         ResetPvPTimer();
  8727.                     }
  8728.                 }
  8729.                 else
  8730.                 {
  8731.                     // Start the "cooldown" timer.
  8732.                     ResetPvPTimer();
  8733.                 }
  8734.                 RemoveFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP_TOGGLE);
  8735.                 SetFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP);
  8736.             }
  8737.             else
  8738.             {
  8739.                 // Move into PvP state.
  8740.                 SetFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP_TOGGLE);
  8741.                 RemoveFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP);
  8742.  
  8743.                 StopPvPTimer();
  8744.                 SetPvPFlag();
  8745.             }
  8746.         }
  8747.     }
  8748. #ifdef PVP_REALM_MEANS_CONSTANT_PVP
  8749.     //zack : This might be huge crap. I have no idea how it is on blizz but i think a pvp realm should allow me to gank anybody anywhere :(
  8750.     else if(sWorld.GetRealmType() == REALM_PVP)
  8751.     {
  8752.         SetPvPFlag();
  8753.         return;
  8754.     }
  8755. #else
  8756.     else if(sWorld.GetRealmType() == REALM_PVP)
  8757.     {
  8758.         AreaTable* at = dbcArea.LookupEntryForced(m_AreaID);
  8759.         if(at == NULL)
  8760.             return;
  8761.  
  8762.         // This is where all the magic happens :P
  8763.         if((at->category == AREAC_ALLIANCE_TERRITORY && IsTeamAlliance()) || (at->category == AREAC_HORDE_TERRITORY && IsTeamHorde()))
  8764.         {
  8765.             if(m_pvpTimer > 0)
  8766.             {
  8767.                 // Means that we typed /pvp while we were "cooling down". Stop the timer.
  8768.                 StopPvPTimer();
  8769.  
  8770.                 SetFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP_TOGGLE);
  8771.                 RemoveFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP);
  8772.  
  8773.                 if(!IsPvPFlagged())
  8774.                     SetPvPFlag();
  8775.             }
  8776.             else
  8777.             {
  8778.                 if(IsPvPFlagged())
  8779.                 {
  8780.                     // Start the "cooldown" timer.
  8781.                     ResetPvPTimer();
  8782.  
  8783.                     RemoveFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP_TOGGLE);
  8784.                     SetFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP);
  8785.                 }
  8786.                 else
  8787.                 {
  8788.                     // Move into PvP state.
  8789.                     SetFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP_TOGGLE);
  8790.                     RemoveFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP);
  8791.  
  8792.                     StopPvPTimer();
  8793.                     SetPvPFlag();
  8794.                 }
  8795.             }
  8796.         }
  8797.         else
  8798.         {
  8799.             if(at->ZoneId)
  8800.             {
  8801.                 AreaTable* at2 = dbcArea.LookupEntryForced(at->ZoneId);
  8802.                 if(at2 && ((at2->category == AREAC_ALLIANCE_TERRITORY && IsTeamAlliance()) || (at2->category == AREAC_HORDE_TERRITORY && IsTeamHorde())))
  8803.                 {
  8804.                     if(m_pvpTimer > 0)
  8805.                     {
  8806.                         // Means that we typed /pvp while we were "cooling down". Stop the timer.
  8807.                         StopPvPTimer();
  8808.  
  8809.                         SetFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP_TOGGLE);
  8810.                         RemoveFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP);
  8811.  
  8812.                         if(!IsPvPFlagged())
  8813.                             SetPvPFlag();
  8814.                     }
  8815.                     else
  8816.                     {
  8817.                         if(IsPvPFlagged())
  8818.                         {
  8819.                             // Start the "cooldown" timer.
  8820.                             ResetPvPTimer();
  8821.  
  8822.                             RemoveFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP_TOGGLE);
  8823.                             SetFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP);
  8824.  
  8825.                         }
  8826.                         else
  8827.                         {
  8828.                             // Move into PvP state.
  8829.                             SetFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP_TOGGLE);
  8830.                             RemoveFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP);
  8831.  
  8832.                             StopPvPTimer();
  8833.                             SetPvPFlag();
  8834.                         }
  8835.                     }
  8836.                     return;
  8837.                 }
  8838.             }
  8839.  
  8840.             if(!HasFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP_TOGGLE))
  8841.             {
  8842.                 SetFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP_TOGGLE);
  8843.                 RemoveFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP);
  8844.             }
  8845.             else
  8846.             {
  8847.                 RemoveFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP_TOGGLE);
  8848.                 SetFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP);
  8849.             }
  8850.         }
  8851.     }
  8852. #endif
  8853. }
  8854.  
  8855. void Player::ResetPvPTimer()
  8856. {
  8857.     m_pvpTimer = sWorld.getIntRate(INTRATE_PVPTIMER);
  8858. }
  8859.  
  8860. void Player::CalculateBaseStats()
  8861. {
  8862.     if(!lvlinfo) return;
  8863.  
  8864.     memcpy(BaseStats, lvlinfo->Stat, sizeof(uint32) * 5);
  8865.  
  8866.     LevelInfo* levelone = objmgr.GetLevelInfo(this->getRace(), this->getClass(), 1);
  8867.     if(levelone == NULL)
  8868.     {
  8869.         LOG_ERROR("%s (%d): NULL pointer", __FUNCTION__, __LINE__);
  8870.         return;
  8871.     }
  8872.     SetMaxHealth(lvlinfo->HP);
  8873.     SetBaseHealth(lvlinfo->HP - (lvlinfo->Stat[2] - levelone->Stat[2]) * 10);
  8874.     SetNextLevelXp(lvlinfo->XPToNextLevel);
  8875.  
  8876.  
  8877.     if(GetPowerType() == POWER_TYPE_MANA)
  8878.     {
  8879.         SetBaseMana(lvlinfo->Mana - (lvlinfo->Stat[3] - levelone->Stat[3]) * 15);
  8880.         SetMaxPower(POWER_TYPE_MANA, lvlinfo->Mana);
  8881.     }
  8882. }
  8883.  
  8884. void Player::CompleteLoading()
  8885. {
  8886.     // cast passive initial spells    -- grep note: these shouldn't require plyr to be in world
  8887.     SpellSet::iterator itr;
  8888.     SpellEntry* info;
  8889.     SpellCastTargets targets;
  8890.     targets.m_unitTarget = this->GetGUID();
  8891.     targets.m_targetMask = TARGET_FLAG_UNIT;
  8892.  
  8893.     // warrior has to have battle stance
  8894.     if(getClass() == WARRIOR)
  8895.     {
  8896.         // battle stance passive
  8897.         CastSpell(this, dbcSpell.LookupEntry(2457), true);
  8898.     }
  8899.  
  8900.  
  8901.     for(itr = mSpells.begin(); itr != mSpells.end(); ++itr)
  8902.     {
  8903.         info = dbcSpell.LookupEntryForced(*itr);
  8904.  
  8905.         if(info != NULL
  8906.                 && (info->Attributes & ATTRIBUTES_PASSIVE)  // passive
  8907.                 && !(info->c_is_flags & SPELL_FLAG_IS_EXPIREING_WITH_PET)   //on pet summon talents
  8908.           )
  8909.         {
  8910.             if(info->RequiredShapeShift)
  8911.             {
  8912.                 if(!(((uint32)1 << (GetShapeShift() - 1)) & info->RequiredShapeShift))
  8913.                     continue;
  8914.             }
  8915.  
  8916.             Spell* spell = sSpellFactoryMgr.NewSpell(this, info, true, NULL);
  8917.             spell->prepare(&targets);
  8918.         }
  8919.     }
  8920.  
  8921.     std::list<LoginAura>::iterator i =  loginauras.begin();
  8922.  
  8923.     for(; i != loginauras.end(); ++i)
  8924.     {
  8925.  
  8926.         //check if we already have this aura
  8927. //      if(this->HasActiveAura((*i).id))
  8928. //          continue;
  8929.         //how many times do we intend to put this aura on us
  8930.         /*      uint32 count_appearence= 0;
  8931.                 std::list<LoginAura>::iterator i2 =  i;
  8932.                 for(;i2!=loginauras.end();i2++)
  8933.                     if((*i).id==(*i2).id)
  8934.                     {
  8935.                         count_appearence++;
  8936.                     }
  8937.         */
  8938.         SpellEntry* sp = dbcSpell.LookupEntry((*i).id);
  8939.  
  8940.         if(sp->c_is_flags & SPELL_FLAG_IS_EXPIREING_WITH_PET)
  8941.             continue; //do not load auras that only exist while pet exist. We should recast these when pet is created anyway
  8942.  
  8943.         Aura* aura = sSpellFactoryMgr.NewAura(sp, (*i).dur, this, this, false);
  8944.         //if ( !(*i).positive ) // do we need this? - vojta
  8945.         //  aura->SetNegative();
  8946.  
  8947.         for(uint32 x = 0; x < 3; x++)
  8948.         {
  8949.             if(sp->Effect[x] == SPELL_EFFECT_APPLY_AURA)
  8950.             {
  8951.                 aura->AddMod(sp->EffectApplyAuraName[x], sp->EffectBasePoints[x] + 1, sp->EffectMiscValue[x], x);
  8952.             }
  8953.         }
  8954.  
  8955.         if(sp->procCharges > 0 && (*i).charges > 0)
  8956.         {
  8957.             for(uint32 x = 0; x < (*i).charges - 1; x++)
  8958.             {
  8959.                 Aura* a = sSpellFactoryMgr.NewAura(sp, (*i).dur, this, this, false);
  8960.                 this->AddAura(a);
  8961.             }
  8962.             if(m_chargeSpells.find(sp->Id) == m_chargeSpells.end() && !(sp->procFlags & PROC_REMOVEONUSE))
  8963.             {
  8964.                 SpellCharge charge;
  8965.                 if(sp->proc_interval == 0)
  8966.                     charge.count = (*i).charges;
  8967.                 else
  8968.                     charge.count = sp->procCharges;
  8969.                 charge.spellId = sp->Id;
  8970.                 charge.ProcFlag = sp->procFlags;
  8971.                 charge.lastproc = 0;
  8972.                 charge.procdiff = 0;
  8973.                 m_chargeSpells.insert(make_pair(sp->Id , charge));
  8974.             }
  8975.         }
  8976.         this->AddAura(aura);
  8977.         //Somehow we should restore number of appearance. Right now I have no idea how :(
  8978. //      if(count_appearence>1)
  8979. //          this->AddAuraVisual((*i).id,count_appearence-1,a->IsPositive());
  8980.     }
  8981.  
  8982.     // this needs to be after the cast of passive spells, because it will cast ghost form, after the remove making it in ghost alive, if no corpse.
  8983.     //death system checkout
  8984.     if(GetHealth() <= 0 && !HasFlag(PLAYER_FLAGS, PLAYER_FLAG_DEATH_WORLD_ENABLE))
  8985.     {
  8986.         setDeathState(CORPSE);
  8987.     }
  8988.     else if(HasFlag(PLAYER_FLAGS, PLAYER_FLAG_DEATH_WORLD_ENABLE))
  8989.     {
  8990.         // Check if we have an existing corpse.
  8991.         Corpse* corpse = objmgr.GetCorpseByOwner(GetLowGUID());
  8992.         if(corpse == NULL)
  8993.         {
  8994.             sEventMgr.AddEvent(this, &Player::RepopAtGraveyard, GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId(), EVENT_PLAYER_CHECKFORCHEATS, 1000, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
  8995.         }
  8996.         else
  8997.         {
  8998.             // Set proper deathstate
  8999.             setDeathState(CORPSE);
  9000.         }
  9001.     }
  9002.  
  9003.     if(IsDead())
  9004.     {
  9005.         if(myCorpseInstanceId != 0)
  9006.         {
  9007.             // cebernic: tempfix. This send a counter for player with just logging in.
  9008.             // TODO: counter will be follow with death time.
  9009.             Corpse* myCorpse = objmgr.GetCorpseByOwner(GetLowGUID());
  9010.             if(myCorpse != NULL)
  9011.                 myCorpse->ResetDeathClock();
  9012.             WorldPacket SendCounter(SMSG_CORPSE_RECLAIM_DELAY, 4);
  9013.             SendCounter << (uint32)(CORPSE_RECLAIM_TIME_MS);
  9014.             GetSession()->SendPacket(&SendCounter);
  9015.         }
  9016.         //RepopRequestedPlayer();
  9017.         //sEventMgr.AddEvent(this, &Player::RepopRequestedPlayer, EVENT_PLAYER_CHECKFORCHEATS, 2000, 1,EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
  9018.     }
  9019.  
  9020.     if(!IsMounted())
  9021.         SpawnActivePet();
  9022.  
  9023.     // useless logon spell
  9024.     Spell* logonspell = sSpellFactoryMgr.NewSpell(this, dbcSpell.LookupEntry(836), false, NULL);
  9025.     logonspell->prepare(&targets);
  9026.  
  9027.     // Banned
  9028.     if(IsBanned())
  9029.     {
  9030.         Kick(10000);
  9031.         BroadcastMessage("This character is not allowed to play.");
  9032.         BroadcastMessage("You have been banned for: %s", GetBanReason().c_str());
  9033.     }
  9034.  
  9035.     if(m_playerInfo->m_Group)
  9036.     {
  9037.         sEventMgr.AddEvent(this, &Player::EventGroupFullUpdate, EVENT_UNK, 100, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
  9038.  
  9039.         //m_playerInfo->m_Group->Update();
  9040.     }
  9041.  
  9042.     if(raidgrouponlysent)
  9043.     {
  9044.         WorldPacket data2(SMSG_RAID_GROUP_ONLY, 8);
  9045.         data2 << uint32(0xFFFFFFFF) << uint32(0);
  9046.         GetSession()->SendPacket(&data2);
  9047.         raidgrouponlysent = false;
  9048.     }
  9049.  
  9050.     sInstanceMgr.BuildSavedInstancesForPlayer(this);
  9051.     CombatStatus.UpdateFlag();
  9052.     // add glyphs
  9053.     for(uint8 j = 0; j < GLYPHS_COUNT; ++j)
  9054.     {
  9055.         GlyphPropertyEntry* glyph = dbcGlyphProperty.LookupEntryForced(m_specs[m_talentActiveSpec].glyphs[j]);
  9056.         if(glyph == NULL)
  9057.             continue;
  9058.  
  9059.         CastSpell(this, glyph->SpellID, true);
  9060.     }
  9061.     //sEventMgr.AddEvent(this,&Player::SendAllAchievementData,EVENT_SEND_ACHIEVEMNTS_TO_PLAYER,ACHIEVEMENT_SEND_DELAY,1,0);
  9062.     sEventMgr.AddEvent(TO< Unit* >(this), &Unit::UpdatePowerAmm, EVENT_SEND_PACKET_TO_PLAYER_AFTER_LOGIN, LOGIN_CIENT_SEND_DELAY, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
  9063. }
  9064.  
  9065. void Player::OnWorldPortAck()
  9066. {
  9067.     //only resurrect if player is porting to a instance portal
  9068.     MapInfo* pMapinfo = WorldMapInfoStorage.LookupEntry(GetMapId());
  9069.     if(IsDead())
  9070.     {
  9071.         if(pMapinfo)
  9072.         {
  9073.             if(pMapinfo->type != INSTANCE_NULL)
  9074.             {
  9075.                 ResurrectPlayer();
  9076.             }
  9077.         }
  9078.     }
  9079.  
  9080.     if(pMapinfo)
  9081.     {
  9082.         WorldPacket data(4);
  9083.         if(pMapinfo->HasFlag(WMI_INSTANCE_WELCOME) && GetMapMgr())
  9084.         {
  9085.             std::string welcome_msg;
  9086.             welcome_msg = string(GetSession()->LocalizedWorldSrv(62)) + " ";
  9087.             welcome_msg += string(GetSession()->LocalizedMapName(pMapinfo->mapid));
  9088.             welcome_msg += ". ";
  9089.             if(pMapinfo->type != INSTANCE_NONRAID && !(pMapinfo->type == INSTANCE_MULTIMODE && iInstanceType >= MODE_HEROIC) && m_mapMgr->pInstance)
  9090.             {
  9091.                 /*welcome_msg += "This instance is scheduled to reset on ";
  9092.                 welcome_msg += asctime(localtime(&m_mapMgr->pInstance->m_expiration));*/
  9093.                 welcome_msg += string(GetSession()->LocalizedWorldSrv(66)) + " ";
  9094.                 welcome_msg += ConvertTimeStampToDataTime((uint32)m_mapMgr->pInstance->m_expiration);
  9095.             }
  9096.             sChatHandler.SystemMessage(m_session, welcome_msg.c_str());
  9097.         }
  9098.     }
  9099.  
  9100.     SpeedCheatReset();
  9101. }
  9102.  
  9103. void Player::ModifyBonuses(uint32 type, int32 val, bool apply)
  9104. {
  9105.     // Added some updateXXXX calls so when an item modifies a stat they get updated
  9106.     // also since this is used by auras now it will handle it for those
  9107.     int32 _val = val;
  9108.     if(!apply)
  9109.         val = -val;
  9110.  
  9111.     switch(type)
  9112.     {
  9113.         case POWER:
  9114.             {
  9115.                 ModMaxPower(POWER_TYPE_MANA, val);
  9116.                 m_manafromitems += val;
  9117.             }
  9118.             break;
  9119.         case HEALTH:
  9120.             {
  9121.                 ModMaxHealth(val);
  9122.                 m_healthfromitems += val;
  9123.             }
  9124.             break;
  9125.         case AGILITY:   //modify agility
  9126.         case STRENGTH:  //modify strength
  9127.         case INTELLECT: //modify intellect
  9128.         case SPIRIT:    //modify spirit
  9129.         case STAMINA:   //modify stamina
  9130.             {
  9131.                 uint8 convert[] = {1, 0, 3, 4, 2};
  9132.                 if(_val > 0)
  9133.                     FlatStatModPos[ convert[ type - 3 ] ] += val;
  9134.                 else
  9135.                     FlatStatModNeg[ convert[ type - 3 ] ] -= val;
  9136.                 CalcStat(convert[ type - 3 ]);
  9137.             }
  9138.             break;
  9139.         case WEAPON_SKILL_RATING:
  9140.             {
  9141.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_RANGED_SKILL, val);   // ranged
  9142.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_MELEE_MAIN_HAND_SKILL, val);   // melee main hand
  9143.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_MELEE_OFF_HAND_SKILL, val);   // melee off hand
  9144.             }
  9145.             break;
  9146.         case DEFENSE_RATING:
  9147.             {
  9148.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_DEFENCE, val);
  9149.             }
  9150.             break;
  9151.         case DODGE_RATING:
  9152.             {
  9153.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_DODGE, val);
  9154.             }
  9155.             break;
  9156.         case PARRY_RATING:
  9157.             {
  9158.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_PARRY, val);
  9159.             }
  9160.             break;
  9161.         case SHIELD_BLOCK_RATING:
  9162.             {
  9163.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_BLOCK, val);
  9164.             }
  9165.             break;
  9166.         case MELEE_HIT_RATING:
  9167.             {
  9168.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_MELEE_HIT, val);
  9169.             }
  9170.             break;
  9171.         case RANGED_HIT_RATING:
  9172.             {
  9173.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_RANGED_HIT, val);
  9174.             }
  9175.             break;
  9176.         case SPELL_HIT_RATING:
  9177.             {
  9178.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_SPELL_HIT, val);
  9179.             }
  9180.             break;
  9181.         case MELEE_CRITICAL_STRIKE_RATING:
  9182.             {
  9183.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_MELEE_CRIT, val);
  9184.             }
  9185.             break;
  9186.         case RANGED_CRITICAL_STRIKE_RATING:
  9187.             {
  9188.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_RANGED_CRIT, val);
  9189.             }
  9190.             break;
  9191.         case SPELL_CRITICAL_STRIKE_RATING:
  9192.             {
  9193.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_SPELL_CRIT, val);
  9194.             }
  9195.             break;
  9196.         case MELEE_HIT_AVOIDANCE_RATING:
  9197.             {
  9198.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_MELEE_HIT_AVOIDANCE, val);
  9199.             }
  9200.             break;
  9201.         case RANGED_HIT_AVOIDANCE_RATING:
  9202.             {
  9203.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_RANGED_HIT_AVOIDANCE, val);
  9204.             }
  9205.             break;
  9206.         case SPELL_HIT_AVOIDANCE_RATING:
  9207.             {
  9208.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_SPELL_HIT_AVOIDANCE, val);
  9209.             }
  9210.             break;
  9211.         case MELEE_CRITICAL_AVOIDANCE_RATING:
  9212.             {
  9213.  
  9214.             } break;
  9215.         case RANGED_CRITICAL_AVOIDANCE_RATING:
  9216.             {
  9217.  
  9218.             } break;
  9219.         case SPELL_CRITICAL_AVOIDANCE_RATING:
  9220.             {
  9221.  
  9222.             } break;
  9223.         case MELEE_HASTE_RATING:
  9224.             {
  9225.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_MELEE_HASTE, val);  //melee
  9226.             }
  9227.             break;
  9228.         case RANGED_HASTE_RATING:
  9229.             {
  9230.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_RANGED_HASTE, val);  //ranged
  9231.             }
  9232.             break;
  9233.         case SPELL_HASTE_RATING:
  9234.             {
  9235.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_SPELL_HASTE, val);  //spell
  9236.             }
  9237.             break;
  9238.         case HIT_RATING:
  9239.             {
  9240.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_MELEE_HIT, val);  //melee
  9241.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_RANGED_HIT, val);  //ranged
  9242.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_SPELL_HIT, val);   //Spell
  9243.             }
  9244.             break;
  9245.         case CRITICAL_STRIKE_RATING:
  9246.             {
  9247.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_MELEE_CRIT, val);  //melee
  9248.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_RANGED_CRIT, val);  //ranged
  9249.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_SPELL_CRIT, val);   //spell
  9250.             }
  9251.             break;
  9252.         case HIT_AVOIDANCE_RATING:// this is guessed based on layout of other fields
  9253.             {
  9254.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_MELEE_HIT_AVOIDANCE, val);  //melee
  9255.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_RANGED_HIT_AVOIDANCE, val);  //ranged
  9256.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_SPELL_HIT_AVOIDANCE, val);  //spell
  9257.             }
  9258.             break;
  9259.         case CRITICAL_AVOIDANCE_RATING:
  9260.             {
  9261.  
  9262.             } break;
  9263.         case EXPERTISE_RATING:
  9264.             {
  9265.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_EXPERTISE, val);
  9266.             }
  9267.             break;
  9268.         case RESILIENCE_RATING:
  9269.             {
  9270.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_MELEE_CRIT_RESILIENCE, val);  //melee
  9271.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_RANGED_CRIT_RESILIENCE, val);  //ranged
  9272.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_SPELL_CRIT_RESILIENCE, val);  //spell
  9273.             }
  9274.             break;
  9275.         case HASTE_RATING:
  9276.             {
  9277.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_MELEE_HASTE, val);  //melee
  9278.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_RANGED_HASTE, val);  //ranged
  9279.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_SPELL_HASTE, val);   // Spell
  9280.             }
  9281.             break;
  9282.         case ATTACK_POWER:
  9283.             {
  9284.                 ModAttackPowerMods(val);
  9285.                 ModRangedAttackPowerMods(val);
  9286.             }
  9287.             break;
  9288.         case RANGED_ATTACK_POWER:
  9289.             {
  9290.                 ModRangedAttackPowerMods(val);
  9291.             }
  9292.             break;
  9293.         case FERAL_ATTACK_POWER:
  9294.             {
  9295.                 ModAttackPowerMods(val);
  9296.             }
  9297.             break;
  9298.         case SPELL_HEALING_DONE:
  9299.             {
  9300.                 for(uint8 school = 1; school < SCHOOL_COUNT; ++school)
  9301.                 {
  9302.                     HealDoneMod[school] += val;
  9303.                 }
  9304.                 ModHealingDoneMod(val);
  9305.             }
  9306.             break;
  9307.         case SPELL_DAMAGE_DONE:
  9308.             {
  9309.                 for(uint8 school = 1; school < SCHOOL_COUNT; ++school)
  9310.                 {
  9311.                     ModPosDamageDoneMod(school, val);
  9312.                 }
  9313.             }
  9314.             break;
  9315.         case MANA_REGENERATION:
  9316.             {
  9317.                 m_ModInterrMRegen += val;
  9318.             }
  9319.             break;
  9320.         case ARMOR_PENETRATION_RATING:
  9321.             {
  9322.                 ModUnsigned32Value(PLAYER_RATING_MODIFIER_ARMOR_PENETRATION_RATING, val);
  9323.             }
  9324.             break;
  9325.         case SPELL_POWER:
  9326.             {
  9327.                 for(uint8 school = 1; school < 7; ++school)
  9328.                 {
  9329.                     ModPosDamageDoneMod(school, val);
  9330.                     HealDoneMod[ school ] += val;
  9331.                 }
  9332.                 ModHealingDoneMod(val);
  9333.             }
  9334.             break;
  9335.     }
  9336. }
  9337.  
  9338. bool Player::CanSignCharter(Charter* charter, Player* requester)
  9339. {
  9340.     if(charter == NULL || requester == NULL)
  9341.         return false;
  9342.     if(charter->CharterType >= CHARTER_TYPE_ARENA_2V2 && m_arenaTeams[charter->CharterType - 1] != NULL)
  9343.         return false;
  9344.  
  9345.     if(charter->CharterType == CHARTER_TYPE_GUILD && IsInGuild())
  9346.         return false;
  9347.  
  9348.     if(m_charters[charter->CharterType] || requester->GetTeam() != GetTeam() || this == requester)
  9349.         return false;
  9350.     else
  9351.         return true;
  9352. }
  9353.  
  9354. void Player::SaveAuras(stringstream & ss)
  9355. {
  9356.     uint32 charges = 0, prevX = 0;
  9357.     //cebernic: save all auras why only just positive?
  9358.     for(uint32 x = MAX_POSITIVE_AURAS_EXTEDED_START; x < MAX_NEGATIVE_AURAS_EXTEDED_END; x++)
  9359.     {
  9360.         if(m_auras[x] != NULL && m_auras[x]->GetTimeLeft() > 3000)
  9361.         {
  9362.             Aura* aur = m_auras[x];
  9363.             for(uint32 i = 0; i < 3; ++i)
  9364.             {
  9365.                 if(aur->m_spellProto->Effect[i] == SPELL_EFFECT_APPLY_GROUP_AREA_AURA || aur->m_spellProto->Effect[i] == SPELL_EFFECT_APPLY_RAID_AREA_AURA || aur->m_spellProto->Effect[i] == SPELL_EFFECT_ADD_FARSIGHT)
  9366.                 {
  9367.                     continue;
  9368.                     break;
  9369.                 }
  9370.             }
  9371.  
  9372.             if(aur->pSpellId)
  9373.                 continue; //these auras were gained due to some proc. We do not save these either to avoid exploits of not removing them
  9374.  
  9375.             if(aur->m_spellProto->c_is_flags & SPELL_FLAG_IS_EXPIREING_WITH_PET)
  9376.                 continue;
  9377.  
  9378.             //we are going to cast passive spells anyway on login so no need to save auras for them
  9379.             if(aur->IsPassive() && !(aur->GetSpellProto()->AttributesEx & 1024))
  9380.                 continue;
  9381.  
  9382.             if(charges > 0 && aur->GetSpellId() != m_auras[prevX]->GetSpellId())
  9383.             {
  9384.                 ss << m_auras[prevX]->GetSpellId() << "," << m_auras[prevX]->GetTimeLeft() << "," << m_auras[prevX]->IsPositive() << "," << charges << ",";
  9385.                 charges = 0;
  9386.             }
  9387.  
  9388.             if(aur->GetSpellProto()->procCharges == 0)
  9389.                 ss << aur->GetSpellId() << "," << aur->GetTimeLeft() << "," << aur->IsPositive() << "," << 0 << ",";
  9390.             else
  9391.                 charges++;
  9392.  
  9393.             prevX = x;
  9394.         }
  9395.     }
  9396.     if(charges > 0 && m_auras[prevX] != NULL)
  9397.     {
  9398.         ss << m_auras[prevX]->GetSpellId() << "," << m_auras[prevX]->GetTimeLeft() << "," << m_auras[prevX]->IsPositive() << "," << charges << ",";
  9399.     }
  9400. }
  9401.  
  9402. void Player::SetShapeShift(uint8 ss)
  9403. {
  9404.     uint8 old_ss = GetShapeShift(); //GetByte( UNIT_FIELD_BYTES_2, 3 );
  9405.     SetByte(UNIT_FIELD_BYTES_2, 3, ss);
  9406.  
  9407.     //remove auras that we should not have
  9408.     for(uint32 x = MAX_TOTAL_AURAS_START; x < MAX_TOTAL_AURAS_END; x++)
  9409.     {
  9410.         if(m_auras[x] != NULL)
  9411.         {
  9412.             uint32 reqss = m_auras[x]->GetSpellProto()->RequiredShapeShift;
  9413.             if(reqss != 0 && m_auras[x]->IsPositive())
  9414.             {
  9415.                 if(old_ss > 0
  9416.                         && old_ss != FORM_SHADOW
  9417.                         && old_ss != FORM_STEALTH
  9418.                   ) // 28 = FORM_SHADOW - Didn't find any aura that required this form
  9419.                     // not sure why all priest spell proto's RequiredShapeShift are set [to 134217728]
  9420.                 {
  9421.                     if((((uint32)1 << (old_ss - 1)) & reqss) &&     // we were in the form that required it
  9422.                             !(((uint32)1 << (ss - 1) & reqss)))         // new form doesn't have the right form
  9423.                     {
  9424.                         m_auras[x]->Remove();
  9425.                         continue;
  9426.                     }
  9427.                 }
  9428.             }
  9429.  
  9430.             if(this->getClass() == DRUID)
  9431.             {
  9432.                 switch(m_auras[x]->GetSpellProto()->MechanicsType)
  9433.                 {
  9434.                     case MECHANIC_ROOTED: //Rooted
  9435.                     case MECHANIC_ENSNARED: //Movement speed
  9436.                     case MECHANIC_POLYMORPHED:  //Polymorphed
  9437.                         {
  9438.                             m_auras[x]->Remove();
  9439.                         }
  9440.                         break;
  9441.                     default:
  9442.                         break;
  9443.                 }
  9444.  
  9445.                 /*Shady: is this check necessary? anyway m_auras[x]!= NULL check already done in next iteration. Commented*/
  9446.                 //if( m_auras[x] == NULL )
  9447.                 //  break;
  9448.             }
  9449.         }
  9450.     }
  9451.  
  9452.     // apply any talents/spells we have that apply only in this form.
  9453.     set<uint32>::iterator itr;
  9454.     SpellEntry* sp;
  9455.     Spell* spe;
  9456.     SpellCastTargets t(GetGUID());
  9457.  
  9458.     for(itr = mSpells.begin(); itr != mSpells.end(); ++itr)
  9459.     {
  9460.         sp = dbcSpell.LookupEntry(*itr);
  9461.         if(sp->apply_on_shapeshift_change || sp->Attributes & 64)       // passive/talent
  9462.         {
  9463.             if(sp->RequiredShapeShift && ((uint32)1 << (ss - 1)) & sp->RequiredShapeShift)
  9464.             {
  9465.                 spe = sSpellFactoryMgr.NewSpell(this, sp, true, NULL);
  9466.                 spe->prepare(&t);
  9467.             }
  9468.         }
  9469.     }
  9470.  
  9471.     //feral attack power
  9472.     if(this->getClass() == DRUID)
  9473.     {
  9474.         // Changed from normal to feral form
  9475.         if(!(old_ss == FORM_MOONKIN || old_ss == FORM_CAT || old_ss == FORM_BEAR || old_ss == FORM_DIREBEAR) &&
  9476.                 (ss == FORM_MOONKIN || ss == FORM_CAT || ss == FORM_BEAR || ss == FORM_DIREBEAR))
  9477.             this->ApplyFeralAttackPower(true);
  9478.         // Changed from feral to normal form
  9479.         else if((old_ss == FORM_MOONKIN || old_ss == FORM_CAT || old_ss == FORM_BEAR || old_ss == FORM_DIREBEAR) &&
  9480.                 !(ss == FORM_MOONKIN || ss == FORM_CAT || ss == FORM_BEAR || ss == FORM_DIREBEAR))
  9481.             this->ApplyFeralAttackPower(false);
  9482.     }
  9483.  
  9484.     // now dummy-handler stupid hacky fixed shapeshift spells (leader of the pack, etc)
  9485.     for(itr = mShapeShiftSpells.begin(); itr != mShapeShiftSpells.end(); ++itr)
  9486.     {
  9487.         sp = dbcSpell.LookupEntry(*itr);
  9488.         if(sp->RequiredShapeShift && ((uint32)1 << (ss - 1)) & sp->RequiredShapeShift)
  9489.         {
  9490.             spe = sSpellFactoryMgr.NewSpell(this, sp, true, NULL);
  9491.             spe->prepare(&t);
  9492.         }
  9493.     }
  9494.  
  9495.     UpdateStats();
  9496.     UpdateChances();
  9497. }
  9498.  
  9499. void Player::CalcDamage()
  9500. {
  9501.     float delta;
  9502.     float r;
  9503.     int ss = GetShapeShift();
  9504. /////////////////MAIN HAND
  9505.     float ap_bonus = GetAP() / 14000.0f;
  9506.     delta = (float)GetPosDamageDoneMod(SCHOOL_NORMAL) - (float)GetNegDamageDoneMod(SCHOOL_NORMAL);
  9507.  
  9508.     if(IsInFeralForm())
  9509.     {
  9510.         float tmp = 1; // multiplicative damage modifier
  9511.         for(map<uint32, WeaponModifier>::iterator i = damagedone.begin(); i != damagedone.end(); i++)
  9512.         {
  9513.             if(i->second.wclass == (uint32) - 1)  // applying only "any weapon" modifiers
  9514.                 tmp += i->second.value;
  9515.         }
  9516.         uint32 lev = getLevel();
  9517.         float feral_damage; // average base damage before bonuses and modifiers
  9518.         uint32 x; // itemlevel of the two hand weapon with dps equal to cat or bear dps
  9519.  
  9520.         if(ss == FORM_CAT)
  9521.         {
  9522.             if(lev < 42) x = lev - 1;
  9523.             else if(lev < 46) x = lev;
  9524.             else if(lev < 49) x = 2 * lev - 45;
  9525.             else if(lev < 60) x = lev + 4;
  9526.             else x = 64;
  9527.  
  9528.             // 3rd grade polinom for calculating blue two-handed weapon dps based on itemlevel (from Hyzenthlei)
  9529.             if(x <= 28) feral_damage = 1.563e-03f * x * x * x - 1.219e-01f * x * x + 3.802e+00f * x - 2.227e+01f;
  9530.             else if(x <= 41) feral_damage = -3.817e-03f * x * x * x + 4.015e-01f * x * x - 1.289e+01f * x + 1.530e+02f;
  9531.             else feral_damage = 1.829e-04f * x * x * x - 2.692e-02f * x * x + 2.086e+00f * x - 1.645e+01f;
  9532.  
  9533.             r = feral_damage * 0.79f + delta + ap_bonus * 1000.0f;
  9534.             r *= tmp;
  9535.             SetMinDamage(r > 0 ? r : 0);
  9536.  
  9537.             r = feral_damage * 1.21f + delta + ap_bonus * 1000.0f;
  9538.             r *= tmp;
  9539.             SetMaxDamage(r > 0 ? r : 0);
  9540.         }
  9541.         else // Bear or Dire Bear Form
  9542.         {
  9543.             if(ss == FORM_BEAR) x = lev;
  9544.             else x = lev + 5; // DIRE_BEAR dps is slightly better than bear dps
  9545.             if(x > 70) x = 70;
  9546.  
  9547.             // 3rd grade polinom for calculating green two-handed weapon dps based on itemlevel (from Hyzenthlei)
  9548.             if(x <= 30) feral_damage = 7.638e-05f * x * x * x + 1.874e-03f * x * x + 4.967e-01f * x + 1.906e+00f;
  9549.             else if(x <= 44) feral_damage = -1.412e-03f * x * x * x + 1.870e-01f * x * x - 7.046e+00f * x + 1.018e+02f;
  9550.             else feral_damage = 2.268e-04f * x * x * x - 3.704e-02f * x * x + 2.784e+00f * x - 3.616e+01f;
  9551.             feral_damage *= 2.5f; // Bear Form attack speed
  9552.  
  9553.             r = feral_damage * 0.79f + delta + ap_bonus * 2500.0f;
  9554.             r *= tmp;
  9555.             SetMinDamage(r > 0 ? r : 0);
  9556.  
  9557.             r = feral_damage * 1.21f + delta + ap_bonus * 2500.0f;
  9558.             r *= tmp;
  9559.             SetMaxDamage(r > 0 ? r : 0);
  9560.         }
  9561.  
  9562.         return;
  9563.     }
  9564.  
  9565. //////no druid ss
  9566.     uint32 speed = 2000;
  9567.     Item* it = GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_MAINHAND);
  9568.  
  9569.     if(!disarmed)
  9570.     {
  9571.         if(it)
  9572.             speed = it->GetProto()->Delay;
  9573.     }
  9574.  
  9575.     float bonus = ap_bonus * speed;
  9576.     float tmp = 1;
  9577.     map<uint32, WeaponModifier>::iterator i;
  9578.     for(i = damagedone.begin(); i != damagedone.end(); i++)
  9579.     {
  9580.         if((i->second.wclass == (uint32) - 1) || //any weapon
  9581.                 (it && ((1 << it->GetProto()->SubClass) & i->second.subclass))
  9582.           )
  9583.             tmp += i->second.value;
  9584.     }
  9585.  
  9586.     r = BaseDamage[0] + delta + bonus;
  9587.     r *= tmp;
  9588.     SetMinDamage(r > 0 ? r : 0);
  9589.  
  9590.     r = BaseDamage[1] + delta + bonus;
  9591.     r *= tmp;
  9592.     SetMaxDamage(r > 0 ? r : 0);
  9593.  
  9594.     uint32 cr = 0;
  9595.     if(it)
  9596.     {
  9597.         if(TO< Player* >(this)->m_wratings.size())
  9598.         {
  9599.             std::map<uint32, uint32>::iterator itr = m_wratings.find(it->GetProto()->SubClass);
  9600.             if(itr != m_wratings.end())
  9601.                 cr = itr->second;
  9602.         }
  9603.     }
  9604.     SetUInt32Value(PLAYER_RATING_MODIFIER_MELEE_MAIN_HAND_SKILL, cr);
  9605.     /////////////// MAIN HAND END
  9606.  
  9607.     /////////////// OFF HAND START
  9608.     cr = 0;
  9609.     it = TO< Player* >(this)->GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_OFFHAND);
  9610.     if(it)
  9611.     {
  9612.         if(!disarmed)
  9613.         {
  9614.             speed = it->GetProto()->Delay;
  9615.         }
  9616.         else speed  = 2000;
  9617.  
  9618.         bonus = ap_bonus * speed;
  9619.         i = damagedone.begin();
  9620.         tmp = 1;
  9621.         for(; i != damagedone.end(); i++)
  9622.         {
  9623.             if((i->second.wclass == (uint32) - 1) || //any weapon
  9624.                     (((1 << it->GetProto()->SubClass) & i->second.subclass))
  9625.               )
  9626.                 tmp += i->second.value;
  9627.         }
  9628.  
  9629.         r = (BaseOffhandDamage[0] + delta + bonus) * offhand_dmg_mod;
  9630.         r *= tmp;
  9631.         SetMinOffhandDamage(r > 0 ? r : 0);
  9632.         r = (BaseOffhandDamage[1] + delta + bonus) * offhand_dmg_mod;
  9633.         r *= tmp;
  9634.         SetMaxOffhandDamage(r > 0 ? r : 0);
  9635.         if(m_wratings.size())
  9636.         {
  9637.             std::map<uint32, uint32>::iterator itr = m_wratings.find(it->GetProto()->SubClass);
  9638.             if(itr != m_wratings.end())
  9639.                 cr = itr->second;
  9640.         }
  9641.     }
  9642.     SetUInt32Value(PLAYER_RATING_MODIFIER_MELEE_OFF_HAND_SKILL, cr);
  9643.  
  9644. /////////////second hand end
  9645. ///////////////////////////RANGED
  9646.     cr = 0;
  9647.     if((it = GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_RANGED)) != 0)
  9648.     {
  9649.         i = damagedone.begin();
  9650.         tmp = 1;
  9651.         for(; i != damagedone.end(); i++)
  9652.         {
  9653.             if(
  9654.                 (i->second.wclass == (uint32) - 1) || //any weapon
  9655.                 (((1 << it->GetProto()->SubClass) & i->second.subclass))
  9656.             )
  9657.             {
  9658.                 tmp += i->second.value;
  9659.             }
  9660.         }
  9661.  
  9662.         if(it->GetProto()->SubClass != 19)//wands do not have bonuses from RAP & ammo
  9663.         {
  9664. //              ap_bonus = (GetRangedAttackPower()+(int32)GetRangedAttackPowerMods())/14000.0;
  9665.             //modified by Zack : please try to use premade functions if possible to avoid forgetting stuff
  9666.             ap_bonus = GetRAP() / 14000.0f;
  9667.             bonus = ap_bonus * it->GetProto()->Delay;
  9668.  
  9669.             if(GetAmmoId() && !m_requiresNoAmmo)
  9670.             {
  9671.                 ItemPrototype* xproto = ItemPrototypeStorage.LookupEntry(GetAmmoId());
  9672.                 if(xproto)
  9673.                 {
  9674.                     bonus += ((xproto->Damage[0].Min + xproto->Damage[0].Max) * it->GetProto()->Delay) / 2000.0f;
  9675.                 }
  9676.             }
  9677.         }
  9678.         else bonus = 0;
  9679.  
  9680.         r = BaseRangedDamage[0] + delta + bonus;
  9681.         r *= tmp;
  9682.         SetMinRangedDamage(r > 0 ? r : 0);
  9683.  
  9684.         r = BaseRangedDamage[1] + delta + bonus;
  9685.         r *= tmp;
  9686.         SetMaxRangedDamage(r > 0 ? r : 0);
  9687.  
  9688.  
  9689.         if(m_wratings.size())
  9690.         {
  9691.             std::map<uint32, uint32>::iterator itr = m_wratings.find(it->GetProto()->SubClass);
  9692.             if(itr != m_wratings.end())
  9693.                 cr = itr->second;
  9694.         }
  9695.  
  9696.     }
  9697.     SetUInt32Value(PLAYER_RATING_MODIFIER_RANGED_SKILL, cr);
  9698.  
  9699. /////////////////////////////////RANGED end
  9700.     std::list<Pet*> summons = GetSummons();
  9701.     for(std::list<Pet*>::iterator itr = summons.begin(); itr != summons.end(); ++itr)
  9702.     {
  9703.         (*itr)->CalcDamage();//Re-calculate pet's too
  9704.     }
  9705. }
  9706.  
  9707. uint32 Player::GetMainMeleeDamage(uint32 AP_owerride)
  9708. {
  9709.     float r;
  9710.     int ss = GetShapeShift();
  9711. /////////////////MAIN HAND
  9712.     float ap_bonus;
  9713.     if(AP_owerride)
  9714.         ap_bonus = AP_owerride / 14000.0f;
  9715.     else
  9716.         ap_bonus = GetAP() / 14000.0f;
  9717.     if(IsInFeralForm())
  9718.     {
  9719.         if(ss == FORM_CAT)
  9720.             r = ap_bonus * 1000.0f;
  9721.         else
  9722.             r = ap_bonus * 2500.0f;
  9723.         return float2int32(r);
  9724.     }
  9725. //////no druid ss
  9726.     uint32 speed = 2000;
  9727.     Item* it = GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_MAINHAND);
  9728.     if(!disarmed)
  9729.     {
  9730.         if(it)
  9731.             speed = it->GetProto()->Delay;
  9732.     }
  9733.     r = ap_bonus * speed;
  9734.     return float2int32(r);
  9735. }
  9736.  
  9737. void Player::EventPortToGM(Player* p)
  9738. {
  9739.     SafeTeleport(p->GetMapId(), p->GetInstanceID(), p->GetPosition());
  9740. }
  9741.  
  9742. void Player::AddComboPoints(uint64 target, int8 count)
  9743. {
  9744.             // GetTimeLeft() checked in SpellAura, so we won't lose points
  9745.             RemoveAllAuraType(SPELL_AURA_RETAIN_COMBO_POINTS);
  9746.  
  9747.             if(m_comboTarget == target)
  9748.                 m_comboPoints += count;
  9749.             else
  9750.             {
  9751.                 m_comboTarget = target;
  9752.                 m_comboPoints = count;
  9753.             }
  9754.             UpdateComboPoints();
  9755. }
  9756.  
  9757. void Player::UpdateComboPoints()
  9758. {
  9759.     // fuck bytebuffers :D
  9760.     unsigned char buffer[10];
  9761.     uint16 c = 2;
  9762.  
  9763.     // check for overflow
  9764.     if(m_comboPoints > 5)
  9765.         m_comboPoints = 5;
  9766.  
  9767.     if(m_comboPoints < 0)
  9768.         m_comboPoints = 0;
  9769.  
  9770.     if(m_comboTarget != 0)
  9771.     {
  9772.         Unit* target = (m_mapMgr != NULL) ? m_mapMgr->GetUnit(m_comboTarget) : NULL;
  9773.         if(!target || target->IsDead() || GetSelection() != m_comboTarget)
  9774.         {
  9775.             buffer[0] = buffer[1] = 0;
  9776.         }
  9777.         else
  9778.         {
  9779.             c = static_cast<uint16>(FastGUIDPack(m_comboTarget, buffer, 0));
  9780.             buffer[c++] = m_comboPoints;
  9781.         }
  9782.     }
  9783.     else
  9784.         buffer[0] = buffer[1] = 0;
  9785.  
  9786.     m_session->OutPacket(SMSG_UPDATE_COMBO_POINTS, c, buffer);
  9787. }
  9788.  
  9789. void Player::SendAreaTriggerMessage(const char* message, ...)
  9790. {
  9791.     va_list ap;
  9792.     va_start(ap, message);
  9793.     char msg[500];
  9794.     vsnprintf(msg, 500, message, ap);
  9795.     va_end(ap);
  9796.  
  9797.     WorldPacket data(SMSG_AREA_TRIGGER_MESSAGE, 6 + strlen(msg));
  9798.     data << (uint32)0 << msg << (uint8)0x00;
  9799.     m_session->SendPacket(&data);
  9800. }
  9801.  
  9802. void Player::removeSoulStone()
  9803. {
  9804.     if(!this->SoulStone) return;
  9805.     uint32 sSoulStone = 0;
  9806.     switch(this->SoulStone)
  9807.     {
  9808.         case 3026:
  9809.             {
  9810.                 sSoulStone = 20707;
  9811.             }
  9812.             break;
  9813.         case 20758:
  9814.             {
  9815.                 sSoulStone = 20762;
  9816.             }
  9817.             break;
  9818.         case 20759:
  9819.             {
  9820.                 sSoulStone = 20763;
  9821.             }
  9822.             break;
  9823.         case 20760:
  9824.             {
  9825.                 sSoulStone = 20764;
  9826.             }
  9827.             break;
  9828.         case 20761:
  9829.             {
  9830.                 sSoulStone = 20765;
  9831.             }
  9832.             break;
  9833.         case 27240:
  9834.             {
  9835.                 sSoulStone = 27239;
  9836.             }
  9837.             break;
  9838.         case 47882:
  9839.             {
  9840.                 sSoulStone = 47883;
  9841.             }
  9842.             break;
  9843.     }
  9844.     this->RemoveAura(sSoulStone);
  9845.     this->SoulStone = this->SoulStoneReceiver = 0; //just incase
  9846. }
  9847.  
  9848. void Player::SoftDisconnect()
  9849. {
  9850.     sEventMgr.RemoveEvents(this, EVENT_PLAYER_SOFT_DISCONNECT);
  9851.     WorldSession* session = GetSession();
  9852.     session->LogoutPlayer(true);
  9853.     session->Disconnect();
  9854. }
  9855.  
  9856. void Player::SetNoseLevel()
  9857. {
  9858.     // Set the height of the player
  9859.     switch(getRace())
  9860.     {
  9861.         case RACE_HUMAN:
  9862.             // female
  9863.             if(getGender()) m_noseLevel = 1.72f;
  9864.             // male
  9865.             else m_noseLevel = 1.78f;
  9866.             break;
  9867.         case RACE_ORC:
  9868.             if(getGender()) m_noseLevel = 1.82f;
  9869.             else m_noseLevel = 1.98f;
  9870.             break;
  9871.         case RACE_DWARF:
  9872.             if(getGender()) m_noseLevel = 1.27f;
  9873.             else m_noseLevel = 1.4f;
  9874.             break;
  9875.         case RACE_NIGHTELF:
  9876.             if(getGender()) m_noseLevel = 1.84f;
  9877.             else m_noseLevel = 2.13f;
  9878.             break;
  9879.         case RACE_UNDEAD:
  9880.             if(getGender()) m_noseLevel = 1.61f;
  9881.             else m_noseLevel = 1.8f;
  9882.             break;
  9883.         case RACE_TAUREN:
  9884.             if(getGender()) m_noseLevel = 2.48f;
  9885.             else m_noseLevel = 2.01f;
  9886.             break;
  9887.         case RACE_GNOME:
  9888.             if(getGender()) m_noseLevel = 1.06f;
  9889.             else m_noseLevel = 1.04f;
  9890.             break;
  9891.         case RACE_TROLL:
  9892.             if(getGender()) m_noseLevel = 2.02f;
  9893.             else m_noseLevel = 1.93f;
  9894.             break;
  9895.         case RACE_BLOODELF:
  9896.             if(getGender()) m_noseLevel = 1.83f;
  9897.             else m_noseLevel = 1.93f;
  9898.             break;
  9899.         case RACE_DRAENEI:
  9900.             if(getGender()) m_noseLevel = 2.09f;
  9901.             else m_noseLevel = 2.36f;
  9902.             break;
  9903.     }
  9904. }
  9905.  
  9906. void Player::Possess(uint64 GUID, uint32 delay)
  9907. {
  9908.     if(m_CurrentCharm)
  9909.         return;
  9910.  
  9911.     Root();
  9912.  
  9913.     if(delay != 0)
  9914.     {
  9915.         sEventMgr.AddEvent(this, &Player::Possess, GUID, uint32(0), 0, delay, 1, 0);
  9916.         return;
  9917.     }
  9918.  
  9919.     Unit* pTarget = m_mapMgr->GetUnit(GUID);
  9920.     if(pTarget == NULL)
  9921.     {
  9922.         Unroot();
  9923.         return;
  9924.     }
  9925.  
  9926.     m_CurrentCharm = GUID;
  9927.     if(pTarget->IsCreature())
  9928.     {
  9929.         // unit-only stuff.
  9930.         pTarget->setAItoUse(false);
  9931.         pTarget->GetAIInterface()->StopMovement(0);
  9932.         pTarget->m_redirectSpellPackets = this;
  9933.     }
  9934.  
  9935.     m_noInterrupt++;
  9936.     SetCharmedUnitGUID(pTarget->GetGUID());
  9937.     pTarget->SetCharmedByGUID(GetGUID());
  9938.     pTarget->SetCharmTempVal(pTarget->GetFaction());
  9939.     SetFarsightTarget(pTarget->GetGUID());
  9940.     pTarget->SetFaction(GetFaction());
  9941.     pTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED_CREATURE | UNIT_FLAG_PVP_ATTACKABLE);
  9942.  
  9943.     SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOCK_PLAYER);
  9944.  
  9945.     /* send "switch mover" packet */
  9946.     WorldPacket data1(SMSG_CLIENT_CONTROL_UPDATE, 10);
  9947.     data1 << pTarget->GetNewGUID() << uint8(1);
  9948.     m_session->SendPacket(&data1);
  9949.  
  9950.     /* update target faction set */
  9951.     pTarget->UpdateOppFactionSet();
  9952.  
  9953.  
  9954.     if(!(pTarget->IsPet() && TO< Pet* >(pTarget) == GetSummon()))
  9955.     {
  9956.         WorldPacket data(SMSG_PET_SPELLS, 4 * 4 + 20);
  9957.         pTarget->BuildPetSpellList(data);
  9958.         m_session->SendPacket(&data);
  9959.     }
  9960.  
  9961. }
  9962.  
  9963. void Player::UnPossess()
  9964. {
  9965.     if(m_CurrentCharm == 0)
  9966.         return;
  9967.  
  9968.     Unit* pTarget = GetMapMgr()->GetUnit(m_CurrentCharm);
  9969.     if(!pTarget)
  9970.         return;
  9971.  
  9972.     m_CurrentCharm = 0;
  9973.  
  9974.     SpeedCheatReset();
  9975.  
  9976.     if(pTarget->IsCreature())
  9977.     {
  9978.         // unit-only stuff.
  9979.         pTarget->setAItoUse(true);
  9980.         pTarget->m_redirectSpellPackets = 0;
  9981.     }
  9982.  
  9983.     m_noInterrupt--;
  9984.     SetFarsightTarget(0);
  9985.     SetCharmedUnitGUID(0);
  9986.     pTarget->SetCharmedByGUID(0);
  9987.     SetCharmedUnitGUID(0);
  9988.  
  9989.     RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOCK_PLAYER);
  9990.     pTarget->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED_CREATURE | UNIT_FLAG_PVP_ATTACKABLE);
  9991.     pTarget->SetFaction(pTarget->GetCharmTempVal());
  9992.     pTarget->UpdateOppFactionSet();
  9993.  
  9994.     /* send "switch mover" packet */
  9995.     WorldPacket data(SMSG_CLIENT_CONTROL_UPDATE, 10);
  9996.     data << pTarget->GetNewGUID() << uint8(0);
  9997.     m_session->SendPacket(&data);
  9998.  
  9999.     if(!(pTarget->IsPet() && TO< Pet* >(pTarget) == GetSummon()))
  10000.         SendEmptyPetSpellList();
  10001.  
  10002.     Unroot();
  10003.  
  10004.     if(!pTarget->IsPet() && (pTarget->GetCreatedByGUID() == GetGUID()))
  10005.     {
  10006.         sEventMgr.AddEvent(TO< Object* >(pTarget), &Object::Delete, 0, 1, 1, 0);
  10007.         return;
  10008.     }
  10009. }
  10010.  
  10011. void Player::SummonRequest(uint32 Requestor, uint32 ZoneID, uint32 MapID, uint32 InstanceID, const LocationVector & Position)
  10012. {
  10013.     m_summonInstanceId = InstanceID;
  10014.     m_summonPos = Position;
  10015.     m_summoner = Requestor;
  10016.     m_summonMapId = MapID;
  10017.  
  10018.     WorldPacket data(SMSG_SUMMON_REQUEST, 16);
  10019.     data << uint64(Requestor) << ZoneID << uint32(120000);      // 2 minutes
  10020.     m_session->SendPacket(&data);
  10021. }
  10022.  
  10023. void Player::RemoveFromBattlegroundQueue()
  10024. {
  10025.     if(!m_pendingBattleground)
  10026.         return;
  10027.  
  10028.     m_pendingBattleground->RemovePendingPlayer(this);
  10029.     sChatHandler.SystemMessage(m_session, "You were removed from the queue for the battleground for not joining after 1 minute 20 seconds.");
  10030. }
  10031.  
  10032. void Player::_AddSkillLine(uint32 SkillLine, uint32 Curr_sk, uint32 Max_sk)
  10033. {
  10034.     skilllineentry* CheckedSkill = dbcSkillLine.LookupEntryForced(SkillLine);
  10035.     if(!CheckedSkill)  //skill doesn't exist, exit here
  10036.         return;
  10037.  
  10038.     // force to be within limits
  10039.  
  10040. #if PLAYER_LEVEL_CAP==250
  10041.     Curr_sk = ( Curr_sk > 1725 ? 1725 : ( Curr_sk < 1 ? 1 : Curr_sk ) );
  10042.     Max_sk = ( Max_sk > 1725 ? 1725 : Max_sk );
  10043. #else
  10044.     Curr_sk = ( Curr_sk > 1725 ? 1725 : ( Curr_sk < 1 ? 1 : Curr_sk ) );
  10045.     Max_sk = ( Max_sk > 1725 ? 1725 : Max_sk );
  10046.  
  10047.     ItemProf* prof;
  10048.     SkillMap::iterator itr = m_skills.find(SkillLine);
  10049.     if(itr != m_skills.end())
  10050.     {
  10051.         if((Curr_sk > itr->second.CurrentValue && Max_sk >= itr->second.MaximumValue) || (Curr_sk == itr->second.CurrentValue && Max_sk > itr->second.MaximumValue))
  10052.         {
  10053.             itr->second.CurrentValue = Curr_sk;
  10054.             itr->second.MaximumValue = Max_sk;
  10055.             _UpdateMaxSkillCounts();
  10056.         }
  10057.     }
  10058.     else
  10059.     {
  10060.         PlayerSkill inf;
  10061.         inf.Skill = CheckedSkill;
  10062.         inf.MaximumValue = Max_sk;
  10063.         inf.CurrentValue = (inf.Skill->id != SKILL_RIDING ? Curr_sk : Max_sk);
  10064.         inf.BonusValue = 0;
  10065.         m_skills.insert(make_pair(SkillLine, inf));
  10066.         _UpdateSkillFields();
  10067.     }
  10068.     //Add to proficiency
  10069.     if((prof = (ItemProf*)GetProficiencyBySkill(SkillLine)) != 0)
  10070.     {
  10071.         if(prof->itemclass == 4)
  10072.         {
  10073.             armor_proficiency |= prof->subclass;
  10074.             SendSetProficiency(prof->itemclass, armor_proficiency);
  10075.         }
  10076.         else
  10077.         {
  10078.             weapon_proficiency |= prof->subclass;
  10079.             SendSetProficiency(prof->itemclass, weapon_proficiency);
  10080.         }
  10081.     }
  10082.     _LearnSkillSpells(SkillLine, Curr_sk);
  10083.  
  10084.     // Displaying bug fix
  10085.     _UpdateSkillFields();
  10086. #ifdef ENABLE_ACHIEVEMENTS
  10087.     m_achievementMgr.UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL, SkillLine, Max_sk / 75, 0);
  10088.     m_achievementMgr.UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, SkillLine, Curr_sk, 0);
  10089. #endif
  10090. }
  10091.  
  10092. void Player::_UpdateSkillFields()
  10093. {
  10094.     uint32 f = PLAYER_SKILL_INFO_1_1;
  10095.     /* Set the valid skills */
  10096.     for(SkillMap::iterator itr = m_skills.begin(); itr != m_skills.end();)
  10097.     {
  10098.         if(!itr->first)
  10099.         {
  10100.             SkillMap::iterator it2 = itr++;
  10101.             m_skills.erase(it2);
  10102.             continue;
  10103.         }
  10104.  
  10105.         ARCEMU_ASSERT(f <= PLAYER_CHARACTER_POINTS1);
  10106.         if(itr->second.Skill->type == SKILL_TYPE_PROFESSION)
  10107.         {
  10108.             SetUInt32Value(f++, itr->first | 0x10000);
  10109. #ifdef ENABLE_ACHIEVEMENTS
  10110.             m_achievementMgr.UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, itr->second.Skill->id, itr->second.CurrentValue, 0);
  10111. #endif
  10112.         }
  10113.         else
  10114.         {
  10115.             SetUInt32Value(f++, itr->first);
  10116. #ifdef ENABLE_ACHIEVEMENTS
  10117.             m_achievementMgr.UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL, itr->second.Skill->id, itr->second.MaximumValue / 75, 0);
  10118. #endif
  10119.         }
  10120.  
  10121.         SetUInt32Value(f++, (itr->second.MaximumValue << 16) | itr->second.CurrentValue);
  10122.         SetUInt32Value(f++, itr->second.BonusValue);
  10123.         ++itr;
  10124.     }
  10125.  
  10126.     /* Null out the rest of the fields */
  10127.     for(; f < PLAYER_CHARACTER_POINTS1; ++f)
  10128.     {
  10129.         if(m_uint32Values[f] != 0)
  10130.             SetUInt32Value(f, 0);
  10131.     }
  10132. }
  10133.  
  10134. bool Player::_HasSkillLine(uint32 SkillLine)
  10135. {
  10136.     return (m_skills.find(SkillLine) != m_skills.end());
  10137. }
  10138.  
  10139. void Player::_AdvanceSkillLine(uint32 SkillLine, uint32 Count /* = 1 */)
  10140. {
  10141.     SkillMap::iterator itr = m_skills.find(SkillLine);
  10142.     uint32 curr_sk = Count;
  10143.     if(itr == m_skills.end())
  10144.     {
  10145.         /* Add it */
  10146.         _AddSkillLine(SkillLine, Count, getLevel() * 5);
  10147.         _UpdateMaxSkillCounts();
  10148.         sHookInterface.OnAdvanceSkillLine(this, SkillLine, Count);
  10149. #ifdef ENABLE_ACHIEVEMENTS
  10150.         m_achievementMgr.UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL, SkillLine, _GetSkillLineMax(SkillLine), 0);
  10151.         m_achievementMgr.UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, SkillLine, Count, 0);
  10152. #endif
  10153.     }
  10154.     else
  10155.     {
  10156.         curr_sk = itr->second.CurrentValue;
  10157.         itr->second.CurrentValue = min(curr_sk + Count, itr->second.MaximumValue);
  10158.         if(itr->second.CurrentValue != curr_sk)
  10159.         {
  10160.             curr_sk = itr->second.CurrentValue;
  10161.             _UpdateSkillFields();
  10162.             sHookInterface.OnAdvanceSkillLine(this, SkillLine, curr_sk);
  10163.         }
  10164. #ifdef ENABLE_ACHIEVEMENTS
  10165.         m_achievementMgr.UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL, SkillLine, itr->second.MaximumValue / 75, 0);
  10166.         m_achievementMgr.UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, SkillLine, itr->second.CurrentValue, 0);
  10167. #endif
  10168.     }
  10169.     _LearnSkillSpells(SkillLine, curr_sk);
  10170. }
  10171.  
  10172. /**
  10173.     _LearnSkillSpells will look up the SkillLine from SkillLineAbility.dbc information, and add spells to the player as needed.
  10174. */
  10175. void Player::_LearnSkillSpells(uint32 SkillLine, uint32 curr_sk)
  10176. {
  10177.     // check for learn new spells (professions), from SkillLineAbility.dbc
  10178.     skilllinespell* sls, * sl2;
  10179.     uint32 rowcount = dbcSkillLineSpell.GetNumRows();
  10180.     SpellEntry* sp;
  10181.     uint32 removeSpellId = 0;
  10182.     for(uint32 idx = 0; idx < rowcount; ++idx)
  10183.     {
  10184.         sls = dbcSkillLineSpell.LookupRow(idx);
  10185.         // add new "automatic-acquired" spell
  10186.         if((sls->skilline == SkillLine) && (sls->acquireMethod == 1))
  10187.         {
  10188.             sp = dbcSpell.LookupEntryForced(sls->spell);
  10189.             if(sp && (curr_sk >= sls->minSkillLineRank))
  10190.             {
  10191.                 // Player is able to learn this spell; check if they already have it, or a higher rank (shouldn't, but just in case)
  10192.                 bool addThisSpell = true;
  10193.                 SpellEntry* se;
  10194.                 for(SpellSet::iterator itr = mSpells.begin(); itr != mSpells.end(); ++itr)
  10195.                 {
  10196.                     se = dbcSpell.LookupEntry(*itr);
  10197.                     if((se->NameHash == sp->NameHash) && (se->RankNumber >= sp->RankNumber))
  10198.                     {
  10199.                         // Stupid profession related spells for "skinning" having the same namehash and not ranked
  10200.                         if(sp->Id != 32605 && sp->Id != 32606 && sp->Id != 49383)
  10201.                         {
  10202.                             // Player already has this spell, or a higher rank. Don't add it.
  10203.                             addThisSpell = false;
  10204.                         }
  10205.                     }
  10206.                 }
  10207.                 if(addThisSpell)
  10208.                 {
  10209.                     // Adding a spell, now check if there was a previous spell, to remove
  10210.                     for(uint32 idx2 = 0; idx2 < rowcount; ++idx2)
  10211.                     {
  10212.                         sl2 = dbcSkillLineSpell.LookupRow(idx2);
  10213.                         if((sl2->skilline == SkillLine) && (sl2->next == sls->spell))
  10214.                         {
  10215.                             removeSpellId = sl2->spell;
  10216.                             idx2 = rowcount;
  10217.                         }
  10218.                     }
  10219.                     addSpell(sls->spell);
  10220.                     if(removeSpellId)
  10221.                     {
  10222.                         removeSpell(removeSpellId, true, true, sls->next);
  10223.                     }
  10224.                     // if passive spell, apply it now
  10225.                     if(sp->Attributes & ATTRIBUTES_PASSIVE)
  10226.                     {
  10227.                         SpellCastTargets targets;
  10228.                         targets.m_unitTarget = this->GetGUID();
  10229.                         targets.m_targetMask = TARGET_FLAG_UNIT;
  10230.                         Spell* spell = sSpellFactoryMgr.NewSpell(this, sp, true, NULL);
  10231.                         spell->prepare(&targets);
  10232.                     }
  10233.                 }
  10234.             }
  10235.         }
  10236.     }
  10237. }
  10238.  
  10239. uint32 Player::_GetSkillLineMax(uint32 SkillLine)
  10240. {
  10241.     SkillMap::iterator itr = m_skills.find(SkillLine);
  10242.     return (itr == m_skills.end()) ? 0 : itr->second.MaximumValue;
  10243. }
  10244.  
  10245. uint32 Player::_GetSkillLineCurrent(uint32 SkillLine, bool IncludeBonus /* = true */)
  10246. {
  10247.     SkillMap::iterator itr = m_skills.find(SkillLine);
  10248.     if(itr == m_skills.end())
  10249.         return 0;
  10250.  
  10251.     return (IncludeBonus ? itr->second.CurrentValue + itr->second.BonusValue : itr->second.CurrentValue);
  10252. }
  10253.  
  10254. void Player::_RemoveSkillLine(uint32 SkillLine)
  10255. {
  10256.     SkillMap::iterator itr = m_skills.find(SkillLine);
  10257.     if(itr == m_skills.end())
  10258.         return;
  10259.  
  10260.     m_skills.erase(itr);
  10261.     _UpdateSkillFields();
  10262. }
  10263.  
  10264. void Player::_UpdateMaxSkillCounts()
  10265. {
  10266.     bool dirty = false;
  10267.     uint32 new_max;
  10268.     for(SkillMap::iterator itr = m_skills.begin(); itr != m_skills.end(); ++itr)
  10269.     {
  10270.         if(itr->second.Skill->type == SKILL_TYPE_WEAPON || itr->second.Skill->id == SKILL_LOCKPICKING)
  10271.         {
  10272.             new_max = 5 * getLevel();
  10273.         }
  10274.         else if(itr->second.Skill->type == SKILL_TYPE_LANGUAGE)
  10275.         {
  10276.             new_max = 300;
  10277.         }
  10278.         else if(itr->second.Skill->type == SKILL_TYPE_PROFESSION || itr->second.Skill->type == SKILL_TYPE_SECONDARY)
  10279.         {
  10280.             new_max = itr->second.MaximumValue;
  10281.             if(new_max >= 1275)
  10282.                 new_max = 1275;
  10283.         }
  10284.         else
  10285.         {
  10286.             new_max = 1;
  10287.         }
  10288.  
  10289.  
  10290. #if PLAYER_LEVEL_CAP==250
  10291.         if (new_max > 1275)
  10292.             new_max = 1275;
  10293. #else
  10294.         if (new_max > 375)
  10295.             new_max = 375;
  10296. #endif
  10297.         if (new_max < 1)
  10298.             new_max = 1;
  10299.  
  10300.  
  10301.         if(itr->second.MaximumValue != new_max)
  10302.         {
  10303.             dirty = true;
  10304.             itr->second.MaximumValue = new_max;
  10305.         }
  10306.         if(itr->second.CurrentValue > new_max)
  10307.         {
  10308.             dirty = true;
  10309.             itr->second.CurrentValue = new_max;
  10310.         }
  10311.     }
  10312.  
  10313.     if(dirty)
  10314.         _UpdateSkillFields();
  10315. }
  10316.  
  10317. void Player::_ModifySkillBonus(uint32 SkillLine, int32 Delta)
  10318. {
  10319.     SkillMap::iterator itr = m_skills.find(SkillLine);
  10320.     if(itr == m_skills.end())
  10321.         return;
  10322.  
  10323.     itr->second.BonusValue += Delta;
  10324.     _UpdateSkillFields();
  10325. }
  10326.  
  10327. void Player::_ModifySkillBonusByType(uint32 SkillType, int32 Delta)
  10328. {
  10329.     bool dirty = false;
  10330.     for(SkillMap::iterator itr = m_skills.begin(); itr != m_skills.end(); ++itr)
  10331.     {
  10332.         if(itr->second.Skill->type == SkillType)
  10333.         {
  10334.             itr->second.BonusValue += Delta;
  10335.             dirty = true;
  10336.         }
  10337.     }
  10338.  
  10339.     if(dirty)
  10340.         _UpdateSkillFields();
  10341. }
  10342.  
  10343. /** Maybe this formula needs to be checked?
  10344.  * - Burlex
  10345.  */
  10346.  
  10347. float PlayerSkill::GetSkillUpChance()
  10348. {
  10349.     float diff = float(MaximumValue - CurrentValue);
  10350.     return (diff * 100.0f / MaximumValue);
  10351. }
  10352.  
  10353. void Player::_RemoveLanguages()
  10354. {
  10355.     for(SkillMap::iterator itr = m_skills.begin(), it2; itr != m_skills.end();)
  10356.     {
  10357.         if(itr->second.Skill->type == SKILL_TYPE_LANGUAGE)
  10358.         {
  10359.             it2 = itr++;
  10360.             m_skills.erase(it2);
  10361.         }
  10362.         else
  10363.             ++itr;
  10364.     }
  10365. }
  10366.  
  10367. void PlayerSkill::Reset(uint32 Id)
  10368. {
  10369.     MaximumValue = 0;
  10370.     CurrentValue = 0;
  10371.     BonusValue = 0;
  10372.     Skill = (Id == 0) ? NULL : dbcSkillLine.LookupEntry(Id);
  10373. }
  10374.  
  10375. void Player::_AddLanguages(bool All)
  10376. {
  10377.     /** This function should only be used at login, and after _RemoveLanguages is called.
  10378.      * Otherwise weird stuff could happen :P
  10379.      * - Burlex
  10380.      */
  10381.  
  10382.     PlayerSkill sk;
  10383.     skilllineentry* en;
  10384.     uint32 spell_id;
  10385.     static uint32 skills[] = { SKILL_LANG_COMMON, SKILL_LANG_ORCISH, SKILL_LANG_DWARVEN, SKILL_LANG_DARNASSIAN, SKILL_LANG_TAURAHE, SKILL_LANG_THALASSIAN,
  10386.                                SKILL_LANG_TROLL, SKILL_LANG_GUTTERSPEAK, SKILL_LANG_DRAENEI, 0
  10387.                              };
  10388.  
  10389.     if(All)
  10390.     {
  10391.         for(uint32 i = 0; skills[i] != 0; ++i)
  10392.         {
  10393.             if(!skills[i])
  10394.                 break;
  10395.  
  10396.             sk.Reset(skills[i]);
  10397.             sk.MaximumValue = sk.CurrentValue = 300;
  10398.             m_skills.insert(make_pair(skills[i], sk));
  10399.             if((spell_id = ::GetSpellForLanguage(skills[i])) != 0)
  10400.                 addSpell(spell_id);
  10401.         }
  10402.     }
  10403.     else
  10404.     {
  10405.         for(list<CreateInfo_SkillStruct>::iterator itr = info->skills.begin(); itr != info->skills.end(); ++itr)
  10406.         {
  10407.             en = dbcSkillLine.LookupEntry(itr->skillid);
  10408.             if(en->type == SKILL_TYPE_LANGUAGE)
  10409.             {
  10410.                 sk.Reset(itr->skillid);
  10411.                 sk.MaximumValue = sk.CurrentValue = 300;
  10412.                 m_skills.insert(make_pair(itr->skillid, sk));
  10413.                 if((spell_id = ::GetSpellForLanguage(itr->skillid)) != 0)
  10414.                     addSpell(spell_id);
  10415.             }
  10416.         }
  10417.     }
  10418.  
  10419.     _UpdateSkillFields();
  10420. }
  10421.  
  10422. float Player::GetSkillUpChance(uint32 id)
  10423. {
  10424.     SkillMap::iterator itr = m_skills.find(id);
  10425.     if(itr == m_skills.end())
  10426.         return 0.0f;
  10427.  
  10428.     return itr->second.GetSkillUpChance();
  10429. }
  10430.  
  10431. void Player::_RemoveAllSkills()
  10432. {
  10433.     m_skills.clear();
  10434.     _UpdateSkillFields();
  10435. }
  10436.  
  10437. void Player::_AdvanceAllSkills(uint32 count)
  10438. {
  10439.     bool dirty = false;
  10440.     for(SkillMap::iterator itr = m_skills.begin(); itr != m_skills.end(); ++itr)
  10441.     {
  10442.         if(itr->second.CurrentValue != itr->second.MaximumValue)
  10443.         {
  10444.             itr->second.CurrentValue += count;
  10445.             if(itr->second.CurrentValue >= itr->second.MaximumValue)
  10446.                 itr->second.CurrentValue = itr->second.MaximumValue;
  10447.             dirty = true;
  10448.         }
  10449.     }
  10450.  
  10451.     if(dirty)
  10452.         _UpdateSkillFields();
  10453. }
  10454.  
  10455. void Player::_ModifySkillMaximum(uint32 SkillLine, uint32 NewMax)
  10456. {
  10457.  
  10458. #if PLAYER_LEVEL_CAP==250
  10459.     Curr_sk = ( Curr_sk > 1275 ? 1275 : ( Curr_sk <1 ? 1 : Curr_sk ) );
  10460.     Max_sk = ( Max_sk > 1275 ? 1275 : Max_sk );
  10461. #else
  10462.     Curr_sk = ( Curr_sk > 375 ? 375 : ( Curr_sk <1 ? 1 : Curr_sk ) );
  10463.     Max_sk = ( Max_sk > 375 ? 375 : Max_sk );
  10464. #endif
  10465.  
  10466.     SkillMap::iterator itr = m_skills.find(SkillLine);
  10467.     if(itr == m_skills.end())
  10468.         return;
  10469.  
  10470.     if(NewMax > itr->second.MaximumValue)
  10471.     {
  10472.         if(SkillLine == SKILL_RIDING)
  10473.             itr->second.CurrentValue = NewMax;
  10474.  
  10475.         itr->second.MaximumValue = NewMax;
  10476.         _UpdateSkillFields();
  10477. #ifdef ENABLE_ACHIEVEMENTS
  10478.         m_achievementMgr.UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL, SkillLine, NewMax / 75, 0);
  10479. #endif
  10480.     }
  10481. }
  10482.  
  10483. void Player::RecalculateHonor()
  10484. {
  10485.     HonorHandler::RecalculateHonorFields(this);
  10486. }
  10487.  
  10488. //wooot, crappy code rulez.....NOT
  10489. void Player::EventTalentHearthOfWildChange(bool apply)
  10490. {
  10491.     if(!hearth_of_wild_pct)
  10492.         return;
  10493.  
  10494.     //druid hearth of the wild should add more features based on form
  10495.     int tval;
  10496.     if(apply)
  10497.         tval = hearth_of_wild_pct;
  10498.     else tval = -hearth_of_wild_pct;
  10499.  
  10500.     uint32 SS = GetShapeShift();
  10501.  
  10502.     //increase stamina if :
  10503.     if(SS == FORM_BEAR || SS == FORM_DIREBEAR)
  10504.     {
  10505.         TotalStatModPctPos[STAT_STAMINA] += tval;
  10506.         CalcStat(STAT_STAMINA);
  10507.         UpdateStats();
  10508.         UpdateChances();
  10509.     }
  10510.     //increase attackpower if :
  10511.     else if(SS == FORM_CAT)
  10512.     {
  10513.         SetAttackPowerMultiplier(GetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER) + tval / 200.0f);
  10514.         SetRangedAttackPowerMultiplier(GetRangedAttackPowerMultiplier() + tval / 200.0f);
  10515.         UpdateStats();
  10516.  
  10517.  
  10518.     }
  10519. }
  10520.  
  10521. void Player::EventGroupFullUpdate()
  10522. {
  10523.     if(m_playerInfo->m_Group)
  10524.     {
  10525.         //m_playerInfo->m_Group->Update();
  10526.         m_playerInfo->m_Group->UpdateAllOutOfRangePlayersFor(this);
  10527.     }
  10528. }
  10529.  
  10530. void Player::EjectFromInstance()
  10531. {
  10532.     if(m_bgEntryPointX && m_bgEntryPointY && m_bgEntryPointZ && !IS_INSTANCE(m_bgEntryPointMap))
  10533.     {
  10534.         if(SafeTeleport(m_bgEntryPointMap, m_bgEntryPointInstance, m_bgEntryPointX, m_bgEntryPointY, m_bgEntryPointZ, m_bgEntryPointO))
  10535.             return;
  10536.     }
  10537.  
  10538.     SafeTeleport(m_bind_mapid, 0, m_bind_pos_x, m_bind_pos_y, m_bind_pos_z, 0);
  10539. }
  10540.  
  10541. bool Player::HasQuestSpell(uint32 spellid) //Only for Cast Quests
  10542. {
  10543.     if(quest_spells.size() > 0 && quest_spells.find(spellid) != quest_spells.end())
  10544.         return true;
  10545.     return false;
  10546. }
  10547. void Player::RemoveQuestSpell(uint32 spellid) //Only for Cast Quests
  10548. {
  10549.     if(quest_spells.size() > 0)
  10550.         quest_spells.erase(spellid);
  10551. }
  10552.  
  10553. bool Player::HasQuestMob(uint32 entry) //Only for Kill Quests
  10554. {
  10555.     if(quest_mobs.size() > 0 && quest_mobs.find(entry) != quest_mobs.end())
  10556.         return true;
  10557.     return false;
  10558. }
  10559.  
  10560. bool Player::HasQuest(uint32 entry)
  10561. {
  10562.     for(uint32 i = 0; i < 25; i++)
  10563.     {
  10564.         if(m_questlog[i] != NULL && m_questlog[i]->GetQuest()->id == entry)
  10565.             return true;
  10566.     }
  10567.     return false;
  10568. }
  10569.  
  10570. void Player::RemoveQuestMob(uint32 entry) //Only for Kill Quests
  10571. {
  10572.     if(quest_mobs.size() > 0)
  10573.         quest_mobs.erase(entry);
  10574. }
  10575.  
  10576. PlayerInfo::~PlayerInfo()
  10577. {
  10578.     if(m_Group != NULL)
  10579.         m_Group->RemovePlayer(this);
  10580. }
  10581.  
  10582. void Player::CopyAndSendDelayedPacket(WorldPacket* data)
  10583. {
  10584.     WorldPacket* data2 = new WorldPacket(*data);
  10585.     delayedPackets.add(data2);
  10586. }
  10587.  
  10588. void Player::SendMeetingStoneQueue(uint32 DungeonId, uint8 Status)
  10589. {
  10590.     WorldPacket data(SMSG_MEETINGSTONE_SETQUEUE, 5);
  10591.     data << DungeonId << Status;
  10592.     m_session->SendPacket(&data);
  10593. }
  10594.  
  10595. void Player::PartLFGChannel()
  10596. {
  10597.     Channel* pChannel = channelmgr.GetChannel("LookingForGroup", this);
  10598.     if(pChannel == NULL)
  10599.         return;
  10600.  
  10601.     /*for(list<Channel*>::iterator itr = m_channels.begin(); itr != m_channels.end(); ++itr)
  10602.     {
  10603.         if( (*itr) == pChannel )
  10604.         {
  10605.             pChannel->Part(this);
  10606.             return;
  10607.         }
  10608.     }*/
  10609.     if(m_channels.find(pChannel) == m_channels.end())
  10610.         return;
  10611.  
  10612.     pChannel->Part(this);
  10613. }
  10614.  
  10615. //if we charmed or simply summoned a pet, this function should get called
  10616. void Player::EventSummonPet(Pet* new_pet)
  10617. {
  10618.     if(!new_pet)
  10619.         return ; //another wtf error
  10620.  
  10621.     SpellSet::iterator it, iter;
  10622.     for(iter = mSpells.begin(); iter != mSpells.end();)
  10623.     {
  10624.         it = iter++;
  10625.         uint32 SpellID = *it;
  10626.         SpellEntry* spellInfo = dbcSpell.LookupEntry(SpellID);
  10627.         if(spellInfo->c_is_flags & SPELL_FLAG_IS_CASTED_ON_PET_SUMMON_PET_OWNER)
  10628.         {
  10629.             this->RemoveAllAuras(SpellID, this->GetGUID());   //this is required since unit::addaura does not check for talent stacking
  10630.             SpellCastTargets targets(this->GetGUID());
  10631.             Spell* spell = sSpellFactoryMgr.NewSpell(this, spellInfo , true, NULL); //we cast it as a proc spell, maybe we should not !
  10632.             spell->prepare(&targets);
  10633.         }
  10634.         if(spellInfo->c_is_flags & SPELL_FLAG_IS_CASTED_ON_PET_SUMMON_ON_PET)
  10635.         {
  10636.             this->RemoveAllAuras(SpellID, this->GetGUID());   //this is required since unit::addaura does not check for talent stacking
  10637.             SpellCastTargets targets(new_pet->GetGUID());
  10638.             Spell* spell = sSpellFactoryMgr.NewSpell(this, spellInfo , true, NULL); //we cast it as a proc spell, maybe we should not !
  10639.             spell->prepare(&targets);
  10640.         }
  10641.     }
  10642.     //there are talents that stop working after you gain pet
  10643.     for(uint32 x = MAX_TOTAL_AURAS_START; x < MAX_TOTAL_AURAS_END; x++)
  10644.         if(m_auras[x] && m_auras[x]->GetSpellProto()->c_is_flags & SPELL_FLAG_IS_EXPIREING_ON_PET)
  10645.             m_auras[x]->Remove();
  10646.     //pet should inherit some of the talents from caster
  10647.     //new_pet->InheritSMMods(); //not required yet. We cast full spell to have visual effect too
  10648. }
  10649.  
  10650. //if pet/charm died or whatever happened we should call this function
  10651. //!! note function might get called multiple times :P
  10652. void Player::EventDismissPet()
  10653. {
  10654.     for(uint32 x = MAX_TOTAL_AURAS_START; x < MAX_TOTAL_AURAS_END; x++)
  10655.         if(m_auras[ x ])
  10656.             if(m_auras [ x ]->GetSpellProto()->c_is_flags & SPELL_FLAG_IS_EXPIREING_WITH_PET)
  10657.                 m_auras[ x ]->Remove();
  10658. }
  10659.  
  10660. #ifdef ENABLE_COMPRESSED_MOVEMENT
  10661.  
  10662. CMovementCompressorThread* MovementCompressor;
  10663.  
  10664. void Player::AppendMovementData(uint32 op, uint32 sz, const uint8* data)
  10665. {
  10666.     //printf("AppendMovementData(%u, %u, 0x%.8X)\n", op, sz, data);
  10667.     m_movementBufferLock.Acquire();
  10668.     m_movementBuffer << uint8(sz + 2);
  10669.     m_movementBuffer << uint16(op);
  10670.     m_movementBuffer.append(data, sz);
  10671.     m_movementBufferLock.Release();
  10672. }
  10673.  
  10674. bool CMovementCompressorThread::run()
  10675. {
  10676.     set<Player*>::iterator itr;
  10677.     while(running)
  10678.     {
  10679.         m_listLock.Acquire();
  10680.         for(itr = m_players.begin(); itr != m_players.end(); ++itr)
  10681.         {
  10682.             (*itr)->EventDumpCompressedMovement();
  10683.         }
  10684.         m_listLock.Release();
  10685.         Arcemu::Sleep(World::m_movementCompressInterval);
  10686.     }
  10687.  
  10688.     return true;
  10689. }
  10690.  
  10691. void CMovementCompressorThread::AddPlayer(Player* pPlayer)
  10692. {
  10693.     m_listLock.Acquire();
  10694.     m_players.insert(pPlayer);
  10695.     m_listLock.Release();
  10696. }
  10697.  
  10698. void CMovementCompressorThread::RemovePlayer(Player* pPlayer)
  10699. {
  10700.     m_listLock.Acquire();
  10701.     m_players.erase(pPlayer);
  10702.     m_listLock.Release();
  10703. }
  10704.  
  10705. void Player::EventDumpCompressedMovement()
  10706. {
  10707.     if(m_movementBuffer.size() == 0)
  10708.         return;
  10709.  
  10710.     m_movementBufferLock.Acquire();
  10711.     uint32 size = (uint32)m_movementBuffer.size();
  10712.     uint32 destsize = size + size / 10 + 16;
  10713.     int rate = World::m_movementCompressRate;
  10714.     if(size >= 40000 && rate < 6)
  10715.         rate = 6;
  10716.     if(size <= 100)
  10717.         rate = 0;           // don't bother compressing packet smaller than this, zlib doesn't really handle them well
  10718.  
  10719.     // set up stream
  10720.     z_stream stream;
  10721.     stream.zalloc = 0;
  10722.     stream.zfree  = 0;
  10723.     stream.opaque = 0;
  10724.  
  10725.     if(deflateInit(&stream, rate) != Z_OK)
  10726.     {
  10727.         LOG_ERROR("deflateInit failed.");
  10728.         m_movementBufferLock.Release();
  10729.         return;
  10730.     }
  10731.  
  10732.     uint8* buffer = new uint8[destsize];
  10733.  
  10734.     // set up stream pointers
  10735.     stream.next_out  = (Bytef*)buffer + 4;
  10736.     stream.avail_out = destsize;
  10737.     stream.next_in   = (Bytef*)m_movementBuffer.contents();
  10738.     stream.avail_in  = size;
  10739.  
  10740.     // call the actual process
  10741.     if(deflate(&stream, Z_NO_FLUSH) != Z_OK ||
  10742.             stream.avail_in != 0)
  10743.     {
  10744.         LOG_ERROR("deflate failed.");
  10745.         delete [] buffer;
  10746.         m_movementBufferLock.Release();
  10747.         return;
  10748.     }
  10749.  
  10750.     // finish the deflate
  10751.     if(deflate(&stream, Z_FINISH) != Z_STREAM_END)
  10752.     {
  10753.         LOG_ERROR("deflate failed: did not end stream");
  10754.         delete [] buffer;
  10755.         m_movementBufferLock.Release();
  10756.         return;
  10757.     }
  10758.  
  10759.     // finish up
  10760.     if(deflateEnd(&stream) != Z_OK)
  10761.     {
  10762.         LOG_ERROR("deflateEnd failed.");
  10763.         delete [] buffer;
  10764.         m_movementBufferLock.Release();
  10765.         return;
  10766.     }
  10767.  
  10768.     // fill in the full size of the compressed stream
  10769.  
  10770.     *(uint32*)&buffer[0] = size;
  10771.  
  10772.     // send it
  10773.     m_session->OutPacket(763, (uint16)stream.total_out + 4, buffer);
  10774.     //printf("Compressed move compressed from %u bytes to %u bytes.\n", m_movementBuffer.size(), stream.total_out + 4);
  10775.  
  10776.     // cleanup memory
  10777.     delete [] buffer;
  10778.     m_movementBuffer.clear();
  10779.     m_movementBufferLock.Release();
  10780. }
  10781. #endif
  10782.  
  10783. void Player::AddShapeShiftSpell(uint32 id)
  10784. {
  10785.     SpellEntry* sp = dbcSpell.LookupEntry(id);
  10786.     mShapeShiftSpells.insert(id);
  10787.  
  10788.     if(sp->RequiredShapeShift && ((uint32)1 << (GetShapeShift() - 1)) & sp->RequiredShapeShift)
  10789.     {
  10790.         Spell* spe = sSpellFactoryMgr.NewSpell(this, sp, true, NULL);
  10791.         SpellCastTargets t(this->GetGUID());
  10792.         spe->prepare(&t);
  10793.     }
  10794. }
  10795.  
  10796. void Player::RemoveShapeShiftSpell(uint32 id)
  10797. {
  10798.     mShapeShiftSpells.erase(id);
  10799.     RemoveAura(id);
  10800. }
  10801.  
  10802. // COOLDOWNS
  10803. void Player::UpdatePotionCooldown()
  10804. {
  10805.     if(m_lastPotionId == 0 || CombatStatus.IsInCombat())
  10806.         return;
  10807.  
  10808.     ItemPrototype* proto = ItemPrototypeStorage.LookupEntry(m_lastPotionId);
  10809.     if(proto != NULL)
  10810.     {
  10811.         for(uint8 i = 0; i < 5; ++i)
  10812.         {
  10813.             if(proto->Spells[i].Id && proto->Spells[i].Trigger == USE)
  10814.             {
  10815.                 SpellEntry* spellInfo = dbcSpell.LookupEntryForced(proto->Spells[i].Id);
  10816.                 if(spellInfo != NULL)
  10817.                 {
  10818.                     Cooldown_AddItem(proto, i);
  10819.                     SendSpellCooldownEvent(spellInfo->Id);
  10820.                 }
  10821.             }
  10822.         }
  10823.     }
  10824.  
  10825.     m_lastPotionId = 0;
  10826. }
  10827.  
  10828. bool Player::HasSpellWithAuraNameAndBasePoints( uint32 auraname, uint32 basepoints ){
  10829.     for( SpellSet::iterator itr = mSpells.begin(); itr != mSpells.end(); ++itr ){
  10830.         SpellEntry *sp = dbcSpell.LookupEntry( *itr );
  10831.  
  10832.         for( uint32 i = 0; i < 3; i++ ){
  10833.             if( sp->Effect[ i ] == SPELL_EFFECT_APPLY_AURA ){
  10834.                 if( ( sp->EffectApplyAuraName[ i ] == auraname ) && ( sp->EffectBasePoints[ i ] == ( basepoints - 1 ) ) )
  10835.                     return true;
  10836.             }
  10837.         }
  10838.  
  10839.     }
  10840.  
  10841.     return false;
  10842. }
  10843.  
  10844. void Player::_Cooldown_Add(uint32 Type, uint32 Misc, uint32 Time, uint32 SpellId, uint32 ItemId)
  10845. {
  10846.     PlayerCooldownMap::iterator itr = m_cooldownMap[Type].find(Misc);
  10847.     if(itr != m_cooldownMap[Type].end())
  10848.     {
  10849.         if(itr->second.ExpireTime < Time)
  10850.         {
  10851.             itr->second.ExpireTime = Time;
  10852.             itr->second.ItemId = ItemId;
  10853.             itr->second.SpellId = SpellId;
  10854.         }
  10855.     }
  10856.     else
  10857.     {
  10858.         PlayerCooldown cd;
  10859.         cd.ExpireTime = Time;
  10860.         cd.ItemId = ItemId;
  10861.         cd.SpellId = SpellId;
  10862.  
  10863.         m_cooldownMap[Type].insert(make_pair(Misc, cd));
  10864.     }
  10865.  
  10866. #ifdef _DEBUG
  10867.     Log.Debug("Cooldown", "added cooldown for type %u misc %u time %u item %u spell %u", Type, Misc, Time - getMSTime(), ItemId, SpellId);
  10868. #endif
  10869. }
  10870.  
  10871. void Player::Cooldown_Add(SpellEntry* pSpell, Item* pItemCaster)
  10872. {
  10873.     uint32 mstime = getMSTime();
  10874.     int32 cool_time;
  10875.  
  10876.     if(pSpell->CategoryRecoveryTime > 0 && pSpell->Category)
  10877.     {
  10878.         cool_time = pSpell->CategoryRecoveryTime;
  10879.         if(pSpell->SpellGroupType)
  10880.         {
  10881.             SM_FIValue(SM_FCooldownTime, &cool_time, pSpell->SpellGroupType);
  10882.             SM_PIValue(SM_PCooldownTime, &cool_time, pSpell->SpellGroupType);
  10883.         }
  10884.  
  10885.         _Cooldown_Add(COOLDOWN_TYPE_CATEGORY, pSpell->Category, mstime + cool_time, pSpell->Id, pItemCaster ? pItemCaster->GetProto()->ItemId : 0);
  10886.     }
  10887.  
  10888.     if(pSpell->RecoveryTime > 0)
  10889.     {
  10890.         cool_time = pSpell->RecoveryTime;
  10891.         if(pSpell->SpellGroupType)
  10892.         {
  10893.             SM_FIValue(SM_FCooldownTime, &cool_time, pSpell->SpellGroupType);
  10894.             SM_PIValue(SM_PCooldownTime, &cool_time, pSpell->SpellGroupType);
  10895.         }
  10896.  
  10897.         _Cooldown_Add(COOLDOWN_TYPE_SPELL, pSpell->Id, mstime + cool_time, pSpell->Id, pItemCaster ? pItemCaster->GetProto()->ItemId : 0);
  10898.     }
  10899. }
  10900.  
  10901. void Player::Cooldown_AddStart(SpellEntry* pSpell)
  10902. {
  10903.     if(pSpell->StartRecoveryTime == 0)
  10904.         return;
  10905.  
  10906.     uint32 mstime = getMSTime();
  10907.     int32 atime; // = float2int32( float( pSpell->StartRecoveryTime ) / SpellHasteRatingBonus );
  10908.  
  10909.     if(GetCastSpeedMod() >= 1.0f)
  10910.         atime = pSpell->StartRecoveryTime;
  10911.     else
  10912.         atime = float2int32(pSpell->StartRecoveryTime * GetCastSpeedMod());
  10913.  
  10914.     if(pSpell->SpellGroupType)
  10915.     {
  10916.         SM_FIValue(SM_FGlobalCooldown, &atime, pSpell->SpellGroupType);
  10917.         SM_PIValue(SM_PGlobalCooldown, &atime, pSpell->SpellGroupType);
  10918.     }
  10919.  
  10920.     if(atime < 0)
  10921.         return;
  10922.  
  10923.     if(pSpell->StartRecoveryCategory && pSpell->StartRecoveryCategory != 133)       // if we have a different cool category to the actual spell category - only used by few spells
  10924.         _Cooldown_Add(COOLDOWN_TYPE_CATEGORY, pSpell->StartRecoveryCategory, mstime + atime, pSpell->Id, 0);
  10925.     //else if( pSpell->Category )               // cooldowns are grouped
  10926.     //_Cooldown_Add( COOLDOWN_TYPE_CATEGORY, pSpell->Category, mstime + pSpell->StartRecoveryTime, pSpell->Id, 0 );
  10927.     else                                    // no category, so it's a gcd
  10928.     {
  10929.         //Log.Debug("Cooldown", "Global cooldown adding: %u ms", atime );
  10930.         m_globalCooldown = mstime + atime;
  10931.  
  10932.     }
  10933. }
  10934.  
  10935. bool Player::Cooldown_CanCast(SpellEntry* pSpell)
  10936. {
  10937.     PlayerCooldownMap::iterator itr;
  10938.     uint32 mstime = getMSTime();
  10939.  
  10940.     if(pSpell->Category)
  10941.     {
  10942.         itr = m_cooldownMap[COOLDOWN_TYPE_CATEGORY].find(pSpell->Category);
  10943.         if(itr != m_cooldownMap[COOLDOWN_TYPE_CATEGORY].end())
  10944.         {
  10945.             if(mstime < itr->second.ExpireTime)
  10946.                 return false;
  10947.             else
  10948.                 m_cooldownMap[COOLDOWN_TYPE_CATEGORY].erase(itr);
  10949.         }
  10950.     }
  10951.  
  10952.     itr = m_cooldownMap[COOLDOWN_TYPE_SPELL].find(pSpell->Id);
  10953.     if(itr != m_cooldownMap[COOLDOWN_TYPE_SPELL].end())
  10954.     {
  10955.         if(mstime < itr->second.ExpireTime)
  10956.             return false;
  10957.         else
  10958.             m_cooldownMap[COOLDOWN_TYPE_SPELL].erase(itr);
  10959.     }
  10960.  
  10961.     if(pSpell->StartRecoveryTime && m_globalCooldown && !this->CooldownCheat /* cebernic:GCD also cheat :D */)          /* gcd doesn't affect spells without a cooldown it seems */
  10962.     {
  10963.         if(mstime < m_globalCooldown)
  10964.             return false;
  10965.         else
  10966.             m_globalCooldown = 0;
  10967.     }
  10968.  
  10969.     return true;
  10970. }
  10971.  
  10972. void Player::Cooldown_AddItem(ItemPrototype* pProto, uint32 x)
  10973. {
  10974.     if(pProto->Spells[x].CategoryCooldown <= 0 && pProto->Spells[x].Cooldown <= 0)
  10975.         return;
  10976.  
  10977.     ItemSpell* isp = &pProto->Spells[x];
  10978.     uint32 mstime = getMSTime();
  10979.  
  10980.     if(isp->CategoryCooldown > 0)
  10981.         _Cooldown_Add(COOLDOWN_TYPE_CATEGORY, isp->Category, isp->CategoryCooldown + mstime, isp->Id, pProto->ItemId);
  10982.  
  10983.     if(isp->Cooldown > 0)
  10984.         _Cooldown_Add(COOLDOWN_TYPE_SPELL, isp->Id, isp->Cooldown + mstime, isp->Id, pProto->ItemId);
  10985. }
  10986.  
  10987. bool Player::Cooldown_CanCast(ItemPrototype* pProto, uint32 x)
  10988. {
  10989.     PlayerCooldownMap::iterator itr;
  10990.     ItemSpell* isp = &pProto->Spells[x];
  10991.     uint32 mstime = getMSTime();
  10992.  
  10993.     if(isp->Category)
  10994.     {
  10995.         itr = m_cooldownMap[COOLDOWN_TYPE_CATEGORY].find(isp->Category);
  10996.         if(itr != m_cooldownMap[COOLDOWN_TYPE_CATEGORY].end())
  10997.         {
  10998.             if(mstime < itr->second.ExpireTime)
  10999.                 return false;
  11000.             else
  11001.                 m_cooldownMap[COOLDOWN_TYPE_CATEGORY].erase(itr);
  11002.         }
  11003.     }
  11004.  
  11005.     itr = m_cooldownMap[COOLDOWN_TYPE_SPELL].find(isp->Id);
  11006.     if(itr != m_cooldownMap[COOLDOWN_TYPE_SPELL].end())
  11007.     {
  11008.         if(mstime < itr->second.ExpireTime)
  11009.             return false;
  11010.         else
  11011.             m_cooldownMap[COOLDOWN_TYPE_SPELL].erase(itr);
  11012.     }
  11013.  
  11014.     return true;
  11015. }
  11016.  
  11017. #define COOLDOWN_SKIP_SAVE_IF_MS_LESS_THAN 10000
  11018.  
  11019. void Player::_SavePlayerCooldowns(QueryBuffer* buf)
  11020. {
  11021.     PlayerCooldownMap::iterator itr;
  11022.     PlayerCooldownMap::iterator itr2;
  11023.     uint32 i;
  11024.     uint32 seconds;
  11025.     uint32 mstime = getMSTime();
  11026.  
  11027.     // clear them (this should be replaced with an update queue later)
  11028.     if(buf != NULL)
  11029.         buf->AddQuery("DELETE FROM playercooldowns WHERE player_guid = %u", GetLowGUID());      // 0 is guid always
  11030.     else
  11031.         CharacterDatabase.Execute("DELETE FROM playercooldowns WHERE player_guid = %u", GetLowGUID());      // 0 is guid always
  11032.  
  11033.     for(i = 0; i < NUM_COOLDOWN_TYPES; ++i)
  11034.     {
  11035.         itr = m_cooldownMap[i].begin();
  11036.         for(; itr != m_cooldownMap[i].end();)
  11037.         {
  11038.             itr2 = itr++;
  11039.  
  11040.             // expired ones - no point saving, nor keeping them around, wipe em
  11041.             if(mstime >= itr2->second.ExpireTime)
  11042.             {
  11043.                 m_cooldownMap[i].erase(itr2);
  11044.                 continue;
  11045.             }
  11046.  
  11047.             // skip small cooldowns which will end up expiring by the time we log in anyway
  11048.             if((itr2->second.ExpireTime - mstime) < COOLDOWN_SKIP_SAVE_IF_MS_LESS_THAN)
  11049.                 continue;
  11050.  
  11051.             // work out the cooldown expire time in unix timestamp format
  11052.             // burlex's reason: 30 day overflow of 32bit integer, also
  11053.             // under windows we use GetTickCount() which is the system uptime, if we reboot
  11054.             // the server all these timestamps will appear to be messed up.
  11055.  
  11056.             seconds = (itr2->second.ExpireTime - mstime) / 1000;
  11057.             // this shouldn't ever be nonzero because of our check before, so no check needed
  11058.  
  11059.             if(buf != NULL)
  11060.             {
  11061.                 buf->AddQuery("INSERT INTO playercooldowns VALUES(%u, %u, %u, %u, %u, %u)", GetLowGUID(),
  11062.                               i, itr2->first, seconds + (uint32)UNIXTIME, itr2->second.SpellId, itr2->second.ItemId);
  11063.             }
  11064.             else
  11065.             {
  11066.                 CharacterDatabase.Execute("INSERT INTO playercooldowns VALUES(%u, %u, %u, %u, %u, %u)", GetLowGUID(),
  11067.                                           i, itr2->first, seconds + (uint32)UNIXTIME, itr2->second.SpellId, itr2->second.ItemId);
  11068.             }
  11069.         }
  11070.     }
  11071. }
  11072.  
  11073. void Player::_LoadPlayerCooldowns(QueryResult* result)
  11074. {
  11075.     if(result == NULL)
  11076.         return;
  11077.  
  11078.     // we should only really call getMSTime() once to avoid user->system transitions, plus
  11079.     // the cost of calling a function for every cooldown the player has
  11080.     uint32 mstime = getMSTime();
  11081.     uint32 type;
  11082.     uint32 misc;
  11083.     uint32 rtime;
  11084.     uint32 realtime;
  11085.     uint32 itemid;
  11086.     uint32 spellid;
  11087.     PlayerCooldown cd;
  11088.  
  11089.     do
  11090.     {
  11091.         type = result->Fetch()[0].GetUInt32();
  11092.         misc = result->Fetch()[1].GetUInt32();
  11093.         rtime = result->Fetch()[2].GetUInt32();
  11094.         spellid = result->Fetch()[3].GetUInt32();
  11095.         itemid = result->Fetch()[4].GetUInt32();
  11096.  
  11097.         if(type >= NUM_COOLDOWN_TYPES)
  11098.             continue;
  11099.  
  11100.         // remember the cooldowns were saved in unix timestamp format for the reasons outlined above,
  11101.         // so restore them back to mstime upon loading
  11102.  
  11103.         if((uint32)UNIXTIME > rtime)
  11104.             continue;
  11105.  
  11106.         rtime -= (uint32)UNIXTIME;
  11107.  
  11108.         if(rtime < 10)
  11109.             continue;
  11110.  
  11111.         realtime = mstime + ((rtime) * 1000);
  11112.  
  11113.         // apply it back into cooldown map
  11114.         cd.ExpireTime = realtime;
  11115.         cd.ItemId = itemid;
  11116.         cd.SpellId = spellid;
  11117.         m_cooldownMap[type].insert(make_pair(misc, cd));
  11118.  
  11119.     }
  11120.     while(result->NextRow());
  11121. }
  11122.  
  11123. void Player::_FlyhackCheck()
  11124. {
  11125.     if(!sWorld.antihack_flight || transporter_info.guid != 0 || GetTaxiState() || (sWorld.no_antihack_on_gm && GetSession()->HasGMPermissions()))
  11126.         return;
  11127.     return;
  11128.     //disabled
  11129.     /*
  11130.     MovementInfo * mi = GetSession()->GetMovementInfo();
  11131.     if(!mi) return; //wtf?
  11132.  
  11133.     if (!GetSession())
  11134.         return;
  11135.     // Falling, CCs, etc. All stuff that could potentially trap a player in mid-air.
  11136.     if(!(mi->flags & (MOVEFLAG_FALLING | MOVEFLAG_SWIMMING | MOVEFLAG_LEVITATE | MOVEFLAG_FEATHER_FALL)) &&
  11137.         !(m_special_state & (UNIT_STATE_CHARM | UNIT_STATE_FEAR | UNIT_STATE_ROOT | UNIT_STATE_STUN | UNIT_STATE_POLYMORPH | UNIT_STATE_CONFUSE | UNIT_STATE_FROZEN))
  11138.         && !flying_aura && !FlyCheat)
  11139.     {
  11140.         float t_height = CollideInterface.GetHeight(GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ() + 2.0f);
  11141.         if(t_height == 999999.0f || t_height == NO_WMO_HEIGHT )
  11142.             t_height = GetMapMgr()->GetLandHeight(GetPositionX(), GetPositionY());
  11143.             if(t_height == 999999.0f || t_height == 0.0f) // Can't rely on anyone these days...
  11144.                 return;
  11145.  
  11146.         float p_height = GetPositionZ();
  11147.  
  11148.         int32 diff = float2int32(p_height - t_height);
  11149.         if(diff < 0)
  11150.             diff = -diff;
  11151.  
  11152.         if(t_height != p_height && (uint32)diff > sWorld.flyhack_threshold)
  11153.         {
  11154.             // Fly hax!
  11155.             EventTeleport(GetMapId(), GetPositionX(), GetPositionY(), t_height + 2.0f); // relog fix.
  11156.             sCheatLog.writefromsession(GetSession(), "Caught fly hacking on map %u hovering %u over the terrain.", GetMapId(), diff);
  11157.             WorldPacket data (SMSG_MOVE_UNSET_CAN_FLY, 13);
  11158.             data << GetNewGUID();
  11159.             data << uint32(5);
  11160.             GetSession()->SendPacket(&data);
  11161.         }
  11162.     }
  11163.     */
  11164.  
  11165. }
  11166.  
  11167. /************************************************************************/
  11168. /* SOCIAL                                                               */
  11169. /************************************************************************/
  11170.  
  11171. void Player::Social_AddFriend(const char* name, const char* note)
  11172. {
  11173.     WorldPacket data(SMSG_FRIEND_STATUS, 10);
  11174.     map<uint32, char*>::iterator itr;
  11175.  
  11176.     // lookup the player
  11177.     PlayerInfo* info = objmgr.GetPlayerInfoByName(name);
  11178.     PlayerCache* cache = objmgr.GetPlayerCache(name, false);
  11179.  
  11180.     if(info == NULL || (cache != NULL && cache->HasFlag(CACHE_PLAYER_FLAGS, PLAYER_FLAG_GM)))
  11181.     {
  11182.         data << uint8(FRIEND_NOT_FOUND);
  11183.         m_session->SendPacket(&data);
  11184.  
  11185.         if(cache != NULL)
  11186.             cache->DecRef();
  11187.         return;
  11188.     }
  11189.  
  11190.     // team check
  11191.     if(info->team != GetTeamInitial()  && m_session->permissioncount == 0 && !sWorld.interfaction_friend)
  11192.     {
  11193.         data << uint8(FRIEND_ENEMY) << uint64(info->guid);
  11194.         m_session->SendPacket(&data);
  11195.         if(cache != NULL)
  11196.             cache->DecRef();
  11197.         return;
  11198.     }
  11199.  
  11200.     // are we ourselves?
  11201.     if(cache != NULL && cache->GetUInt32Value(CACHE_PLAYER_LOWGUID) == GetLowGUID())
  11202.     {
  11203.         data << uint8(FRIEND_SELF) << GetGUID();
  11204.         m_session->SendPacket(&data);
  11205.         if(cache != NULL)
  11206.             cache->DecRef();
  11207.         return;
  11208.     }
  11209.  
  11210.     if(m_cache->CountValue64(CACHE_SOCIAL_FRIENDLIST, info->guid))
  11211.     {
  11212.         data << uint8(FRIEND_ALREADY) << uint64(info->guid);
  11213.         m_session->SendPacket(&data);
  11214.         if(cache != NULL)
  11215.             cache->DecRef();
  11216.         return;
  11217.     }
  11218.  
  11219.     if(cache != NULL)   //hes online if he has a cache
  11220.     {
  11221.         data << uint8(FRIEND_ADDED_ONLINE);
  11222.         data << uint64(cache->GetUInt32Value(CACHE_PLAYER_LOWGUID));
  11223.         if(note != NULL)
  11224.             data << note;
  11225.         else
  11226.             data << uint8(0);
  11227.  
  11228.         data << uint8(1);
  11229.         data << info->m_loggedInPlayer->GetZoneId();
  11230.         data << info->lastLevel;
  11231.         data << uint32(info->cl);
  11232.  
  11233.         cache->InsertValue64(CACHE_SOCIAL_HASFRIENDLIST, GetLowGUID());
  11234.     }
  11235.     else
  11236.     {
  11237.         data << uint8(FRIEND_ADDED_OFFLINE);
  11238.         data << uint64(info->guid);
  11239.     }
  11240.  
  11241.     char* notedup = note == NULL ? NULL : strdup(note);
  11242.     m_cache->InsertValue64(CACHE_SOCIAL_FRIENDLIST, info->guid, notedup);
  11243.  
  11244.     m_session->SendPacket(&data);
  11245.  
  11246.     // dump into the db
  11247.     CharacterDatabase.Execute("INSERT INTO social_friends VALUES(%u, %u, \'%s\')",
  11248.                               GetLowGUID(), info->guid, note ? CharacterDatabase.EscapeString(string(note)).c_str() : "");
  11249.  
  11250.     if(cache != NULL)
  11251.         cache->DecRef();
  11252. }
  11253.  
  11254. void Player::Social_RemoveFriend(uint32 guid)
  11255. {
  11256.     WorldPacket data(SMSG_FRIEND_STATUS, 10);
  11257.  
  11258.     // are we ourselves?
  11259.     if(guid == GetLowGUID())
  11260.     {
  11261.         data << uint8(FRIEND_SELF) << GetGUID();
  11262.         m_session->SendPacket(&data);
  11263.         return;
  11264.     }
  11265.  
  11266.     //free note first
  11267.     m_cache->AcquireLock64(CACHE_SOCIAL_FRIENDLIST);
  11268.     PlayerCacheMap::iterator itr = m_cache->Find64(CACHE_SOCIAL_FRIENDLIST, guid);
  11269.     if(itr != m_cache->End64(CACHE_SOCIAL_FRIENDLIST) && itr->second != NULL)
  11270.     {
  11271.         free(itr->second);
  11272.         itr->second = NULL;
  11273.     }
  11274.     m_cache->RemoveValue64(CACHE_SOCIAL_FRIENDLIST, guid);
  11275.     m_cache->ReleaseLock64(CACHE_SOCIAL_FRIENDLIST);
  11276.  
  11277.     data << uint8(FRIEND_REMOVED);
  11278.     data << uint64(guid);
  11279.  
  11280.     PlayerCache* cache = objmgr.GetPlayerCache((uint32)guid);
  11281.     if(cache != NULL)
  11282.     {
  11283.         cache->RemoveValue64(CACHE_SOCIAL_HASFRIENDLIST, GetLowGUID());
  11284.         cache->DecRef();
  11285.     }
  11286.  
  11287.     m_session->SendPacket(&data);
  11288.  
  11289.     // remove from the db
  11290.     CharacterDatabase.Execute("DELETE FROM social_friends WHERE character_guid = %u AND friend_guid = %u",
  11291.                               GetLowGUID(), (uint32)guid);
  11292. }
  11293.  
  11294. void Player::Social_SetNote(uint32 guid, const char* note)
  11295. {
  11296.     //free note first
  11297.     m_cache->AcquireLock64(CACHE_SOCIAL_FRIENDLIST);
  11298.     PlayerCacheMap::iterator itr = m_cache->Find64(CACHE_SOCIAL_FRIENDLIST, guid);
  11299.     if(itr != m_cache->End64(CACHE_SOCIAL_FRIENDLIST))
  11300.     {
  11301.         if(itr->second != NULL)
  11302.             free(itr->second);
  11303.         itr->second = strdup(note);
  11304.     }
  11305.     m_cache->ReleaseLock64(CACHE_SOCIAL_FRIENDLIST);
  11306.  
  11307.     CharacterDatabase.Execute("UPDATE social_friends SET note = \'%s\' WHERE character_guid = %u AND friend_guid = %u",
  11308.                               note ? CharacterDatabase.EscapeString(string(note)).c_str() : "", GetLowGUID(), guid);
  11309. }
  11310.  
  11311. void Player::Social_AddIgnore(const char* name)
  11312. {
  11313.     WorldPacket data(SMSG_FRIEND_STATUS, 10);
  11314.     PlayerInfo* info;
  11315.  
  11316.     // lookup the player
  11317.     info = objmgr.GetPlayerInfoByName(name);
  11318.     if(info == NULL)
  11319.     {
  11320.         data << uint8(FRIEND_IGNORE_NOT_FOUND);
  11321.         m_session->SendPacket(&data);
  11322.         return;
  11323.     }
  11324.  
  11325.     // are we ourselves?
  11326.     if(info == m_playerInfo)
  11327.     {
  11328.         data << uint8(FRIEND_IGNORE_SELF) << GetGUID();
  11329.         m_session->SendPacket(&data);
  11330.         return;
  11331.     }
  11332.  
  11333.     if(m_cache->CountValue64(CACHE_SOCIAL_IGNORELIST, info->guid) > 0)
  11334.     {
  11335.         data << uint8(FRIEND_IGNORE_ALREADY) << uint64(info->guid);
  11336.         m_session->SendPacket(&data);
  11337.         return;
  11338.     }
  11339.  
  11340.     data << uint8(FRIEND_IGNORE_ADDED);
  11341.     data << uint64(info->guid);
  11342.  
  11343.     m_cache->InsertValue64(CACHE_SOCIAL_IGNORELIST, info->guid);
  11344.     m_session->SendPacket(&data);
  11345.  
  11346.     // dump into db
  11347.     CharacterDatabase.Execute("INSERT INTO social_ignores VALUES(%u, %u)", GetLowGUID(), info->guid);
  11348. }
  11349.  
  11350. void Player::Social_RemoveIgnore(uint32 guid)
  11351. {
  11352.     WorldPacket data(SMSG_FRIEND_STATUS, 10);
  11353.  
  11354.     // are we ourselves?
  11355.     if(guid == GetLowGUID())
  11356.     {
  11357.         data << uint8(FRIEND_IGNORE_SELF) << GetGUID();
  11358.         m_session->SendPacket(&data);
  11359.         return;
  11360.     }
  11361.  
  11362.     m_cache->RemoveValue64(CACHE_SOCIAL_IGNORELIST, guid);
  11363.     data << uint8(FRIEND_IGNORE_REMOVED);
  11364.     data << uint64(guid);
  11365.  
  11366.     m_session->SendPacket(&data);
  11367.  
  11368.     // remove from the db
  11369.     CharacterDatabase.Execute("DELETE FROM social_ignores WHERE character_guid = %u AND ignore_guid = %u",
  11370.                               GetLowGUID(), (uint32)guid);
  11371. }
  11372.  
  11373. bool Player::Social_IsIgnoring(PlayerInfo* m_info)
  11374. {
  11375.     return m_cache->CountValue64(CACHE_SOCIAL_IGNORELIST, m_info->guid) > 0;
  11376. }
  11377.  
  11378. bool Player::Social_IsIgnoring(uint32 guid)
  11379. {
  11380.     return m_cache->CountValue64(CACHE_SOCIAL_IGNORELIST, guid) > 0;
  11381. }
  11382.  
  11383. void Player::Social_TellFriendsOnline()
  11384. {
  11385.     if(m_cache->GetSize64(CACHE_SOCIAL_HASFRIENDLIST) == 0)
  11386.         return;
  11387.  
  11388.     PlayerCache* cache;
  11389.  
  11390.     WorldPacket data(SMSG_FRIEND_STATUS, 22);
  11391.     data << uint8(FRIEND_ONLINE) << GetGUID() << uint8(1);
  11392.     data << GetAreaID() << getLevel() << uint32(getClass());
  11393.  
  11394.     m_cache->AcquireLock64(CACHE_SOCIAL_HASFRIENDLIST);
  11395.     for(PlayerCacheMap::iterator itr = m_cache->Begin64(CACHE_SOCIAL_HASFRIENDLIST); itr != m_cache->End64(CACHE_SOCIAL_HASFRIENDLIST); ++itr)
  11396.     {
  11397.         cache = objmgr.GetPlayerCache(uint32(itr->first));
  11398.         if(cache != NULL)
  11399.         {
  11400.             cache->SendPacket(data);
  11401.             cache->DecRef();
  11402.         }
  11403.     }
  11404.     m_cache->ReleaseLock64(CACHE_SOCIAL_HASFRIENDLIST);
  11405. }
  11406.  
  11407. void Player::Social_TellFriendsOffline()
  11408. {
  11409.     if(m_cache->GetSize64(CACHE_SOCIAL_HASFRIENDLIST) == 0)
  11410.         return;
  11411.  
  11412.     WorldPacket data(SMSG_FRIEND_STATUS, 10);
  11413.     data << uint8(FRIEND_OFFLINE) << GetGUID() << uint8(0);
  11414.  
  11415.     PlayerCache* cache;
  11416.     m_cache->AcquireLock64(CACHE_SOCIAL_HASFRIENDLIST);
  11417.     for(PlayerCacheMap::iterator itr = m_cache->Begin64(CACHE_SOCIAL_HASFRIENDLIST); itr != m_cache->End64(CACHE_SOCIAL_HASFRIENDLIST); ++itr)
  11418.     {
  11419.         cache = objmgr.GetPlayerCache(uint32(itr->first));
  11420.         if(cache != NULL)
  11421.         {
  11422.             cache->SendPacket(data);
  11423.             cache->DecRef();
  11424.         }
  11425.     }
  11426.     m_cache->ReleaseLock64(CACHE_SOCIAL_HASFRIENDLIST);
  11427. }
  11428.  
  11429. void Player::Social_SendFriendList(uint32 flag)
  11430. {
  11431.     WorldPacket data(SMSG_CONTACT_LIST, 500);
  11432.     Player* plr;
  11433.     PlayerCache* cache;
  11434.  
  11435.  
  11436.     data << flag;
  11437.     data << uint32(m_cache->GetSize64(CACHE_SOCIAL_FRIENDLIST) + m_cache->GetSize64(CACHE_SOCIAL_IGNORELIST));
  11438.     m_cache->AcquireLock64(CACHE_SOCIAL_FRIENDLIST);
  11439.     for(PlayerCacheMap::iterator itr = m_cache->Begin64(CACHE_SOCIAL_FRIENDLIST); itr != m_cache->End64(CACHE_SOCIAL_FRIENDLIST); ++itr)
  11440.     {
  11441.         // guid
  11442.         data << uint64(itr->first);
  11443.  
  11444.         // friend/ignore flag.
  11445.         // 1 - friend
  11446.         // 2 - ignore
  11447.         // 3 - muted?
  11448.         data << uint32(1);
  11449.  
  11450.         // player note
  11451.         if(itr->second != NULL)
  11452.         {
  11453.             char* note = (char*)itr->second;
  11454.             data << note;
  11455.         }
  11456.         else
  11457.             data << uint8(0);
  11458.  
  11459.         // online/offline flag
  11460.         plr = objmgr.GetPlayer((uint32)itr->first);
  11461.         cache = objmgr.GetPlayerCache((uint32)itr->first);
  11462.         if(plr != NULL)
  11463.         {
  11464.             data << uint8(1);
  11465.             data << plr->GetZoneId();
  11466.             data << plr->getLevel();
  11467.             data << uint32(plr->getClass());
  11468.         }
  11469.         else
  11470.             data << uint8(0);
  11471.  
  11472.         if(cache != NULL)
  11473.             cache->DecRef();
  11474.     }
  11475.     m_cache->ReleaseLock64(CACHE_SOCIAL_FRIENDLIST);
  11476.  
  11477.     m_cache->AcquireLock64(CACHE_SOCIAL_IGNORELIST);
  11478.     PlayerCacheMap::iterator ignoreitr = m_cache->Begin64(CACHE_SOCIAL_IGNORELIST);
  11479.     for(; ignoreitr != m_cache->End64(CACHE_SOCIAL_IGNORELIST); ++ignoreitr)
  11480.     {
  11481.         // guid
  11482.         data << uint64(ignoreitr->first);
  11483.         // ignore flag - 2
  11484.         data << uint32(2);
  11485.         // no note
  11486.         data << uint8(0);
  11487.     }
  11488.  
  11489.     m_cache->ReleaseLock64(CACHE_SOCIAL_IGNORELIST);
  11490.     m_session->SendPacket(&data);
  11491. }
  11492.  
  11493. void Player::SpeedCheatDelay(uint32 ms_delay)
  11494. {
  11495. //  SDetector->SkipSamplingUntil( getMSTime() + ms_delay );
  11496.     //add triple latency to avoid client handling the spell effect with delay and we detect as cheat
  11497. //  SDetector->SkipSamplingUntil( getMSTime() + ms_delay + GetSession()->GetLatency() * 3 );
  11498.     //add constant value to make sure the effect packet was sent to client from network pool
  11499.     SDetector->SkipSamplingUntil(getMSTime() + ms_delay + GetSession()->GetLatency() * 2 + 2000);   //2 second should be enough to send our packets to client
  11500. }
  11501.  
  11502. // Reset GM speed hacks after a SafeTeleport
  11503. void Player::SpeedCheatReset()
  11504. {
  11505.     // wtf?
  11506.     SDetector->EventSpeedChange();
  11507.  
  11508.     /*
  11509.     SetSpeeds(RUN, m_runSpeed);
  11510.     SetSpeeds(SWIM, m_runSpeed);
  11511.     SetSpeeds(RUNBACK, m_runSpeed / 2); // Backwards slower, it's more natural :P
  11512.     SetSpeeds(FLY, m_flySpeed );
  11513.     */
  11514. }
  11515.  
  11516. uint32 Player::GetMaxPersonalRating()
  11517. {
  11518.     uint32 maxrating = 0;
  11519.     int i;
  11520.  
  11521.     ARCEMU_ASSERT(m_playerInfo != NULL);
  11522.  
  11523.     for(i = 0; i < NUM_ARENA_TEAM_TYPES; i++)
  11524.     {
  11525.         if(m_arenaTeams[i] != NULL)
  11526.         {
  11527.             ArenaTeamMember* m = m_arenaTeams[i]->GetMemberByGuid(m_playerInfo->guid);
  11528.             if(m)
  11529.             {
  11530.                 if(m->PersonalRating > maxrating) maxrating = m->PersonalRating;
  11531.             }
  11532.             else
  11533.             {
  11534.                 LOG_ERROR("%s: GetMemberByGuid returned NULL for player guid = %u", __FUNCTION__, m_playerInfo->guid);
  11535.             }
  11536.         }
  11537.     }
  11538.  
  11539.     return maxrating;
  11540. }
  11541. /***********************************
  11542. * Give player full hp/mana
  11543. ***********************************/
  11544.  
  11545. void Player::FullHPMP()
  11546. {
  11547.     if(IsDead())
  11548.         ResurrectPlayer();
  11549.     SetHealth(GetMaxHealth());
  11550.     SetPower(POWER_TYPE_MANA, GetMaxPower(POWER_TYPE_MANA));
  11551.     SetPower(POWER_TYPE_ENERGY, GetMaxPower(POWER_TYPE_ENERGY));
  11552. }
  11553.  
  11554. /**********************************************
  11555. * Remove all temporary enchants from all items
  11556. **********************************************/
  11557. void Player::RemoveTempEnchantsOnArena()
  11558. {
  11559.     ItemInterface* itemi = GetItemInterface();
  11560.  
  11561.     // Loop through all equipment items
  11562.     for(uint32 x = EQUIPMENT_SLOT_START; x < EQUIPMENT_SLOT_END; ++x)
  11563.     {
  11564.         Item* it = itemi->GetInventoryItem(static_cast<int16>(x));
  11565.  
  11566.         if(it != NULL)
  11567.         {
  11568.             it->RemoveAllEnchantments(true);
  11569.         }
  11570.     }
  11571.  
  11572.     // Loop through all your bags..
  11573.     for(uint32 x = INVENTORY_SLOT_BAG_START; x < INVENTORY_SLOT_BAG_END; ++x)
  11574.     {
  11575.         Item* it = itemi->GetInventoryItem(static_cast<int16>(x));
  11576.  
  11577.         if(it != NULL)
  11578.         {
  11579.             if(it->IsContainer())
  11580.             {
  11581.                 Container* bag = TO< Container* >(it);
  11582.                 for(uint32 ci = 0; ci < bag->GetProto()->ContainerSlots; ++ci)
  11583.                 {
  11584.                     it = bag->GetItem(static_cast<int16>(ci));
  11585.                     if(it != NULL)
  11586.                         it->RemoveAllEnchantments(true);
  11587.                 }
  11588.             }
  11589.         }
  11590.     }
  11591.  
  11592.     // Loop through all your invintory items
  11593.     for(uint32 x = INVENTORY_SLOT_ITEM_START; x < INVENTORY_SLOT_ITEM_END; ++x)
  11594.     {
  11595.         Item* it = itemi->GetInventoryItem(static_cast<int16>(x));
  11596.  
  11597.         if(it != NULL)
  11598.         {
  11599.             it->RemoveAllEnchantments(true);
  11600.         }
  11601.     }
  11602. }
  11603.  
  11604. void Player::PlaySound(uint32 sound_id)
  11605. {
  11606.     WorldPacket data(SMSG_PLAY_SOUND, 4);
  11607.     data << sound_id;
  11608.     GetSession()->SendPacket(&data);
  11609. }
  11610.  
  11611. //really need to work on the speed of this. This will be called on a lot of events
  11612. /*void Player::Event_Achiement_Received(uint32 achievementtype,uint32 pentry,uint32 pvalue)
  11613. {
  11614.     for (uint32 i= 0; i<dbcAchievementCriteriaStore.GetNumRows(); i++)
  11615.     {
  11616.         AchievementCriteriaEntry *criteria = dbcAchievementCriteriaStore.LookupRow(i);
  11617.         uint32 achientry = criteria->ID;
  11618.         //check if we need to even know about this criteria
  11619.         if( !criteria || criteria->requiredType != achievementtype )
  11620.             continue;
  11621.  
  11622.         //we will send only this if it is required for this type
  11623.         if( pentry && criteria->requiredAchievementRelatedEntry != pentry )
  11624.             continue;
  11625.  
  11626.         //check if this achievement is even for us
  11627.         AchievementEntry *achi = dbcAchievementStore.LookupEntry( criteria->referredAchievement );
  11628.  
  11629.         if( !achi
  11630. //          || !( achi->factionFlag == -1 || (isAlliance(this) && achi->factionFlag == 1) || (!isAlliance(this) && achi->factionFlag == 0 ) ) ||
  11631. //          || achi->flags & ACHIEVEMENT_FLAG_COUNTER
  11632. //          || ((criteria->groupFlag & ACHIEVEMENT_CRITERIA_GROUP_NOT_IN_GROUP) && GetGroup() )
  11633.             )
  11634.             continue;
  11635.  
  11636.         if( !m_achievements[ achientry ] )
  11637.             m_achievements[ achientry ] = new AchievementVal;
  11638.  
  11639.         //check if we can finish = get achievement points on this
  11640. //      if( pvalue < criteria->requiredAchievementRelatedCount )
  11641. //          SendAchievmentStatus( achientry );
  11642. //      else
  11643.             if( pvalue >= criteria->requiredAchievementRelatedCount
  11644.                 &&
  11645.                 m_achievements[ achientry ]->cur_value < criteria->requiredAchievementRelatedCount
  11646.                 )
  11647.             {
  11648. //              m_achievement_points += achi->points;
  11649.                 m_achievements[ achientry ]->completed_at_stamp = (uint32)UNIXTIME;
  11650.                 SendAchievmentEarned( criteria->referredAchievement );
  11651.             }
  11652.  
  11653.         //if we got here then we could update our status
  11654.         m_achievements[ achientry ]->cur_value = pvalue;
  11655.     }
  11656.  
  11657. }
  11658.  
  11659. void Player::SendAchievmentEarned( uint32 archiId, uint32 at_stamp )
  11660. {
  11661.     WorldPacket data( SMSG_ACHIEVEMENT_EARNED, 30);
  11662.     data << GetNewGUID();
  11663.     data << uint32( archiId );
  11664.     if( at_stamp )
  11665.         data << uint32( at_stamp ); //seems to be something that increases in time. Also seems to a large enough value for time
  11666.     else data << uint32( UNIXTIME );
  11667.     data << uint32(0);
  11668.     GetSession()->SendPacket(&data);
  11669. }*/
  11670.  
  11671.  
  11672. void Player::SendAchievmentStatus(uint32 criteriaid, uint32 new_value, uint32 at_stamp)
  11673. {
  11674.     /*
  11675.     noob warlock
  11676.     E2 14 00 00 - some index ? does not seem to be criteria id though
  11677.     01 - is this related to the indexes ? Seems to be 1 all the time
  11678.     2B - some index ?
  11679.     0F 82 43 97 01 - packed guid
  11680.     00 00 00 00
  11681.     B4 82 94 08
  11682.     00 00 00 00
  11683.     00 00 00 00
  11684.  
  11685.     E2 14 00 00 01 2B 0F 82 43 97 01 00 00 00 00 B4 82 94 08 00 00 00 00 00 00 00 00
  11686.     E2 14 00 00 01 53 0F 82 43 97 01 00 00 00 00 B4 82 94 08 00 00 00 00 00 00 00 00
  11687.     E3 14 00 00 01 BB 0F 82 43 97 01 00 00 00 00 B4 82 94 08 00 00 00 00 00 00 00 00
  11688.     E4 14 00 00 01 15 0F 82 43 97 01 00 00 00 00 B4 82 94 08 00 00 00 00 00 00 00 00
  11689.     E5 14 00 00 01 15 0F 82 43 97 01 00 00 00 00 B4 82 94 08 00 00 00 00 00 00 00 00
  11690.     E8 14 00 00 01 18 0F 82 43 97 01 00 00 00 00 B4 82 94 08 00 00 00 00 00 00 00 00
  11691.     E6 14 00 00 01 16 0F 82 43 97 01 00 00 00 00 B4 82 94 08 00 00 00 00 00 00 00 00
  11692.     E7 14 00 00 01 18 0F 82 43 97 01 00 00 00 00 B4 82 94 08 00 00 00 00 00 00 00 00
  11693.     EA 14 00 00 01 2A 0F 82 43 97 01 00 00 00 00 B4 82 94 08 00 00 00 00 00 00 00 00
  11694.     EA 14 00 00 01 52 0F 82 43 97 01 00 00 00 00 B4 82 94 08 00 00 00 00 00 00 00 00
  11695.     EA 14 00 00 01 55 0F 82 43 97 01 00 00 00 00 B4 82 94 08 00 00 00 00 00 00 00 00
  11696.     EA 14 00 00 01 57 0F 82 43 97 01 00 00 00 00 B4 82 94 08 00 00 00 00 00 00 00 00
  11697.     EA 14 00 00 01 5E 0F 82 43 97 01 00 00 00 00 B4 82 94 08 00 00 00 00 00 00 00 00
  11698.     EA 14 00 00 01 62 0F 82 43 97 01 00 00 00 00 B4 82 94 08 00 00 00 00 00 00 00 00
  11699.     */
  11700.     /*WorldPacket data( SMSG_CRITERIA_UPDATE, 30);
  11701.     data << uint32(criteriaid);
  11702.     data << uint8(1);
  11703.     data << uint8(1); //this is some ID or something maybe merge with previous value ? Maybe it is value for criteria ?
  11704.     data << GetNewGUID();
  11705.     data << uint32(0);
  11706.     if( at_stamp )
  11707.         data << uint32( at_stamp / 8.50194274f ); //seems to be something that increases in time. Also seems to a large enough value for time
  11708.     else
  11709.         data << uint32( UNIXTIME / 8.50194274f ); //seems to be something that increases in time. Also seems to a large enough value for time
  11710.     data << uint32(0); //duration
  11711.     data << uint32(0); //duration left
  11712.     GetSession()->SendPacket(&data);*/
  11713. }
  11714. //send completed criteria's to client
  11715. /*void Player::SendAllAchievementStatus()
  11716. {
  11717.     std::map<uint32,AchievementVal*>::iterator itr;
  11718.     for(itr=m_achievements.begin();itr!=m_achievements.end();itr++)
  11719.     {
  11720. //      uint32 critentry = itr->first;
  11721. //      AchievementCriteriaEntry *criteria = dbcAchievementCriteriaStore.LookupEntry( critentry );
  11722. //      if( !critentry ) continue; //wtf ?
  11723. //      if( criteria->requiredAchievementRelatedCount > itr->second )
  11724.         SendAchievmentStatus( itr->first, itr->second->cur_value, itr->second->completed_at_stamp );
  11725.     }
  11726. }
  11727.  
  11728. void Player::SendAllAchievementEarned()
  11729. {
  11730.     std::map<uint32,AchievementVal*>::iterator itr;
  11731.     for(itr=m_achievements.begin();itr!=m_achievements.end();itr++)
  11732.     {
  11733.         uint32 critentry = itr->first;
  11734.         AchievementCriteriaEntry *criteria = dbcAchievementCriteriaStore.LookupEntry( critentry );
  11735.         if( !criteria )
  11736.             continue; //wtf ?
  11737.         if( criteria->requiredAchievementRelatedCount <= itr->second->cur_value )
  11738.             SendAchievmentEarned( criteria->referredAchievement );
  11739.     }
  11740. }*/
  11741.  
  11742. //this packet might get huge in time. Might reach over 1.2 MByte !
  11743. /*void Player::SendAllAchievementData()
  11744. {
  11745.     //we are cheating with these. Something is enabling client side the achievemnts menu
  11746.     WorldPacket data(SMSG_ALL_ACHIEVEMENT_DATA, 500);
  11747.     uint32 found_finished= 0;
  11748.  
  11749.     //generate block of finished acheivemnts
  11750.     std::map<uint32,AchievementVal*>::iterator itr;
  11751.     for(itr=m_achievements.begin();itr!=m_achievements.end();itr++)
  11752.     {
  11753.         uint32 critentry = itr->first;
  11754.         AchievementCriteriaEntry *criteria = dbcAchievementCriteriaStore.LookupEntry( critentry );
  11755.         if( !criteria )
  11756.             continue; //wtf ?
  11757.         if( criteria->requiredAchievementRelatedCount <= itr->second->cur_value )
  11758.         {
  11759.             found_finished++;
  11760.             data << uint32( criteria->referredAchievement );
  11761.             data << uint32( itr->second->completed_at_stamp / 8.50194274f); // -sometimes it is durations
  11762.         }
  11763.     }
  11764.     data << uint32( 0xFFFFFFFF ); //maybe a terminator like a null terminated string ?
  11765. */
  11766. //now the block for those : SMSG_CRITERIA_UPDATE
  11767. /*
  11768.             //sometimes this is duration left
  11769.             data << uint32( criteria->ID );
  11770.             data << uint8( 1 );
  11771.             data << uint8( itr->second->cur_value ); //probably not since it does not fit into this size. Also seems to change from time to time
  11772.             data << GetNewGUID();
  11773.             data << uint32( 0 ); //no idea. was always 0
  11774.             data << uint32( UNIXTIME ); //seems to be something that increases in time. Also seems to a large enough value for time
  11775.             data << uint32(0); //duration
  11776.             data << uint32(0); //duration left
  11777. */
  11778. /*  if( found_finished )
  11779.         GetSession()->SendPacket(&data);
  11780. }*/
  11781.  
  11782. void Player::UpdatePowerAmm()
  11783. {
  11784.     WorldPacket data(SMSG_POWER_UPDATE, 5);
  11785.     FastGUIDPack(data, GetGUID());
  11786.     data << uint8(GetPowerType());
  11787.     data << GetUInt32Value(UNIT_FIELD_POWER1 + GetPowerType());
  11788.     SendMessageToSet(&data, true);
  11789. }
  11790. // Initialize Glyphs or update them after level change
  11791. void Player::UpdateGlyphs()
  11792. {
  11793.     uint32 level = getLevel();
  11794.  
  11795.     // Init glyph slots
  11796.     if(level >= 15)
  11797.     {
  11798.         GlyphSlotEntry* gse;
  11799.         uint32 y = 0;
  11800.         for(uint32 i = 0; i < dbcGlyphSlot.GetNumRows(); ++i)
  11801.         {
  11802.             gse = dbcGlyphSlot.LookupRow(i);
  11803.             if(gse->Slot > 0)
  11804.                 SetUInt32Value(PLAYER_FIELD_GLYPH_SLOTS_1 + y++, gse->Id);
  11805.         }
  11806.     }
  11807.  
  11808.     if(level > 80)
  11809.         level = 80;
  11810.  
  11811.     // Enable number of glyphs depending on level
  11812.     SetUInt32Value(PLAYER_GLYPHS_ENABLED, glyphMask[level]);
  11813. }
  11814.  
  11815. // Fills fields from firstField to firstField+fieldsNum-1 with integers from the string
  11816. void Player::LoadFieldsFromString(const char* string, uint32 firstField, uint32 fieldsNum)
  11817. {
  11818.     if(string == NULL)
  11819.         return;
  11820.     char* end;
  11821.     char* start = (char*) string;
  11822.     for(uint32 Counter = 0; Counter < fieldsNum; Counter++)
  11823.     {
  11824.         end = strchr(start, ',');
  11825.         if(!end)
  11826.             break;
  11827.         *end = 0;
  11828.         SetUInt32Value(firstField + Counter, atol(start));
  11829.         start = end + 1;
  11830.     }
  11831. }
  11832.  
  11833. void Player::SetKnownTitle(RankTitles title, bool set)
  11834. {
  11835.     if(!HasTitle(title) ^ set)
  11836.         return;
  11837.  
  11838.     uint64 current = GetUInt64Value(PLAYER__FIELD_KNOWN_TITLES + ((title >> 6) << 1));
  11839.     if(set)
  11840.         SetUInt64Value(PLAYER__FIELD_KNOWN_TITLES + ((title >> 6) << 1), current | uint64(1) << (title % 64));
  11841.     else
  11842.         SetUInt64Value(PLAYER__FIELD_KNOWN_TITLES + ((title >> 6) << 1), current & ~uint64(1) << (title % 64));
  11843.  
  11844.     WorldPacket data(SMSG_TITLE_EARNED, 8);
  11845.     data << uint32(title) << uint32(set ? 1 : 0);
  11846.     m_session->SendPacket(&data);
  11847. }
  11848.  
  11849. void Player::SendTriggerMovie(uint32 movieID)
  11850. {
  11851.     if(m_session)
  11852.         m_session->OutPacket(SMSG_TRIGGER_MOVIE, 4, &movieID);
  11853. }
  11854.  
  11855. uint32 Player::GetInitialFactionId()
  11856. {
  11857.  
  11858.     PlayerCreateInfo* pci = objmgr.GetPlayerCreateInfo(getRace(), getClass());
  11859.     if(pci)
  11860.         return pci->factiontemplate;
  11861.     else
  11862.         return 35;
  11863. }
  11864.  
  11865. void Player::CalcExpertise()
  11866. {
  11867.     int32 modifier = 0;
  11868.     int32 val = 0;
  11869.     SpellEntry* entry = NULL;
  11870.     Item* itMH = NULL;
  11871.     Item* itOH = NULL;
  11872.  
  11873.     SetUInt32Value(PLAYER_EXPERTISE, 0);
  11874.     SetUInt32Value(PLAYER_OFFHAND_EXPERTISE, 0);
  11875.  
  11876.     for(uint32 x = MAX_TOTAL_AURAS_START; x < MAX_TOTAL_AURAS_END; ++x)
  11877.     {
  11878.         if(m_auras[x] != NULL && m_auras[x]->HasModType(SPELL_AURA_EXPERTISE))
  11879.         {
  11880.             entry = m_auras[x]->m_spellProto;
  11881.             val = m_auras[x]->GetModAmountByMod();
  11882.  
  11883.             if(entry->EquippedItemSubClass != 0)
  11884.             {
  11885.                 itMH = GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_MAINHAND);
  11886.                 itOH = GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_OFFHAND);
  11887.                 uint32 reqskillMH = 0;
  11888.                 uint32 reqskillOH = 0;
  11889.  
  11890.                 if(itMH != NULL)
  11891.                     reqskillMH = entry->EquippedItemSubClass & (((uint32)1) << itMH->GetProto()->SubClass);
  11892.                 if(itOH != NULL)
  11893.                     reqskillOH = entry->EquippedItemSubClass & (((uint32)1) << itOH->GetProto()->SubClass);
  11894.  
  11895.                 if(reqskillMH != 0 || reqskillOH != 0)
  11896.                     modifier = +val;
  11897.             }
  11898.             else
  11899.                 modifier += val;
  11900.         }
  11901.     }
  11902.  
  11903.     ModUnsigned32Value(PLAYER_EXPERTISE, (int32)CalcRating(PLAYER_RATING_MODIFIER_EXPERTISE) + modifier);
  11904.     ModUnsigned32Value(PLAYER_OFFHAND_EXPERTISE, (int32)CalcRating(PLAYER_RATING_MODIFIER_EXPERTISE) + modifier);
  11905.     UpdateStats();
  11906. }
  11907.  
  11908. void Player::UpdateKnownCurrencies(uint32 itemId, bool apply)
  11909. {
  11910.     if(CurrencyTypesEntry const* ctEntry = dbcCurrencyTypesStore.LookupEntryForced(itemId))
  11911.     {
  11912.         if(apply)
  11913.         {
  11914.             uint64 oldval = GetUInt64Value(PLAYER_FIELD_KNOWN_CURRENCIES);
  11915.             uint64 newval = oldval | (uint64)(((uint32)1) << (ctEntry->BitIndex - 1));
  11916.             SetUInt64Value(PLAYER_FIELD_KNOWN_CURRENCIES, newval);
  11917.         }
  11918.         else
  11919.         {
  11920.             uint64 oldval = GetUInt64Value(PLAYER_FIELD_KNOWN_CURRENCIES);
  11921.             uint64 newval = oldval & ~(((uint32)1) << (ctEntry->BitIndex - 1));
  11922.             SetUInt64Value(PLAYER_FIELD_KNOWN_CURRENCIES, newval);
  11923.         }
  11924.     }
  11925. }
  11926.  
  11927. void Player::RemoveItemByGuid(uint64 GUID)
  11928. {
  11929.     this->GetItemInterface()->SafeFullRemoveItemByGuid(GUID);
  11930. }
  11931.  
  11932. void Player::SendAvailSpells(SpellShapeshiftForm* ssf, bool active)
  11933. {
  11934.     if(active)
  11935.     {
  11936.         if(!ssf)
  11937.             return;
  11938.  
  11939.         WorldPacket data(SMSG_PET_SPELLS, 8 * 4 + 20);
  11940.         data << GetGUID();
  11941.         data << uint32(0) << uint32(0);
  11942.         data << uint8(0) << uint8(0) << uint16(0);
  11943.  
  11944.         // Send the spells
  11945.         for(uint32 i = 0; i < 8; i++)
  11946.         {
  11947.             data << uint16(ssf->spells[i]) << uint16(DEFAULT_SPELL_STATE);
  11948.         }
  11949.  
  11950.         data << uint8(1);
  11951.         data << uint8(0);
  11952.         GetSession()->SendPacket(&data);
  11953.     }
  11954.     else
  11955.     {
  11956.         WorldPacket data(SMSG_PET_SPELLS, 10);
  11957.         data << uint64(0);
  11958.         data << uint32(0);
  11959.         GetSession()->SendPacket(&data);
  11960.     }
  11961. }
  11962.  
  11963. bool Player::IsPvPFlagged()
  11964. {
  11965.     return HasByteFlag(UNIT_FIELD_BYTES_2, 1, U_FIELD_BYTES_FLAG_PVP);
  11966. }
  11967.  
  11968. void Player::SetPvPFlag()
  11969. {
  11970.     StopPvPTimer();
  11971.  
  11972.     SetByteFlag(UNIT_FIELD_BYTES_2, 1, U_FIELD_BYTES_FLAG_PVP);
  11973.     SetFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP);
  11974.  
  11975.     summonhandler.SetPvPFlags();
  11976.  
  11977.     // flagging the pet too for PvP, if we have one
  11978.     std::list<Pet*> summons = GetSummons();
  11979.     for(std::list<Pet*>::iterator itr = summons.begin(); itr != summons.end(); ++itr)
  11980.     {
  11981.         (*itr)->SetPvPFlag();
  11982.     }
  11983.  
  11984.     if(CombatStatus.IsInCombat())
  11985.         SetFlag(PLAYER_FLAGS, 0x100);
  11986.  
  11987. }
  11988.  
  11989. void Player::RemovePvPFlag()
  11990. {
  11991.     StopPvPTimer();
  11992.     RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, U_FIELD_BYTES_FLAG_PVP);
  11993.     RemoveFlag(PLAYER_FLAGS, PLAYER_FLAG_PVP);
  11994.  
  11995.     summonhandler.RemovePvPFlags();
  11996.  
  11997.     // If we have a pet we will remove the pvp flag from that too
  11998.     std::list<Pet*> summons = GetSummons();
  11999.     for(std::list<Pet*>::iterator itr = summons.begin(); itr != summons.end(); ++itr)
  12000.     {
  12001.         (*itr)->RemovePvPFlag();
  12002.     }
  12003. }
  12004.  
  12005. bool Player::IsFFAPvPFlagged()
  12006. {
  12007.     return HasByteFlag(UNIT_FIELD_BYTES_2, 1, U_FIELD_BYTES_FLAG_FFA_PVP);
  12008. }
  12009.  
  12010. void Player::SetFFAPvPFlag()
  12011. {
  12012.     StopPvPTimer();
  12013.     SetByteFlag(UNIT_FIELD_BYTES_2, 1, U_FIELD_BYTES_FLAG_FFA_PVP);
  12014.     SetFlag(PLAYER_FLAGS, PLAYER_FLAG_FREE_FOR_ALL_PVP);
  12015.  
  12016.     summonhandler.SetFFAPvPFlags();
  12017.  
  12018.     // flagging the pet too for FFAPvP, if we have one
  12019.     std::list<Pet*> summons = GetSummons();
  12020.     for(std::list<Pet*>::iterator itr = summons.begin(); itr != summons.end(); ++itr)
  12021.     {
  12022.         (*itr)->SetFFAPvPFlag();
  12023.     }
  12024. }
  12025.  
  12026. void Player::RemoveFFAPvPFlag()
  12027. {
  12028.     StopPvPTimer();
  12029.     RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, U_FIELD_BYTES_FLAG_FFA_PVP);
  12030.     RemoveFlag(PLAYER_FLAGS, PLAYER_FLAG_FREE_FOR_ALL_PVP);
  12031.  
  12032.     summonhandler.RemoveFFAPvPFlags();
  12033.  
  12034.     // If we have a pet we will remove the FFA pvp flag from that too
  12035.     std::list<Pet*> summons = GetSummons();
  12036.     for(std::list<Pet*>::iterator itr = summons.begin(); itr != summons.end(); ++itr)
  12037.     {
  12038.         (*itr)->RemoveFFAPvPFlag();
  12039.     }
  12040. }
  12041.  
  12042. bool Player::IsSanctuaryFlagged()
  12043. {
  12044.     return HasByteFlag(UNIT_FIELD_BYTES_2, 1 , U_FIELD_BYTES_FLAG_SANCTUARY);
  12045. }
  12046.  
  12047. void Player::SetSanctuaryFlag()
  12048. {
  12049.     SetByteFlag(UNIT_FIELD_BYTES_2, 1, U_FIELD_BYTES_FLAG_SANCTUARY);
  12050.  
  12051.     summonhandler.SetSanctuaryFlags();
  12052.  
  12053.     // flagging the pet too for sanctuary, if we have one
  12054.     std::list<Pet*> summons = GetSummons();
  12055.     for(std::list<Pet*>::iterator itr = summons.begin(); itr != summons.end(); ++itr)
  12056.     {
  12057.         (*itr)->SetSanctuaryFlag();
  12058.     }
  12059. }
  12060.  
  12061. void Player::RemoveSanctuaryFlag()
  12062. {
  12063.     RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, U_FIELD_BYTES_FLAG_SANCTUARY);
  12064.  
  12065.     summonhandler.RemoveSanctuaryFlags();
  12066.  
  12067.     // If we have a pet we will remove the sanctuary flag from that too
  12068.     std::list<Pet*> summons = GetSummons();
  12069.     for(std::list<Pet*>::iterator itr = summons.begin(); itr != summons.end(); ++itr)
  12070.     {
  12071.         (*itr)->RemoveSanctuaryFlag();
  12072.     }
  12073. }
  12074.  
  12075. void Player::SendExploreXP(uint32 areaid, uint32 xp)
  12076. {
  12077.  
  12078.     WorldPacket data(SMSG_EXPLORATION_EXPERIENCE, 8);
  12079.     data << uint32(areaid);
  12080.     data << uint32(xp);
  12081.     m_session->SendPacket(&data);
  12082. }
  12083.  
  12084. void Player::HandleSpellLoot(uint32 itemid)
  12085. {
  12086.     Loot loot;
  12087.     std::vector< __LootItem >::iterator itr;
  12088.  
  12089.     lootmgr.FillItemLoot(&loot, itemid);
  12090.  
  12091.     for(itr = loot.items.begin(); itr != loot.items.end(); ++itr)
  12092.     {
  12093.         uint32 looteditemid = itr->item.itemproto->ItemId;
  12094.         uint32 count = itr->iItemsCount;
  12095.  
  12096.         m_ItemInterface->AddItemById(looteditemid, count, 0);
  12097.     }
  12098. }
  12099.  
  12100.  
  12101. void Player::LearnTalent(uint32 talentid, uint32 rank, bool isPreviewed)
  12102. {
  12103.     uint32 CurTalentPoints = m_specs[ m_talentActiveSpec ].GetTP();   // Calculate free points in active spec
  12104.  
  12105.     if(CurTalentPoints == 0)
  12106.         return;
  12107.  
  12108.     if(rank > 4)
  12109.         return;
  12110.  
  12111.     TalentEntry* talentInfo = dbcTalent.LookupEntryForced(talentid);
  12112.     if(!talentInfo)return;
  12113.  
  12114.     if(objmgr.IsSpellDisabled(talentInfo->RankID[rank]))
  12115.     {
  12116.         if(IsInWorld())
  12117.             SendCastResult(talentInfo->RankID[rank], SPELL_FAILED_SPELL_UNAVAILABLE, 0, 0);
  12118.  
  12119.         return;
  12120.     }
  12121.  
  12122.     // Check if it requires another talent
  12123.     if(talentInfo->DependsOn > 0)
  12124.     {
  12125.         TalentEntry* depTalentInfo = NULL;
  12126.         depTalentInfo = dbcTalent.LookupEntryForced(talentInfo->DependsOn);
  12127.         if(depTalentInfo)
  12128.         {
  12129.             bool hasEnoughRank = false;
  12130.             for(int i = 0; i < 5; ++i)
  12131.             {
  12132.                 if(depTalentInfo->RankID[i] != 0)
  12133.                 {
  12134.                     if(HasSpell(depTalentInfo->RankID[i]))
  12135.                     {
  12136.                         hasEnoughRank = true;
  12137.                         break;
  12138.                     }
  12139.                 }
  12140.             }
  12141.             if(!hasEnoughRank)
  12142.                 return;
  12143.         }
  12144.     }
  12145.  
  12146.     // Find out how many points we have in this field
  12147.     uint32 spentPoints = 0;
  12148.  
  12149.     // points we are spending now
  12150.     int32 points = 0;
  12151.  
  12152.     uint32 tTree = talentInfo->TalentTree;
  12153.     uint32 cl = getClass();
  12154.  
  12155.     unsigned int k;
  12156.     for(k = 0; k < 3; ++k)
  12157.     {
  12158.         if(tTree == TalentTreesPerClass[cl][k])
  12159.         {
  12160.             break;
  12161.         }
  12162.     }
  12163.     if(3 == k)
  12164.     {
  12165.         // cheater!
  12166.         m_session->Disconnect();
  12167.         return;
  12168.     }
  12169.  
  12170.  
  12171.     if(talentInfo->Row > 0)
  12172.     {
  12173.         for(unsigned int i = 0; i < dbcTalent.GetNumRows(); ++i)           // Loop through all talents.
  12174.         {
  12175.             // Someday, someone needs to revamp
  12176.             TalentEntry* tmpTalent = dbcTalent.LookupRowForced(i);
  12177.             if(tmpTalent)                                  // the way talents are tracked
  12178.             {
  12179.                 if(tmpTalent->TalentTree == tTree)
  12180.                 {
  12181.                     for(int j = 0; j < 5; j++)
  12182.                     {
  12183.                         if(tmpTalent->RankID[j] != 0)
  12184.                         {
  12185.                             if(HasSpell(tmpTalent->RankID[j]))
  12186.                             {
  12187.                                 spentPoints += j + 1;
  12188.                                 //  break;
  12189.                             }
  12190.                         }
  12191.                         else
  12192.                             break;
  12193.                     }
  12194.                 }
  12195.             }
  12196.         }
  12197.     }
  12198.  
  12199.     uint32 spellid = talentInfo->RankID[ rank ];
  12200.     if(spellid == 0)
  12201.     {
  12202.         LOG_DETAIL("Talent: %u Rank: %u = 0", talentid, rank);
  12203.     }
  12204.     else
  12205.     {
  12206.         if(spentPoints < (talentInfo->Row * 5))          // Min points spent
  12207.         {
  12208.             return;
  12209.         }
  12210.  
  12211.  
  12212.         // Check if we already have the talent with the same or higher rank
  12213.         for(unsigned int i = rank; i < 5; ++i)
  12214.             if(talentInfo->RankID[i] != 0 && HasSpell(talentInfo->RankID[i]))
  12215.                 return; // cheater
  12216.  
  12217.         if(rank > 0)
  12218.         {
  12219.             // If we are not learning thru the preview system, check if we have the lower rank of the talent
  12220.             if(talentInfo->RankID[rank - 1] && !HasSpell(talentInfo->RankID[rank - 1]) && !isPreviewed)
  12221.             {
  12222.                 // cheater
  12223.                 return;
  12224.             }
  12225.  
  12226.             int32 highest = 0;
  12227.             for( highest = 4; highest >= 0; highest-- )
  12228.                 if( ( talentInfo->RankID[ highest ] != 0 ) && HasSpell( talentInfo->RankID[ highest ] ) )
  12229.                     break;
  12230.  
  12231.             points = static_cast< int32 >( rank ) - highest;
  12232.         }else
  12233.             points = 1;
  12234.  
  12235.         if( static_cast< uint32 >( points ) > CurTalentPoints )
  12236.             return;
  12237.  
  12238.         if(!(HasSpell(spellid)))
  12239.         {
  12240.             addSpell(spellid);
  12241.  
  12242.             SpellEntry* spellInfo = dbcSpell.LookupEntry(spellid);
  12243.  
  12244.             if(rank > 0)
  12245.             {
  12246.                 uint32 respellid = talentInfo->RankID[rank - 1];
  12247.                 if(respellid && !isPreviewed)
  12248.                 {
  12249.                     removeSpell(respellid, false, false, 0);
  12250.                     RemoveAura(respellid);
  12251.                 }
  12252.             }
  12253.  
  12254.             if(spellInfo->Attributes & ATTRIBUTES_PASSIVE || ((spellInfo->Effect[0] == SPELL_EFFECT_LEARN_SPELL ||
  12255.                     spellInfo->Effect[1] == SPELL_EFFECT_LEARN_SPELL ||
  12256.                     spellInfo->Effect[2] == SPELL_EFFECT_LEARN_SPELL)
  12257.                     && ((spellInfo->c_is_flags & SPELL_FLAG_IS_EXPIREING_WITH_PET) == 0 || ((spellInfo->c_is_flags & SPELL_FLAG_IS_EXPIREING_WITH_PET) && GetSummon())))
  12258.               )
  12259.             {
  12260.                 if(spellInfo->RequiredShapeShift && !((uint32)1 << (GetShapeShift() - 1) & spellInfo->RequiredShapeShift))
  12261.                 {
  12262.                     // do nothing
  12263.                 }
  12264.                 else
  12265.                 {
  12266.                     Spell* sp = sSpellFactoryMgr.NewSpell(this, spellInfo, true, NULL);
  12267.                     SpellCastTargets tgt;
  12268.                     tgt.m_unitTarget = this->GetGUID();
  12269.                     sp->prepare(&tgt);
  12270.                 }
  12271.             }
  12272.  
  12273.             SetCurrentTalentPoints( CurTalentPoints - static_cast< uint32 >( points ) );
  12274.             m_specs[m_talentActiveSpec].AddTalent(talentid, uint8(rank));
  12275.             smsg_TalentsInfo(false);
  12276.         }
  12277.     }
  12278. }
  12279.  
  12280. void Player::SetDungeonDifficulty(uint32 diff)
  12281. {
  12282.     iInstanceType = diff;
  12283. }
  12284.  
  12285. uint32 Player::GetDungeonDifficulty()
  12286. {
  12287.     return iInstanceType;
  12288. }
  12289.  
  12290. void Player::SetRaidDifficulty(uint32 diff)
  12291. {
  12292.     m_RaidDifficulty = diff;
  12293. }
  12294.  
  12295. uint32 Player::GetRaidDifficulty()
  12296. {
  12297.     return m_RaidDifficulty;
  12298. }
  12299.  
  12300. void Player::SendPreventSchoolCast(uint32 SpellSchool, uint32 unTimeMs)
  12301. {
  12302.     WorldPacket data(SMSG_SPELL_COOLDOWN, 8 + 1 + mSpells.size() * 8);
  12303.     data << GetGUID();
  12304.     data << uint8(0x0);
  12305.  
  12306.     SpellSet::iterator sitr;
  12307.     for(sitr = mSpells.begin(); sitr != mSpells.end(); ++sitr)
  12308.     {
  12309.         uint32 SpellId = (*sitr);
  12310.  
  12311.         SpellEntry* spellInfo = dbcSpell.LookupEntry(SpellId);
  12312.  
  12313.         if(!spellInfo)
  12314.         {
  12315.             ASSERT(spellInfo);
  12316.             continue;
  12317.         }
  12318.  
  12319.         // Not send cooldown for this spells
  12320.         if(spellInfo->Attributes & ATTRIBUTES_TRIGGER_COOLDOWN)
  12321.             continue;
  12322.  
  12323.         if(spellInfo->School == SpellSchool)
  12324.         {
  12325.             data << uint32(SpellId);
  12326.             data << uint32(unTimeMs);                       // in m.secs
  12327.         }
  12328.     }
  12329.     GetSession()->SendPacket(&data);
  12330. }
  12331.  
  12332.  
  12333. void Player::ToggleXpGain()
  12334. {
  12335.  
  12336.     if(m_XpGain)
  12337.         m_XpGain = false;
  12338.     else
  12339.         m_XpGain = true;
  12340.  
  12341. }
  12342.  
  12343. bool Player::CanGainXp()
  12344. {
  12345.     return m_XpGain;
  12346. }
  12347.  
  12348. void Player::RemoveGarbageItems()
  12349. {
  12350.     std::list< Item* >::iterator itr;
  12351.  
  12352.     for(itr = m_GarbageItems.begin(); itr != m_GarbageItems.end(); ++itr)
  12353.     {
  12354.         Item* it = *itr;
  12355.  
  12356.         delete it;
  12357.     }
  12358.  
  12359.     m_GarbageItems.clear();
  12360. }
  12361.  
  12362. void Player::AddGarbageItem(Item* it)
  12363. {
  12364.     m_GarbageItems.push_back(it);
  12365. }
  12366.  
  12367. void Player::SendTeleportAckMsg(const LocationVector & v)
  12368. {
  12369.  
  12370.     ///////////////////////////////////////
  12371.     //Update player on the client with TELEPORT_ACK
  12372.     SetPlayerStatus(TRANSFER_PENDING);
  12373.  
  12374.     WorldPacket data(MSG_MOVE_TELEPORT_ACK, 80);
  12375.  
  12376.     data << GetNewGUID();
  12377.     data << uint32(2);   // flags
  12378.     data << getMSTime();
  12379.     data << uint16(0);
  12380.     data << float(0);
  12381.     data << v;
  12382.     data << v.o;
  12383.     data << uint16(2);
  12384.     data << uint8(0);
  12385.  
  12386.     m_session->SendPacket(&data);
  12387. }
  12388.  
  12389. void Player::OutPacket(uint16 opcode, uint16 len, const void* data)
  12390. {
  12391.     ARCEMU_ASSERT(m_session != NULL);
  12392.     m_session->OutPacket(opcode, len, data);
  12393. }
  12394.  
  12395. void Player::SendPacket(WorldPacket* packet)
  12396. {
  12397.     ARCEMU_ASSERT(m_session != NULL);
  12398.     m_session->SendPacket(packet);
  12399. }
  12400.  
  12401. void Player::OutPacketToSet(uint16 Opcode, uint16 Len, const void* Data, bool self)
  12402. {
  12403.     if(!IsInWorld())
  12404.         return;
  12405.  
  12406.     bool gm = m_isGmInvisible;
  12407.  
  12408.     if(self)
  12409.         OutPacket(Opcode, Len, Data);
  12410.  
  12411.     for(std::set< Object* >::iterator itr = m_inRangePlayers.begin(); itr != m_inRangePlayers.end(); ++itr)
  12412.     {
  12413.         Player* p = TO< Player* >(*itr);
  12414.  
  12415.         if(gm)
  12416.         {
  12417.             if(p->GetSession()->GetPermissionCount() > 0)
  12418.                 p->OutPacket(Opcode, Len, Data);
  12419.         }
  12420.         else
  12421.         {
  12422.             p->OutPacket(Opcode, Len, Data);
  12423.         }
  12424.     }
  12425. }
  12426.  
  12427. void Player::SendMessageToSet(WorldPacket* data, bool bToSelf, bool myteam_only)
  12428. {
  12429.     if(!IsInWorld())
  12430.         return;
  12431.  
  12432.     bool gminvis = false;
  12433.  
  12434.     if(bToSelf)
  12435.     {
  12436.         SendPacket(data);
  12437.     }
  12438.  
  12439.     gminvis = m_isGmInvisible;
  12440.     uint32 myphase = GetPhase();
  12441.  
  12442.     if(myteam_only)
  12443.     {
  12444.         uint32 myteam = GetTeam();
  12445.  
  12446.         if( data->GetOpcode() != SMSG_MESSAGECHAT)
  12447.         {
  12448.             for(std::set< Object* >::iterator itr = m_inRangePlayers.begin(); itr != m_inRangePlayers.end(); ++itr)
  12449.             {
  12450.                 Player* p = TO< Player* >(*itr);
  12451.  
  12452.                 if( gminvis && ( ( p->GetSession() == NULL ) || ( p->GetSession()->GetPermissionCount() <= 0 ) ) )
  12453.                     continue;
  12454.  
  12455.                 if( p->GetTeam() == myteam
  12456.                     && (p->GetPhase() & myphase) != 0
  12457.                     && p->IsVisible( GetGUID() ) )
  12458.                     p->SendPacket(data);
  12459.             }
  12460.         }
  12461.         else
  12462.         {
  12463.             for(std::set< Object* >::iterator itr = m_inRangePlayers.begin(); itr != m_inRangePlayers.end(); ++itr)
  12464.             {
  12465.                 Player* p = TO< Player* >(*itr);
  12466.  
  12467.                 if(p->GetSession()
  12468.                     && p->GetTeam() == myteam
  12469.                     && !p->Social_IsIgnoring(GetLowGUID())
  12470.                     && (p->GetPhase() & myphase) != 0 )
  12471.                     p->SendPacket(data);
  12472.             }
  12473.         }
  12474.     }
  12475.     else
  12476.     {
  12477.         if( data->GetOpcode() != SMSG_MESSAGECHAT)
  12478.         {
  12479.             for(std::set< Object* >::iterator itr = m_inRangePlayers.begin(); itr != m_inRangePlayers.end(); ++itr)
  12480.             {
  12481.                 Player* p = TO< Player* >(*itr);
  12482.  
  12483.                 if( gminvis && ( ( p->GetSession() == NULL ) || ( p->GetSession()->GetPermissionCount() <= 0 ) ) )
  12484.                     continue;
  12485.  
  12486.                 if( (p->GetPhase() & myphase) != 0
  12487.                     && p->IsVisible( GetGUID() ) )
  12488.                     p->SendPacket(data);
  12489.             }
  12490.         }
  12491.         else
  12492.         {
  12493.             for(std::set< Object* >::iterator itr = m_inRangePlayers.begin(); itr != m_inRangePlayers.end(); ++itr)
  12494.             {
  12495.                 Player* p = TO< Player* >(*itr);
  12496.  
  12497.                 if(p->GetSession()
  12498.                     && !p->Social_IsIgnoring(GetLowGUID())
  12499.                     && (p->GetPhase() & myphase) != 0 )
  12500.                     p->SendPacket(data);
  12501.             }
  12502.         }
  12503.     }
  12504. }
  12505.  
  12506. uint32 Player::CheckDamageLimits(uint32 dmg, uint32 spellid)
  12507. {
  12508.     if((spellid != 0) && (sWorld.m_limits.spellDamageCap > 0))
  12509.     {
  12510.         if(dmg > sWorld.m_limits.spellDamageCap)
  12511.         {
  12512.             std::stringstream dmglog;
  12513.             dmglog << "Dealt " << dmg << " with spell " << spellid;
  12514.  
  12515.             sCheatLog.writefromsession(m_session, dmglog.str().c_str());
  12516.  
  12517.             if(sWorld.m_limits.broadcast != 0)
  12518.                 sWorld.SendDamageLimitTextToGM(GetName(), dmglog.str().c_str());
  12519.  
  12520.             if(sWorld.m_limits.disconnect != 0)
  12521.                 m_session->Disconnect();
  12522.  
  12523.             dmg = sWorld.m_limits.spellDamageCap;
  12524.         }
  12525.     }
  12526.  
  12527.     else if((sWorld.m_limits.autoattackDamageCap > 0) && (dmg > sWorld.m_limits.autoattackDamageCap))
  12528.     {
  12529.         std::stringstream dmglog;
  12530.  
  12531.         dmglog << "Dealt " << dmg << " with auto attack";
  12532.         sCheatLog.writefromsession(m_session, dmglog.str().c_str());
  12533.  
  12534.         if(sWorld.m_limits.broadcast != 0)
  12535.             sWorld.SendDamageLimitTextToGM(GetName(), dmglog.str().c_str());
  12536.  
  12537.         if(sWorld.m_limits.disconnect != 0)
  12538.             m_session->Disconnect();
  12539.  
  12540.         dmg = sWorld.m_limits.autoattackDamageCap;
  12541.     }
  12542.  
  12543.     return dmg;
  12544. }
  12545.  
  12546. void Player::DealDamage(Unit* pVictim, uint32 damage, uint32 targetEvent, uint32 unitEvent, uint32 spellId, bool no_remove_auras)
  12547. {
  12548.     if(!pVictim || !pVictim->isAlive() || !pVictim->IsInWorld() || !IsInWorld())
  12549.         return;
  12550.     if(pVictim->IsPlayer() && TO< Player* >(pVictim)->GodModeCheat == true)
  12551.         return;
  12552.     if(pVictim->bInvincible)
  12553.         return;
  12554.     if(pVictim->IsSpiritHealer())
  12555.         return;
  12556.  
  12557.     if(this != pVictim)
  12558.     {
  12559.         if(!GetSession()->HasPermissions() && sWorld.m_limits.enable != 0)
  12560.             damage = CheckDamageLimits(damage, spellId);
  12561.  
  12562.         CombatStatus.OnDamageDealt(pVictim);
  12563.  
  12564.         if(pVictim->IsPvPFlagged())
  12565.         {
  12566.             if(!IsPvPFlagged())
  12567.                 PvPToggle();
  12568.  
  12569.             AggroPvPGuards();
  12570.         }
  12571.     }
  12572.  
  12573.     pVictim->SetStandState(STANDSTATE_STAND);
  12574.  
  12575.     if(CombatStatus.IsInCombat())
  12576.         sHookInterface.OnEnterCombat(this, this);
  12577.  
  12578. ///////////////////////////////////////////////////// Hackatlon ///////////////////////////////////////////////////////////
  12579.  
  12580.     //the black sheep , no actually it is paladin : Ardent Defender
  12581.     if(DamageTakenPctModOnHP35 && HasFlag(UNIT_FIELD_AURASTATE , AURASTATE_FLAG_HEALTH35))
  12582.         damage = damage - float2int32(damage * DamageTakenPctModOnHP35) / 100;
  12583.  
  12584.  
  12585.     //Mage: Fiery Payback
  12586.     /*if( FieryPaybackModHP35 == 1 ){
  12587.  
  12588.         if( GetHealthPct() <= 35){
  12589.             if( HasAura( 44441 ) )
  12590.                 CastSpell( GetGUID(), 44441, true );
  12591.         }else
  12592.             RemoveAllAuraById( 44441 );
  12593.     }*/
  12594.  
  12595. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  12596.  
  12597.     if(pVictim->IsCreature() && pVictim->IsTaggable())
  12598.     {
  12599.         pVictim->Tag(GetGUID());
  12600.         TagUnit(pVictim);
  12601.     }
  12602.  
  12603.     // Bg dmg counter
  12604.     if(pVictim != this)
  12605.     {
  12606.         if(m_bg != NULL && GetMapMgr() == pVictim->GetMapMgr())
  12607.         {
  12608.             m_bgScore.DamageDone += damage;
  12609.             m_bg->UpdatePvPData();
  12610.         }
  12611.     }
  12612.  
  12613.  
  12614.     // Duel
  12615.     if(pVictim->IsPlayer() && DuelingWith != NULL && DuelingWith->GetGUID() == pVictim->GetGUID())
  12616.     {
  12617.         if(pVictim->GetHealth() <= damage)
  12618.         {
  12619.             uint32 NewHP = pVictim->GetMaxHealth() / 100;
  12620.  
  12621.             if(NewHP < 5)
  12622.                 NewHP = 5;
  12623.  
  12624.             pVictim->SetHealth(NewHP);
  12625.             EndDuel(DUEL_WINNER_KNOCKOUT);
  12626.             pVictim->Emote(EMOTE_ONESHOT_BEG);
  12627.             return;
  12628.         }
  12629.     }
  12630.  
  12631.     if(pVictim->GetHealth() <= damage)
  12632.     {
  12633.  
  12634.         if(pVictim->isTrainingDummy())
  12635.         {
  12636.             pVictim->SetHealth(1);
  12637.             return;
  12638.         }
  12639.  
  12640.         if(m_bg != NULL)
  12641.         {
  12642.             m_bg->HookOnUnitKill(this, pVictim);
  12643.  
  12644.             if(pVictim->IsPlayer())
  12645.                 m_bg->HookOnPlayerKill(this, TO< Player* >(pVictim));
  12646.         }
  12647.  
  12648.         if(pVictim->IsPlayer())
  12649.         {
  12650.  
  12651.             Player* playerVictim = TO_PLAYER(pVictim);
  12652.             sHookInterface.OnKillPlayer(this, playerVictim);
  12653.  
  12654.             bool setAurastateFlag = false;
  12655.  
  12656.             if(getLevel() >= (pVictim->getLevel() - 8) && (GetGUID() != pVictim->GetGUID()))
  12657.             {
  12658.  
  12659. #ifdef ENABLE_ACHIEVEMENTS
  12660.                 GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA, GetAreaID(), 1, 0);
  12661.                 GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL, 1, 0, 0);
  12662. #endif
  12663.                 HonorHandler::OnPlayerKilled(this, playerVictim);
  12664.                 setAurastateFlag = true;
  12665.  
  12666.             }
  12667.  
  12668.             if(setAurastateFlag)
  12669.             {
  12670.                 SetFlag(UNIT_FIELD_AURASTATE, AURASTATE_FLAG_LASTKILLWITHHONOR);
  12671.  
  12672.                 if(!sEventMgr.HasEvent(this, EVENT_LASTKILLWITHHONOR_FLAG_EXPIRE))
  12673.                     sEventMgr.AddEvent(TO_UNIT(this), &Unit::EventAurastateExpire, static_cast< uint32 >(AURASTATE_FLAG_LASTKILLWITHHONOR), EVENT_LASTKILLWITHHONOR_FLAG_EXPIRE, 20000, 1, 0);
  12674.                 else
  12675.                     sEventMgr.ModifyEventTimeLeft(this, EVENT_LASTKILLWITHHONOR_FLAG_EXPIRE, 20000);
  12676.  
  12677.             }
  12678.         }
  12679.         else
  12680.         {
  12681.             if(pVictim->IsCreature())
  12682.             {
  12683.                 Reputation_OnKilledUnit(pVictim, false);
  12684.  
  12685. #ifdef ENABLE_ACHIEVEMENTS
  12686.                 GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLING_BLOW, GetMapId(), 0, 0);
  12687. #endif
  12688.  
  12689.                 if( pVictim->getLevel() >= (getLevel()-8) && ( GetGUID() != pVictim->GetGUID() ) )
  12690.                 {
  12691.                     HandleProc(PROC_ON_GAIN_EXPIERIENCE, this, NULL);
  12692.                     m_procCounter = 0;
  12693.                 }
  12694.             }
  12695.         }
  12696.  
  12697.         EventAttackStop();
  12698.  
  12699.         SendPartyKillLog(pVictim->GetGUID());
  12700.  
  12701.         if(pVictim->IsPvPFlagged())
  12702.         {
  12703.             uint32 team = GetTeam();
  12704.  
  12705.             if(team == TEAM_ALLIANCE)
  12706.                 team = TEAM_HORDE;
  12707.             else
  12708.                 team = TEAM_ALLIANCE;
  12709.  
  12710.             uint32 AreaID = pVictim->GetMapMgr()->GetAreaID(pVictim->GetPositionX(), pVictim->GetPositionY());
  12711.  
  12712.             if(AreaID == 0)
  12713.                 AreaID = GetZoneId(); // Failsafe for a shitty TerrainMgr
  12714.  
  12715.             if(AreaID)
  12716.             {
  12717.                 sWorld.SendZoneUnderAttackMsg(AreaID, static_cast< uint8 >(team));
  12718.             }
  12719.         }
  12720.  
  12721.         pVictim->Die(this, damage, spellId);
  12722.  
  12723. ///////////////////////////////////////////////////////////// Loot  //////////////////////////////////////////////////////////////////////////////////////////////
  12724.  
  12725.         if(pVictim->isLootable())
  12726.         {
  12727.             Player* tagger = GetMapMgr()->GetPlayer(Arcemu::Util::GUID_LOPART(pVictim->GetTaggerGUID()));
  12728.  
  12729.             // Tagger might have left the map so we need to check
  12730.             if(tagger != NULL)
  12731.             {
  12732.                 if(tagger->InGroup())
  12733.                     tagger->GetGroup()->SendLootUpdates(pVictim);
  12734.                 else
  12735.                     tagger->SendLootUpdate(pVictim);
  12736.             }
  12737.         }
  12738.  
  12739. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  12740.  
  12741.  
  12742. /////////////////////////////////////////////////////////// Experience /////////////////////////////////////////////////////////////////////////////////////////////
  12743.  
  12744.         if(pVictim->GetCreatedByGUID() == 0 && !pVictim->IsPet() && pVictim->IsTagged())
  12745.         {
  12746.             Unit* uTagger = pVictim->GetMapMgr()->GetUnit(pVictim->GetTaggerGUID());
  12747.  
  12748.             if(uTagger != NULL && uTagger->IsPlayer())
  12749.             {
  12750.                 Player* pTagger = TO_PLAYER(uTagger);
  12751.  
  12752.                 if(pTagger != NULL)
  12753.                 {
  12754.  
  12755.                     if(pTagger->InGroup())
  12756.                         pTagger->GiveGroupXP(pVictim, pTagger);
  12757.                     else if(IsUnit())
  12758.                     {
  12759.                         uint32 xp = CalculateXpToGive(pVictim, uTagger);
  12760.  
  12761.                         if(xp > 0)
  12762.                         {
  12763.                             pTagger->GiveXP(xp, pVictim->GetGUID(), true);
  12764.  
  12765.                             SetFlag(UNIT_FIELD_AURASTATE, AURASTATE_FLAG_LASTKILLWITHHONOR);
  12766.  
  12767.                             if(!sEventMgr.HasEvent(this, EVENT_LASTKILLWITHHONOR_FLAG_EXPIRE))
  12768.                                 sEventMgr.AddEvent(TO_UNIT(this), &Unit::EventAurastateExpire, (uint32)AURASTATE_FLAG_LASTKILLWITHHONOR, EVENT_LASTKILLWITHHONOR_FLAG_EXPIRE, 20000, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
  12769.                             else
  12770.                                 sEventMgr.ModifyEventTimeLeft(this, EVENT_LASTKILLWITHHONOR_FLAG_EXPIRE, 20000);
  12771.  
  12772.                             // let's give the pet some experience too
  12773.                             if(pTagger->GetSummon() && pTagger->GetSummon()->CanGainXP())
  12774.                             {
  12775.                                 xp = CalculateXpToGive(pVictim, pTagger->GetSummon());
  12776.  
  12777.                                 if(xp > 0)
  12778.                                     pTagger->GetSummon()->GiveXP(xp);
  12779.                             }
  12780.                         }
  12781.                     }
  12782.  
  12783. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  12784.  
  12785.                     if(pVictim->IsCreature())
  12786.                     {
  12787.                         sQuestMgr.OnPlayerKill(pTagger, TO_CREATURE(pVictim), true);
  12788. ///////////////////////////////////////////////// Kill creature/creature type Achievements /////////////////////////////////////////////////////////////////////
  12789. #ifdef ENABLE_ACHIEVEMENTS
  12790.                         if(pTagger->InGroup())
  12791.                         {
  12792.                             Group* pGroup = pTagger->GetGroup();
  12793.  
  12794.                             pGroup->UpdateAchievementCriteriaForInrange(pVictim, ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, pVictim->GetEntry(), 1, 0);
  12795.                             pGroup->UpdateAchievementCriteriaForInrange(pVictim, ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE, GetHighGUID(), GetLowGUID(), 0);
  12796.  
  12797.                         }
  12798.                         else
  12799.                         {
  12800.                             pTagger->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, pVictim->GetEntry(), 1, 0);
  12801.                             pTagger->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE, GetHighGUID(), GetLowGUID(), 0);
  12802.                         }
  12803. #endif
  12804.                     }
  12805.                 }
  12806.             }
  12807.         }
  12808. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  12809.  
  12810. #ifdef ENABLE_ACHIEVEMENTS
  12811.  
  12812.         if(pVictim->isCritter())
  12813.         {
  12814.             GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, pVictim->GetEntry(), 1, 0);
  12815.             GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE, GetHighGUID(), GetLowGUID(), 0);
  12816.         }
  12817.  
  12818. #endif
  12819.  
  12820.     }
  12821.     else
  12822.     {
  12823.         pVictim->TakeDamage(this, damage, spellId, no_remove_auras);
  12824.     }
  12825. }
  12826.  
  12827.  
  12828. void Player::TakeDamage(Unit* pAttacker, uint32 damage, uint32 spellid, bool no_remove_auras)
  12829. {
  12830.  
  12831.     if(!no_remove_auras)
  12832.     {
  12833.         //zack 2007 04 24 : root should not remove self (and also other unknown spells)
  12834.         if(spellid)
  12835.         {
  12836.             RemoveAurasByInterruptFlagButSkip(AURA_INTERRUPT_ON_ANY_DAMAGE_TAKEN, spellid);
  12837.             if(Rand(35.0f))
  12838.                 RemoveAurasByInterruptFlagButSkip(AURA_INTERRUPT_ON_UNUSED2, spellid);
  12839.         }
  12840.         else
  12841.         {
  12842.             RemoveAurasByInterruptFlag(AURA_INTERRUPT_ON_ANY_DAMAGE_TAKEN);
  12843.             if(Rand(35.0f))
  12844.                 RemoveAurasByInterruptFlag(AURA_INTERRUPT_ON_UNUSED2);
  12845.         }
  12846.     }
  12847.  
  12848.     if(CombatStatus.IsInCombat())
  12849.         sHookInterface.OnEnterCombat(this, pAttacker);
  12850.  
  12851.  
  12852.     // Rage generation on damage
  12853.     if(GetPowerType() == POWER_TYPE_RAGE && pAttacker != this)
  12854.     {
  12855.         float val;
  12856.         float level = static_cast< float >(getLevel());
  12857.         float c = 0.0091107836f * level * level + 3.225598133f * level + 4.2652911f;
  12858.  
  12859.         val = 2.5f * damage / c;
  12860.         uint32 rage = GetPower(POWER_TYPE_RAGE);
  12861.  
  12862.         if(rage + float2int32(val) > 1000)
  12863.             val = 1000.0f - static_cast< float >(GetPower(POWER_TYPE_RAGE));
  12864.  
  12865.         val *= 10.0;
  12866.         ModPower(POWER_TYPE_RAGE, static_cast< int32 >(val));
  12867.     }
  12868.  
  12869.  
  12870.     // Cannibalize, when we are hit we need to stop munching that nice fresh corpse
  12871.     {
  12872.         if(cannibalize)
  12873.         {
  12874.             sEventMgr.RemoveEvents(this, EVENT_CANNIBALIZE);
  12875.             SetEmoteState(0);
  12876.             cannibalize = false;
  12877.         }
  12878.     }
  12879.  
  12880.     if(pAttacker != this)
  12881.     {
  12882.  
  12883.         // Defensive pet
  12884.         std::list<Pet*> summons = GetSummons();
  12885.  
  12886.         for(std::list<Pet*>::iterator itr = summons.begin(); itr != summons.end(); ++itr)
  12887.         {
  12888.             Pet* pPet = *itr;
  12889.  
  12890.             if(pPet->GetPetState() != PET_STATE_PASSIVE)
  12891.             {
  12892.                 pPet->GetAIInterface()->AttackReaction(pAttacker, 1, 0);
  12893.                 pPet->HandleAutoCastEvent(AUTOCAST_EVENT_OWNER_ATTACKED);
  12894.             }
  12895.         }
  12896.     }
  12897.  
  12898.     ModHealth(-1 * static_cast< int32 >(damage));
  12899. }
  12900.  
  12901. void Player::Die(Unit* pAttacker, uint32 damage, uint32 spellid)
  12902. {
  12903.     if( GetVehicleComponent() != NULL ){
  12904.         GetVehicleComponent()->RemoveAccessories();
  12905.         GetVehicleComponent()->EjectAllPassengers();
  12906.     }
  12907.  
  12908. #ifdef ENABLE_ACHIEVEMENTS
  12909.     // A Player has died
  12910.     if(IsPlayer())
  12911.     {
  12912.         GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH, 1, 0, 0);
  12913.         GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP, GetMapId(), 1, 0);
  12914.  
  12915.         // A Player killed a Player
  12916.         if(pAttacker->IsPlayer())
  12917.         {
  12918.             GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1, 0, 0);
  12919.         }// A Creature killed a Player
  12920.         else if(pAttacker->IsCreature())
  12921.         {
  12922.             GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, 1, 0, 0);
  12923.         }
  12924.     }
  12925. #endif
  12926.  
  12927.     //general hook for die
  12928.     if(!sHookInterface.OnPreUnitDie(pAttacker, this))
  12929.         return;
  12930.  
  12931.     // on die and an target die proc
  12932.     {
  12933.         SpellEntry* killerspell;
  12934.         if(spellid)
  12935.             killerspell = dbcSpell.LookupEntry(spellid);
  12936.         else killerspell = NULL;
  12937.  
  12938.         HandleProc(PROC_ON_DIE, this, killerspell);
  12939.         m_procCounter = 0;
  12940.         pAttacker->HandleProc(PROC_ON_TARGET_DIE, this, killerspell);
  12941.         pAttacker->m_procCounter = 0;
  12942.     }
  12943.  
  12944.     if(!pAttacker->IsPlayer())
  12945.         DeathDurabilityLoss(0.10);
  12946.  
  12947.  
  12948.     if(GetChannelSpellTargetGUID() != 0)
  12949.     {
  12950.  
  12951.         Spell* spl = GetCurrentSpell();
  12952.  
  12953.         if(spl != NULL)
  12954.         {
  12955.  
  12956.             for(int i = 0; i < 3; i++)
  12957.             {
  12958.                 if(spl->GetProto()->Effect[i] == SPELL_EFFECT_PERSISTENT_AREA_AURA)
  12959.                 {
  12960.                     uint64 guid = GetChannelSpellTargetGUID();
  12961.                     DynamicObject* dObj = GetMapMgr()->GetDynamicObject(Arcemu::Util::GUID_LOPART(guid));
  12962.                     if(!dObj)
  12963.                         continue;
  12964.  
  12965.                     dObj->Remove();
  12966.                 }
  12967.             }
  12968.  
  12969.             if(spl->GetProto()->ChannelInterruptFlags == 48140) spl->cancel();
  12970.         }
  12971.     }
  12972.  
  12973.     /* Stop players from casting */
  12974.     for(std::set< Object* >::iterator itr = GetInRangePlayerSetBegin() ; itr != GetInRangePlayerSetEnd() ; itr ++)
  12975.     {
  12976.         Unit* attacker = TO< Unit* >(*itr);
  12977.  
  12978.         if(attacker->GetCurrentSpell() != NULL)
  12979.         {
  12980.             if(attacker->GetCurrentSpell()->m_targets.m_unitTarget == GetGUID())
  12981.                 attacker->GetCurrentSpell()->cancel();
  12982.         }
  12983.     }
  12984.  
  12985.     smsg_AttackStop(pAttacker);
  12986.     EventAttackStop();
  12987.  
  12988.     CALL_INSTANCE_SCRIPT_EVENT(m_mapMgr, OnPlayerDeath)(this, pAttacker);
  12989.  
  12990.     {
  12991.         uint32 self_res_spell = 0;
  12992.         if(m_bg == NULL || (m_bg != NULL && !IS_ARENA(m_bg->GetType())))
  12993.         {
  12994.             self_res_spell = SoulStone;
  12995.  
  12996.             SoulStone = SoulStoneReceiver = 0;
  12997.  
  12998.             if(self_res_spell == 0 && bReincarnation)
  12999.             {
  13000.                 SpellEntry* m_reincarnSpellInfo = dbcSpell.LookupEntry(20608);
  13001.                 if(Cooldown_CanCast(m_reincarnSpellInfo))
  13002.                 {
  13003.  
  13004.                     uint32 ankh_count = GetItemInterface()->GetItemCount(17030);
  13005.                     if(ankh_count)
  13006.                         self_res_spell = 21169;
  13007.                 }
  13008.             }
  13009.         }
  13010.  
  13011.         SetUInt32Value(PLAYER_SELF_RES_SPELL, self_res_spell);
  13012.         SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID , 0);
  13013.     }
  13014.  
  13015.     // Wipe our attacker set on death
  13016.     CombatStatus.Vanished();
  13017.  
  13018.     CALL_SCRIPT_EVENT(pAttacker, OnTargetDied)(this);
  13019.     pAttacker->smsg_AttackStop(this);
  13020.  
  13021.     /* Tell Unit that it's target has Died */
  13022.     pAttacker->addStateFlag(UF_TARGET_DIED);
  13023.  
  13024.  
  13025.     m_UnderwaterTime = 0;
  13026.     m_UnderwaterState = 0;
  13027.  
  13028.     summonhandler.RemoveAllSummons();
  13029.     DismissActivePets();
  13030.  
  13031.     SetHealth(0);
  13032.  
  13033.     //check for spirit of Redemption
  13034.     if(HasSpell(20711))
  13035.     {
  13036.         SpellEntry* sorInfo = dbcSpell.LookupEntryForced(27827);
  13037.  
  13038.         if(sorInfo != NULL)
  13039.         {
  13040.             Spell* sor = sSpellFactoryMgr.NewSpell(this, sorInfo, true, NULL);
  13041.             SpellCastTargets targets;
  13042.             targets.m_unitTarget = GetGUID();
  13043.             sor->prepare(&targets);
  13044.         }
  13045.     }
  13046.  
  13047.  
  13048.     KillPlayer();
  13049.     if( m_mapMgr->m_battleground != NULL )
  13050.         m_mapMgr->m_battleground->HookOnUnitDied( this );
  13051. }
  13052.  
  13053.  
  13054. void Player::HandleKnockback(Object* caster, float horizontal, float vertical)
  13055. {
  13056.     if(caster == NULL)
  13057.         caster = this;
  13058.     float angle = calcRadAngle(caster->GetPositionX(), caster->GetPositionY(), GetPositionX(), GetPositionY());
  13059.     if(caster == this)
  13060.         angle = GetOrientation() + M_PI;
  13061.     float sin = sinf(angle);
  13062.     float cos = cosf(angle);
  13063.  
  13064.     WorldPacket data(SMSG_MOVE_KNOCK_BACK, 50);
  13065.  
  13066.     data << GetNewGUID();
  13067.     data << uint32(getMSTime());
  13068.     data << float(cos);
  13069.     data << float(sin);
  13070.     data << float(horizontal);
  13071.     data << float(-vertical);
  13072.  
  13073.     GetSession()->SendPacket(&data);
  13074.  
  13075.     blinked = true;
  13076.     SpeedCheatDelay(10000);
  13077. }
  13078.  
  13079. void Player::RemoveIfVisible(uint64 obj)
  13080. {
  13081.     std::set< uint64 >::iterator itr = m_visibleObjects.find(obj);
  13082.     if(itr == m_visibleObjects.end())
  13083.         return;
  13084.  
  13085.     m_visibleObjects.erase(obj);
  13086.     PushOutOfRange(obj);
  13087. }
  13088.  
  13089. void Player::Phase(uint8 command, uint32 newphase)
  13090. {
  13091.     Unit::Phase(command, newphase);
  13092.  
  13093.     std::list<Pet*> summons = GetSummons();
  13094.     for(std::list<Pet*>::iterator itr = summons.begin(); itr != summons.end(); ++itr)
  13095.     {
  13096.         Pet* p = *itr;
  13097.         p->Phase(command, newphase);
  13098.     }
  13099.     //We should phase other, non-combat "pets" too...
  13100.  
  13101.     if(m_CurrentCharm != 0)
  13102.     {
  13103.         Unit* charm = m_mapMgr->GetUnit(m_CurrentCharm);
  13104.         if(charm == NULL)
  13105.             return;
  13106.  
  13107.         charm->Phase(command, newphase);
  13108.     }
  13109. }
  13110.  
  13111. // TODO: Use this method all over source code
  13112. uint32 Player::GetBlockDamageReduction()
  13113. {
  13114.     Item* it = this->GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_OFFHAND);
  13115.     if(it == NULL || it->GetProto()->InventoryType != INVTYPE_SHIELD)
  13116.         return 0;
  13117.  
  13118.     float block_multiplier = (100.0f + this->m_modblockabsorbvalue) / 100.0f;
  13119.     if(block_multiplier < 1.0f)
  13120.         block_multiplier = 1.0f;
  13121.  
  13122.     return float2int32((it->GetProto()->Block + this->m_modblockvaluefromspells + this->GetUInt32Value(PLAYER_RATING_MODIFIER_BLOCK) + this->GetStat(STAT_STRENGTH) / 2.0f - 1.0f) * block_multiplier);
  13123. }
  13124.  
  13125. void Player::ApplyFeralAttackPower(bool apply, Item* item)
  13126. {
  13127.     float FeralAP = 0.0f;
  13128.  
  13129.     Item* it = item;
  13130.     if(it == NULL)
  13131.         it = GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_MAINHAND);
  13132.  
  13133.     if(it != NULL)
  13134.     {
  13135.         float delay = (float)it->GetProto()->Delay / 1000.0f;
  13136.         delay = max(1.0f, delay);
  13137.         float dps = ((it->GetProto()->Damage[0].Min + it->GetProto()->Damage[0].Max) / 2) / delay;
  13138.         if(dps > 54.8f)
  13139.             FeralAP = (dps - 54.8f) * 14;
  13140.     }
  13141.     ModifyBonuses(FERAL_ATTACK_POWER, (int) FeralAP, apply);
  13142. }
  13143.  
  13144. void Player::SendChatMessage(uint8 type, uint32 lang, const char* msg, uint32 delay)
  13145. {
  13146.     if(delay)
  13147.     {
  13148.         sEventMgr.AddEvent(this, &Player::SendChatMessage, type, lang, msg, uint32(0), EVENT_UNIT_CHAT_MSG, delay, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
  13149.         return;
  13150.     }
  13151.  
  13152.     WorldPacket* data = sChatHandler.FillMessageData(type, lang, msg, GetGUID());
  13153.     SendMessageToSet(data, true);
  13154.     delete data;
  13155. }
  13156.  
  13157. void Player::SendChatMessageToPlayer(uint8 type, uint32 lang, const char* msg, Player* plr)
  13158. {
  13159.     if(plr == NULL)
  13160.         return;
  13161.     WorldPacket* data = sChatHandler.FillMessageData(type, lang, msg, GetGUID());
  13162.     plr->SendPacket(data);
  13163.     delete data;
  13164. }
  13165.  
  13166. void Player::AcceptQuest(uint64 guid, uint32 quest_id)
  13167. {
  13168.  
  13169.     bool bValid = false;
  13170.     bool hasquest = true;
  13171.     bool bSkipLevelCheck = false;
  13172.     Quest* qst = NULL;
  13173.     Object* qst_giver = NULL;
  13174.     uint32 guidtype = GET_TYPE_FROM_GUID(guid);
  13175.  
  13176.     if(guidtype == HIGHGUID_TYPE_UNIT)
  13177.     {
  13178.         Creature* quest_giver = m_mapMgr->GetCreature(GET_LOWGUID_PART(guid));
  13179.         if(quest_giver)
  13180.             qst_giver = quest_giver;
  13181.         else
  13182.             return;
  13183.         hasquest = quest_giver->HasQuest(quest_id, 1);
  13184.         if(quest_giver->isQuestGiver())
  13185.         {
  13186.             bValid = true;
  13187.             qst = QuestStorage.LookupEntry(quest_id);
  13188.         }
  13189.     }
  13190.     else if(guidtype == HIGHGUID_TYPE_GAMEOBJECT)
  13191.     {
  13192.         GameObject* quest_giver = m_mapMgr->GetGameObject(GET_LOWGUID_PART(guid));
  13193.         if(quest_giver)
  13194.             qst_giver = quest_giver;
  13195.         else
  13196.             return;
  13197.  
  13198.         bValid = true;
  13199.         qst = QuestStorage.LookupEntry(quest_id);
  13200.     }
  13201.     else if(guidtype == HIGHGUID_TYPE_ITEM)
  13202.     {
  13203.         Item* quest_giver = m_ItemInterface->GetItemByGUID(guid);
  13204.         if(quest_giver)
  13205.             qst_giver = quest_giver;
  13206.         else
  13207.             return;
  13208.         bValid = true;
  13209.         bSkipLevelCheck = true;
  13210.         qst = QuestStorage.LookupEntry(quest_id);
  13211.     }
  13212.     else if(guidtype == HIGHGUID_TYPE_PLAYER)
  13213.     {
  13214.         Player* quest_giver = m_mapMgr->GetPlayer((uint32)guid);
  13215.         if(quest_giver)
  13216.             qst_giver = quest_giver;
  13217.         else
  13218.             return;
  13219.         bValid = true;
  13220.         qst = QuestStorage.LookupEntry(quest_id);
  13221.     }
  13222.  
  13223.     if(!qst_giver)
  13224.     {
  13225.         LOG_DEBUG("WORLD: Invalid questgiver GUID.");
  13226.         return;
  13227.     }
  13228.  
  13229.     if(!bValid || qst == NULL)
  13230.     {
  13231.         LOG_DEBUG("WORLD: Creature is not a questgiver.");
  13232.         return;
  13233.     }
  13234.  
  13235.     if(GetQuestLogForEntry(qst->id))
  13236.         return;
  13237.  
  13238.     if(qst_giver->IsCreature() && TO< Creature* >(qst_giver)->m_escorter != NULL)
  13239.     {
  13240.         m_session->SystemMessage("You cannot accept this quest at this time.");
  13241.         return;
  13242.     }
  13243.  
  13244.     // Check the player hasn't already taken this quest, or
  13245.     // it isn't available.
  13246.     uint32 status = sQuestMgr.CalcQuestStatus(qst_giver, this, qst, 3, bSkipLevelCheck);
  13247.  
  13248.     if((!sQuestMgr.IsQuestRepeatable(qst) && HasFinishedQuest(qst->id)) || (status != QMGR_QUEST_AVAILABLE && status != QMGR_QUEST_REPEATABLE && status != QMGR_QUEST_CHAT)
  13249.             || !hasquest)
  13250.     {
  13251.         // We've got a hacker. Disconnect them.
  13252.         //sCheatLog.writefromsession(this, "tried to accept incompatible quest %u from %u.", qst->id, qst_giver->GetEntry());
  13253.         //Disconnect();
  13254.         return;
  13255.     }
  13256.  
  13257.     int32 log_slot = GetOpenQuestSlot();
  13258.  
  13259.     if(log_slot == -1)
  13260.     {
  13261.         sQuestMgr.SendQuestLogFull(this);
  13262.         return;
  13263.     }
  13264.  
  13265.     if( ( qst->time != 0 ) && HasTimedQuest() ){
  13266.         sQuestMgr.SendQuestInvalid( INVALID_REASON_HAVE_TIMED_QUEST, this );
  13267.         return;
  13268.     }
  13269.  
  13270.     if(qst->count_receiveitems || qst->srcitem)
  13271.     {
  13272.         uint32 slots_required = qst->count_receiveitems;
  13273.  
  13274.         if(m_ItemInterface->CalculateFreeSlots(NULL) < slots_required)
  13275.         {
  13276.             m_ItemInterface->BuildInventoryChangeError(NULL, NULL, INV_ERR_BAG_FULL);
  13277.             sQuestMgr.SendQuestFailed(FAILED_REASON_INV_FULL, qst, this);
  13278.             return;
  13279.         }
  13280.     }
  13281.  
  13282.     QuestLogEntry* qle = new QuestLogEntry();
  13283.     qle->Init(qst, this, log_slot);
  13284.     qle->UpdatePlayerFields();
  13285.  
  13286.     // If the quest should give any items on begin, give them the items.
  13287.     for(uint32 i = 0; i < 4; ++i)
  13288.     {
  13289.         if(qst->receive_items[i])
  13290.         {
  13291.             Item* item = objmgr.CreateItem(qst->receive_items[i], this);
  13292.             if(item == NULL)
  13293.                 continue;
  13294.             if(!m_ItemInterface->AddItemToFreeSlot(item))
  13295.             {
  13296.                 item->DeleteMe();
  13297.             }
  13298.             else
  13299.                 SendItemPushResult(false, true, false, true,
  13300.                                    m_ItemInterface->LastSearchItemBagSlot(), m_ItemInterface->LastSearchItemSlot(),
  13301.                                    1, item->GetEntry(), item->GetItemRandomSuffixFactor(), item->GetItemRandomPropertyId(), item->GetStackCount());
  13302.         }
  13303.     }
  13304.  
  13305.     if(qst->srcitem && qst->srcitem != qst->receive_items[0])
  13306.     {
  13307.         if( !qst_giver->IsItem() || ( qst_giver->GetEntry() != qst->srcitem ) )
  13308.         {
  13309.             Item *item = objmgr.CreateItem(qst->srcitem, this);
  13310.             if( item != NULL )
  13311.             {
  13312.                 item->SetStackCount(qst->srcitemcount ? qst->srcitemcount : 1);
  13313.                 if(!m_ItemInterface->AddItemToFreeSlot(item))
  13314.                     item->DeleteMe();
  13315.             }
  13316.         }
  13317.     }
  13318.  
  13319.     if(qst->count_required_item || qst_giver->IsGameObject())   // gameobject quests deactivate
  13320.         UpdateNearbyGameObjects();
  13321.  
  13322.     //ScriptSystem->OnQuestEvent(qst, TO< Creature* >( qst_giver ), _player, QUEST_EVENT_ON_ACCEPT);
  13323.  
  13324.     sQuestMgr.OnQuestAccepted(this, qst, qst_giver);
  13325.  
  13326.     LOG_DEBUG("WORLD: Added new QLE.");
  13327.     sHookInterface.OnQuestAccept(this, qst, qst_giver);
  13328. }
  13329.  
  13330. bool Player::LoadReputations( QueryResult *result ){
  13331.     if( result == NULL )
  13332.         return false;
  13333.  
  13334.     FactionDBC *faction = NULL;
  13335.     FactionReputation *reputation = NULL;
  13336.  
  13337.     uint32 id = 0;
  13338.     uint32 flag = 0;
  13339.     int32 basestanding = 0;
  13340.     int32 standing = 0;
  13341.  
  13342.     Field *field = NULL;
  13343.  
  13344.     do{
  13345.         Field *field = result->Fetch();
  13346.  
  13347.         id = field[ 0 ].GetUInt32();
  13348.         flag = field[ 1 ].GetUInt32();
  13349.         basestanding = field[ 2 ].GetInt32();
  13350.         standing = field[ 3 ].GetInt32();
  13351.        
  13352.         faction = dbcFaction.LookupEntryForced( id );
  13353.         if( ( faction == NULL ) || ( faction->RepListId < 0 ) )
  13354.             continue;
  13355.  
  13356.         ReputationMap::iterator itr = m_reputation.find( id );
  13357.         if( itr != m_reputation.end() )
  13358.             delete itr->second;
  13359.  
  13360.         reputation = new FactionReputation;
  13361.         reputation->baseStanding = basestanding;
  13362.         reputation->standing = standing;
  13363.         reputation->flag = static_cast< uint8 >( flag );
  13364.         m_reputation[ id ] = reputation;
  13365.         reputationByListId[ faction->RepListId ] = reputation;
  13366.  
  13367.     }while( result->NextRow() );
  13368.    
  13369.     if( m_reputation.size() == 0 )
  13370.         _InitialReputation();
  13371.  
  13372.     return true;
  13373. }
  13374.  
  13375. bool Player::SaveReputations( bool NewCharacter, QueryBuffer *buf ){
  13376.     if( !NewCharacter && ( buf == NULL ) )
  13377.         return false;
  13378.  
  13379.     std::stringstream ds;
  13380.     uint32 guid = GetLowGUID();
  13381.  
  13382.     ds << "DELETE FROM playerreputations WHERE guid = '";
  13383.     ds << guid;
  13384.     ds << "';";
  13385.  
  13386.     if( !NewCharacter )
  13387.         buf->AddQueryStr( ds.str() );
  13388.     else
  13389.         CharacterDatabase.ExecuteNA( ds.str().c_str() );
  13390.  
  13391.  
  13392.     for( ReputationMap::iterator itr = m_reputation.begin(); itr != m_reputation.end(); ++itr ){
  13393.         std::stringstream ss;
  13394.  
  13395.         ss << "INSERT INTO playerreputations VALUES('";
  13396.         ss << GetLowGUID() << "','";
  13397.         ss << itr->first << "','";
  13398.         ss << uint32( itr->second->flag ) << "','";
  13399.         ss << itr->second->baseStanding << "','";
  13400.         ss << itr->second->standing << "');";
  13401.        
  13402.         if( !NewCharacter )
  13403.             buf->AddQueryStr( ss.str() );
  13404.         else
  13405.             CharacterDatabase.ExecuteNA( ss.str().c_str() );
  13406.     }
  13407.  
  13408.     return true;
  13409. }
  13410.  
  13411. bool Player::LoadSpells(QueryResult* result)
  13412. {
  13413.     if(result == NULL)
  13414.         return false;
  13415.  
  13416.     Field* fields = NULL;
  13417.  
  13418.     do
  13419.     {
  13420.         fields = result->Fetch();
  13421.  
  13422.         uint32 spellid = fields[ 0 ].GetUInt32();
  13423.  
  13424.         SpellEntry* sp = dbcSpell.LookupEntryForced(spellid);
  13425.         if(sp != NULL)
  13426.             mSpells.insert(spellid);
  13427.  
  13428.     }
  13429.     while(result->NextRow());
  13430.  
  13431.     return true;
  13432. }
  13433.  
  13434. bool Player::SaveSpells(bool NewCharacter, QueryBuffer* buf)
  13435. {
  13436.     if(!NewCharacter && buf == NULL)
  13437.         return false;
  13438.  
  13439.     std::stringstream ds;
  13440.     uint32 guid = GetLowGUID();
  13441.  
  13442.     ds << "DELETE FROM playerspells WHERE GUID = '";
  13443.     ds << guid;
  13444.     ds << "';";
  13445.  
  13446.     if(!NewCharacter)
  13447.         buf->AddQueryStr(ds.str());
  13448.     else
  13449.         CharacterDatabase.ExecuteNA(ds.str().c_str());
  13450.  
  13451.     for(SpellSet::iterator itr = mSpells.begin(); itr != mSpells.end(); ++itr)
  13452.     {
  13453.         uint32 spellid = *itr;
  13454.  
  13455.         std::stringstream ss;
  13456.  
  13457.         ss << "INSERT INTO playerspells VALUES('";
  13458.         ss << guid << "','";
  13459.         ss << spellid << "');";
  13460.  
  13461.         if(!NewCharacter)
  13462.             buf->AddQueryStr(ss.str());
  13463.         else
  13464.             CharacterDatabase.ExecuteNA(ss.str().c_str());
  13465.     }
  13466.  
  13467.     return true;
  13468. }
  13469.  
  13470. bool Player::LoadDeletedSpells(QueryResult* result)
  13471. {
  13472.     if(result == NULL)
  13473.         return false;
  13474.  
  13475.     Field* fields = NULL;
  13476.  
  13477.     do
  13478.     {
  13479.         fields = result->Fetch();
  13480.  
  13481.         uint32 spellid = fields[ 0 ].GetUInt32();
  13482.  
  13483.         SpellEntry* sp = dbcSpell.LookupEntryForced(spellid);
  13484.         if(sp != NULL)
  13485.             mDeletedSpells.insert(spellid);
  13486.  
  13487.     }
  13488.     while(result->NextRow());
  13489.  
  13490.     return true;
  13491. }
  13492.  
  13493. bool Player::SaveDeletedSpells(bool NewCharacter, QueryBuffer* buf)
  13494. {
  13495.     if(!NewCharacter && buf == NULL)
  13496.         return false;
  13497.  
  13498.     std::stringstream ds;
  13499.     uint32 guid = GetLowGUID();
  13500.  
  13501.     ds << "DELETE FROM playerdeletedspells WHERE GUID = '";
  13502.     ds << guid;
  13503.     ds << "';";
  13504.  
  13505.     if(!NewCharacter)
  13506.         buf->AddQueryStr(ds.str());
  13507.     else
  13508.         CharacterDatabase.ExecuteNA(ds.str().c_str());
  13509.  
  13510.     for(SpellSet::iterator itr = mDeletedSpells.begin(); itr != mDeletedSpells.end(); ++itr)
  13511.     {
  13512.         uint32 spellid = *itr;
  13513.  
  13514.         std::stringstream ss;
  13515.  
  13516.         ss << "INSERT INTO playerdeletedspells VALUES('";
  13517.         ss << guid << "','";
  13518.         ss << spellid << "');";
  13519.  
  13520.         if(!NewCharacter)
  13521.             buf->AddQueryStr(ss.str());
  13522.         else
  13523.             CharacterDatabase.ExecuteNA(ss.str().c_str());
  13524.     }
  13525.  
  13526.     return true;
  13527. }
  13528.  
  13529. bool Player::LoadSkills(QueryResult* result)
  13530. {
  13531.     if(result == NULL)
  13532.         return false;
  13533.  
  13534.     Field* fields = NULL;
  13535.  
  13536.     do
  13537.     {
  13538.         fields = result->Fetch();
  13539.  
  13540.         uint32 skillid = fields[ 0 ].GetUInt32();
  13541.         uint32 currval = fields[ 1 ].GetUInt32();
  13542.         uint32 maxval  = fields[ 2 ].GetUInt32();
  13543.  
  13544.         PlayerSkill sk;
  13545.  
  13546.         sk.Reset(skillid);
  13547.         sk.CurrentValue = currval;
  13548.         sk.MaximumValue = maxval;
  13549.  
  13550.         if(sk.CurrentValue == 0)
  13551.             sk.CurrentValue = 1;
  13552.  
  13553.         m_skills.insert(std::pair< uint32, PlayerSkill >(skillid, sk));
  13554.  
  13555.     }
  13556.     while(result->NextRow());
  13557.  
  13558.     return true;
  13559. }
  13560.  
  13561. bool Player::SaveSkills(bool NewCharacter, QueryBuffer* buf)
  13562. {
  13563.     if(!NewCharacter && buf == NULL)
  13564.         return false;
  13565.  
  13566.     std::stringstream ds;
  13567.     uint32 guid = GetLowGUID();
  13568.  
  13569.     ds << "DELETE FROM playerskills WHERE GUID = '";
  13570.     ds << guid;
  13571.     ds << "';";
  13572.  
  13573.     if(!NewCharacter)
  13574.         buf->AddQueryStr(ds.str());
  13575.     else
  13576.         CharacterDatabase.ExecuteNA(ds.str().c_str());
  13577.  
  13578.     for(SkillMap::iterator itr = m_skills.begin(); itr != m_skills.end(); ++itr)
  13579.     {
  13580.  
  13581.         if(itr->second.Skill->type == SKILL_TYPE_LANGUAGE)
  13582.             continue;
  13583.  
  13584.         uint32 skillid = itr->first;
  13585.         uint32 currval = itr->second.CurrentValue;
  13586.         uint32 maxval  = itr->second.MaximumValue;
  13587.  
  13588.         std::stringstream ss;
  13589.  
  13590.         ss << "INSERT INTO playerskills VALUES('";
  13591.         ss << guid << "','";
  13592.         ss << skillid << "','";
  13593.         ss << currval << "','";
  13594.         ss << maxval << "');";
  13595.  
  13596.         if(!NewCharacter)
  13597.             buf->AddQueryStr(ss.str());
  13598.         else
  13599.             CharacterDatabase.ExecuteNA(ss.str().c_str());
  13600.     }
  13601.  
  13602.     return true;
  13603. }
  13604.  
  13605. void Player::AddQuestKill(uint32 questid, uint8 reqid, uint32 delay)
  13606. {
  13607.     if(!HasQuest(questid))
  13608.         return;
  13609.  
  13610.     if(delay)
  13611.     {
  13612.         sEventMgr.AddEvent(this, &Player::AddQuestKill, questid, reqid, uint32(0), EVENT_PLAYER_UPDATE, delay, 1, EVENT_FLAG_DO_NOT_EXECUTE_IN_WORLD_CONTEXT);
  13613.         return;
  13614.     }
  13615.  
  13616.     QuestLogEntry* qle = GetQuestLogForEntry(questid);
  13617.     Quest* qst = qle->GetQuest();
  13618.  
  13619.     if(qle->GetMobCount(reqid) >= qst->required_mobcount[reqid])
  13620.         return;
  13621.  
  13622.     qle->IncrementMobCount(reqid);
  13623.     qle->SendUpdateAddKill(reqid);
  13624.     qle->UpdatePlayerFields();
  13625.  
  13626.     if(qle->CanBeFinished())
  13627.         qle->SendQuestComplete();
  13628. }
  13629.  
  13630. bool Player::CanBuyAt(VendorRestrictionEntry* vendor)
  13631. {
  13632.     if(vendor == NULL)
  13633.         return true;
  13634.  
  13635.     if(vendor->flags == RESTRICTION_CHECK_ALL)
  13636.     {
  13637.         // check for race mask
  13638.         if((vendor->racemask > 0) && !(getRaceMask() & vendor->racemask))
  13639.             return false;
  13640.  
  13641.         // check for class mask
  13642.         if((vendor->classmask > 0) && !(getClassMask() & vendor->classmask))
  13643.             return false;
  13644.  
  13645.         // check for required reputation
  13646.         if(vendor->reqrepfaction)
  13647.         {
  13648.             uint32 plrep = GetStanding(vendor->reqrepfaction);
  13649.             if(plrep < vendor->reqrepvalue)
  13650.                 return false;
  13651.         }
  13652.     }
  13653.     else if(vendor->flags == RESTRICTION_CHECK_MOUNT_VENDOR)
  13654.     {
  13655.         if((vendor->racemask > 0) && (vendor->reqrepfaction))
  13656.         {
  13657.             uint32 plrep = GetStanding(vendor->reqrepfaction);
  13658.             if(!(getRaceMask() & vendor->racemask) && (plrep < vendor->reqrepvalue))
  13659.                 return false;
  13660.         }
  13661.         else
  13662.         {
  13663.             LOG_ERROR("VendorRestrictions: Mount vendor specified, but not enough info for creature %u", vendor->entry);
  13664.         }
  13665.     }
  13666.  
  13667.     return true;
  13668. }
  13669.  
  13670. bool Player::CanTrainAt(Trainer* trn)
  13671. {
  13672.     if((trn->RequiredClass && this->getClass() != trn->RequiredClass) ||
  13673.             ((trn->RequiredRace && this->getRace() != trn->RequiredRace) && ((trn->RequiredRepFaction && trn->RequiredRepValue) && this->GetStanding(trn->RequiredRepFaction) != static_cast<int32>(trn->RequiredRepValue))) ||
  13674.             (trn->RequiredSkill && !this->_HasSkillLine(trn->RequiredSkill)) ||
  13675.             (trn->RequiredSkillLine && this->_GetSkillLineCurrent(trn->RequiredSkill) < trn->RequiredSkillLine))
  13676.     {
  13677.         return false;
  13678.     }
  13679.  
  13680.     return true;
  13681. }
  13682.  
  13683. void Player::SendEmptyPetSpellList()
  13684. {
  13685.     WorldPacket data(SMSG_PET_SPELLS, 8);
  13686.     data << uint64(0);
  13687.     m_session->SendPacket(&data);
  13688. }
  13689.  
  13690. void Player::BuildPetSpellList(WorldPacket & data)
  13691. {
  13692.     data << uint64(0);
  13693. }
  13694.  
  13695. void Player::AddVehicleComponent( uint32 creature_entry, uint32 vehicleid ){
  13696.     if( mountvehicleid == 0 ){
  13697.         LOG_ERROR( "Tried to add a vehicle component with 0 as vehicle id for player %u ( %s )", GetLowGUID(), GetName() );
  13698.         return;
  13699.     }
  13700.  
  13701.     if( vehicle != NULL ){
  13702.         LOG_ERROR( "Tried to add a vehicle component, but there's already one for player %u ( %s )", GetLowGUID(), GetName() );
  13703.         return;
  13704.     }
  13705.    
  13706.     vehicle = new Vehicle();
  13707.     vehicle->Load( this, creature_entry, vehicleid );
  13708. }
  13709.  
  13710. void Player::RemoveVehicleComponent(){
  13711.     delete vehicle;
  13712.     vehicle = NULL;
  13713. }
Add Comment
Please, Sign In to add comment