From b071505216be07da3134ab40b4ad8b4ff75900ff Mon Sep 17 00:00:00 2001 From: Kapoeira Date: Thu, 12 Jan 2012 01:57:46 -0500 Subject: Scripts/Arenas: Fix achievement [The Last Standing]. Closes #3637. --- src/server/game/Battlegrounds/Battleground.cpp | 4 ++++ src/server/game/Battlegrounds/Battleground.h | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 6a758695116..36c9fe17ea5 100755 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -792,6 +792,10 @@ void Battleground::EndBattleground(uint32 winner) if (!player) continue; + // Last standing - Rated 5v5 arena & be solely alive player + if (team == winner && isArena() && isRated() && GetArenaType() == ARENA_TYPE_5v5 && GetAlivePlayersCountByTeam(winner) == 1 && player->isAlive()) + player->CastSpell(player, SPELL_THE_LAST_STANDING, true); + // should remove spirit of redemption if (player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT); diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index fcfc0c48cb4..274f7d04757 100755 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -98,7 +98,8 @@ enum BattlegroundSpells SPELL_RECENTLY_DROPPED_FLAG = 42792, // Recently Dropped Flag SPELL_AURA_PLAYER_INACTIVE = 43681, // Inactive SPELL_HONORABLE_DEFENDER_25Y = 68652, // +50% honor when standing at a capture point that you control, 25yards radius (added in 3.2) - SPELL_HONORABLE_DEFENDER_60Y = 66157 // +50% honor when standing at a capture point that you control, 60yards radius (added in 3.2), probably for 40+ player battlegrounds + SPELL_HONORABLE_DEFENDER_60Y = 66157, // +50% honor when standing at a capture point that you control, 60yards radius (added in 3.2), probably for 40+ player battlegrounds + SPELL_THE_LAST_STANDING = 26549, // Arena achievement related }; enum BattlegroundTimeIntervals -- cgit v1.2.3 From 894edcaafe2ff99deaa687adc05d725c4eb62ebd Mon Sep 17 00:00:00 2001 From: Kapoeira Date: Thu, 12 Jan 2012 02:05:11 -0500 Subject: Scripts/Arenas: Fix some typos in the last commit. I should stop hitting the Commit button as soon as possible. --- src/server/game/Battlegrounds/Battleground.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 36c9fe17ea5..59cfed42ab2 100755 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -771,6 +771,7 @@ void Battleground::EndBattleground(uint32 winner) } } + uint8 aliveWinners = GetAlivePlayersCountByTeam(winner); for (BattlegroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { uint32 team = itr->second.Team; @@ -793,7 +794,7 @@ void Battleground::EndBattleground(uint32 winner) continue; // Last standing - Rated 5v5 arena & be solely alive player - if (team == winner && isArena() && isRated() && GetArenaType() == ARENA_TYPE_5v5 && GetAlivePlayersCountByTeam(winner) == 1 && player->isAlive()) + if (team == winner && isArena() && isRated() && GetArenaType() == ARENA_TYPE_5v5 && aliveWinners == 1 && player->isAlive()) player->CastSpell(player, SPELL_THE_LAST_STANDING, true); // should remove spirit of redemption -- cgit v1.2.3 From 27f2baca1d3d5023ee298c29819ddfcb148874e7 Mon Sep 17 00:00:00 2001 From: Kapoeira Date: Thu, 12 Jan 2012 02:21:44 -0500 Subject: Scripts/Arenas: Also prevent bugs with Spirit of Redemption. Meh. Three commits for this. My bad. Farewell TrinityCore. :( --- src/server/game/Battlegrounds/Battleground.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 59cfed42ab2..5012a0f8665 100755 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -793,14 +793,14 @@ void Battleground::EndBattleground(uint32 winner) if (!player) continue; - // Last standing - Rated 5v5 arena & be solely alive player - if (team == winner && isArena() && isRated() && GetArenaType() == ARENA_TYPE_5v5 && aliveWinners == 1 && player->isAlive()) - player->CastSpell(player, SPELL_THE_LAST_STANDING, true); - // should remove spirit of redemption if (player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT); + // Last standing - Rated 5v5 arena & be solely alive player + if (team == winner && isArena() && isRated() && GetArenaType() == ARENA_TYPE_5v5 && aliveWinners == 1 && player->isAlive()) + player->CastSpell(player, SPELL_THE_LAST_STANDING, true); + if (!player->isAlive()) { player->ResurrectPlayer(1.0f); -- cgit v1.2.3 From 40c6e7bcdbff46f355af5b43bbf5ca0fd86e6777 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Date: Mon, 23 Jan 2012 20:03:06 -0300 Subject: Scripts/UK: Re-written Prince Keleseth script. * Corrected spawns amount, only 4 Skeletons must be spawned not 5. * Adjusted timers, now they are blizzlike. * This also includes skeleton resurrection timer. * Removed hacky code that was replacing spells (they are casted now). * Implemented "On The Rocks" achievement. Thanks to Subv for help. --- .../2012_01_23_01_world_creature_script_names.sql | 2 + sql/updates/world/2012_01_23_02_world_disables.sql | 1 + ...12_01_23_03_world_achievement_criteria_data.sql | 3 + .../world/2012_01_23_04_world_creature_text.sql | 9 + .../2012_01_23_05_world_spell_script_names.sql | 3 + .../UtgardeKeep/UtgardeKeep/boss_keleseth.cpp | 434 ++++++++++----------- 6 files changed, 223 insertions(+), 229 deletions(-) create mode 100644 sql/updates/world/2012_01_23_01_world_creature_script_names.sql create mode 100644 sql/updates/world/2012_01_23_02_world_disables.sql create mode 100644 sql/updates/world/2012_01_23_03_world_achievement_criteria_data.sql create mode 100644 sql/updates/world/2012_01_23_04_world_creature_text.sql create mode 100644 sql/updates/world/2012_01_23_05_world_spell_script_names.sql (limited to 'src') diff --git a/sql/updates/world/2012_01_23_01_world_creature_script_names.sql b/sql/updates/world/2012_01_23_01_world_creature_script_names.sql new file mode 100644 index 00000000000..d7c2b22725e --- /dev/null +++ b/sql/updates/world/2012_01_23_01_world_creature_script_names.sql @@ -0,0 +1,2 @@ +UPDATE `creature_template` SET `ScriptName`='npc_frost_tomb' WHERE `entry`=23965; +UPDATE `creature_template` SET `ScriptName`='npc_vrykul_skeleton' WHERE `entry`=23970; diff --git a/sql/updates/world/2012_01_23_02_world_disables.sql b/sql/updates/world/2012_01_23_02_world_disables.sql new file mode 100644 index 00000000000..0a1be704dac --- /dev/null +++ b/sql/updates/world/2012_01_23_02_world_disables.sql @@ -0,0 +1 @@ +DELETE FROM `disables` WHERE `entry`=7231 AND `sourceType`=4; diff --git a/sql/updates/world/2012_01_23_03_world_achievement_criteria_data.sql b/sql/updates/world/2012_01_23_03_world_achievement_criteria_data.sql new file mode 100644 index 00000000000..4d1f4536455 --- /dev/null +++ b/sql/updates/world/2012_01_23_03_world_achievement_criteria_data.sql @@ -0,0 +1,3 @@ +DELETE FROM `achievement_criteria_data` WHERE `criteria_id`=7231; +INSERT INTO `achievement_criteria_data` (`criteria_id`, `type`, `ScriptName`) VALUES +(7231,11,'achievement_on_the_rocks'); diff --git a/sql/updates/world/2012_01_23_04_world_creature_text.sql b/sql/updates/world/2012_01_23_04_world_creature_text.sql new file mode 100644 index 00000000000..f505a86b16c --- /dev/null +++ b/sql/updates/world/2012_01_23_04_world_creature_text.sql @@ -0,0 +1,9 @@ +DELETE FROM `script_texts` WHERE `entry` IN (-1574000,-1574001,-1574002,-1574003,-1574004); + +DELETE FROM `creature_text` WHERE `entry`=23953; +INSERT INTO `creature_text` (`entry`, `groupid`, `text`, `sound`, `emote`, `type`) VALUES +(23953,1,'Your blood is mine!',13221,7,14), +(23953,2,'Aranal, ledel! Their fate shall be yours!',13224,0,14), +(23953,3,'Not so fast.',13222,0,14), +(23953,4,'%s casts Frost Tomb on $n.',0,0,41), +(23953,5,'I join... the night.',13225,0,14); diff --git a/sql/updates/world/2012_01_23_05_world_spell_script_names.sql b/sql/updates/world/2012_01_23_05_world_spell_script_names.sql new file mode 100644 index 00000000000..6f3b4907e5b --- /dev/null +++ b/sql/updates/world/2012_01_23_05_world_spell_script_names.sql @@ -0,0 +1,3 @@ +DELETE FROM `spell_script_names` WHERE `spell_id`=48400; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(48400,'spell_frost_tomb'); diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp index dc93917f2e5..639d1852c15 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp @@ -17,354 +17,330 @@ /* ScriptData SDName: Boss_Prince_Keleseth -SD%Complete: 90 -SDComment: Needs Prince Movements, Needs adjustments to blizzlike timers, Needs Shadowbolt castbar, Needs right Ressurect Visual, Needs Some Heroic Spells +SD%Complete: 100 +SDComment: SDCategory: Utgarde Keep EndScriptData */ #include "ScriptPCH.h" #include "utgarde_keep.h" -enum eEnums +enum KelsethEncounter { - ACHIEVEMENT_ON_THE_ROCKS = 1919, - SPELL_SHADOWBOLT = 43667, - SPELL_SHADOWBOLT_HEROIC = 59389, SPELL_FROST_TOMB = 48400, + SPELL_FROST_TOMB_STUN = 42672, SPELL_FROST_TOMB_SUMMON = 42714, + + SPELL_SHADOW_FISSURE = 50657, + SPELL_FULL_HEAL = 17683, SPELL_DECREPIFY = 42702, - SPELL_SCOURGE_RESSURRECTION = 42704, - CREATURE_FROSTTOMB = 23965, - CREATURE_SKELETON = 23970, - - SAY_AGGRO = -1574000, - SAY_FROST_TOMB = -1574001, - SAY_SKELETONS = -1574002, - SAY_KILL = -1574003, - SAY_DEATH = -1574004 + SPELL_BONE_ARMOR = 59386, + + NPC_FROSTTOMB = 23965, + NPC_SKELETON = 23970, + + SAY_START_COMBAT = 1, + SAY_SUMMON_SKELETONS, + SAY_FROST_TOMB, + SAY_FROST_TOMB_EMOTE, + SAY_DEATH, + + EVENT_SHADOWBOLT = 1, + EVENT_FROST_TOMB, + EVENT_SUMMON_SKELETONS, + + EVENT_DECREPIFY, + EVENT_FULL_HEAL, + EVENT_SHADOW_FISSURE, + EVENT_RESURRECT, + + DATA_ON_THE_ROCKS }; #define SKELETONSPAWN_Z 42.8668f -float SkeletonSpawnPoint[5][5]= +const float SkeletonSpawnPoint[1][2] = { {156.2559f, 259.2093f}, - {156.2559f, 259.2093f}, - {156.2559f, 259.2093f}, - {156.2559f, 259.2093f}, - {156.2559f, 259.2093f}, }; -float AttackLoc[3]={197.636f, 194.046f, 40.8164f}; +float AttackLoc[3]= {197.636f, 194.046f, 40.8164f}; -bool ShatterFrostTomb; // needed for achievement: On The Rocks(1919) - -class mob_frost_tomb : public CreatureScript +class npc_frost_tomb : public CreatureScript { public: - mob_frost_tomb() : CreatureScript("mob_frost_tomb") { } + npc_frost_tomb() : CreatureScript("npc_frost_tomb") {} CreatureAI* GetAI(Creature* creature) const { - return new mob_frost_tombAI(creature); + return new npc_frost_tombAI(creature); } - struct mob_frost_tombAI : public ScriptedAI + struct npc_frost_tombAI : public ScriptedAI { - mob_frost_tombAI(Creature* c) : ScriptedAI(c) + npc_frost_tombAI(Creature* creature) : ScriptedAI(creature) { - FrostTombGUID = 0; - } - - uint64 FrostTombGUID; + if (me->isSummon()) + if (Unit* summon = me->ToTempSummon()->GetSummoner()) + DoCast(summon, SPELL_FROST_TOMB, true); - void SetPrisoner(Unit* uPrisoner) - { - FrostTombGUID = uPrisoner->GetGUID(); + instance = creature->GetInstanceScript(); } - void Reset(){ FrostTombGUID = 0; } - void EnterCombat(Unit* /*who*/) {} - void AttackStart(Unit* /*who*/) {} - void MoveInLineOfSight(Unit* /*who*/) {} + void UpdateAI(const uint32 /*diff*/) {} - void JustDied(Unit* killer) + void JustDied(Unit* /*killer*/) { - if (killer->GetGUID() != me->GetGUID()) - ShatterFrostTomb = true; - - if (FrostTombGUID) - { - Unit* FrostTomb = Unit::GetUnit((*me), FrostTombGUID); - if (FrostTomb) - FrostTomb->RemoveAurasDueToSpell(SPELL_FROST_TOMB); - } + if (instance) + if (Unit* boss = me->GetUnit(*me, instance->GetData64(DATA_PRINCEKELESETH))) + if (boss->ToCreature() && boss->ToCreature()->AI()) + boss->ToCreature()->AI()->SetData(DATA_ON_THE_ROCKS, false); } - void UpdateAI(const uint32 /*diff*/) - { - Unit* temp = Unit::GetUnit((*me), FrostTombGUID); - if ((temp && temp->isAlive() && !temp->HasAura(SPELL_FROST_TOMB)) || !temp) - me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } + private: + InstanceScript* instance; }; - }; class boss_keleseth : public CreatureScript { public: - boss_keleseth() : CreatureScript("boss_keleseth") { } + boss_keleseth() : CreatureScript("boss_keleseth") {} CreatureAI* GetAI(Creature* creature) const { return new boss_kelesethAI (creature); } - struct boss_kelesethAI : public ScriptedAI + struct boss_kelesethAI : public BossAI { - boss_kelesethAI(Creature* c) : ScriptedAI(c) + boss_kelesethAI(Creature* creature) : BossAI(creature, DATA_PRINCEKELESETH_EVENT) { - instance = c->GetInstanceScript(); + creature->SetReactState(REACT_DEFENSIVE); } - InstanceScript* instance; - - uint32 FrostTombTimer; - uint32 SummonSkeletonsTimer; - uint32 RespawnSkeletonsTimer; - uint32 ShadowboltTimer; - uint64 SkeletonGUID[5]; - bool Skeletons; - bool RespawnSkeletons; - void Reset() { - ShadowboltTimer = 0; - Skeletons = false; + instance->SetData(DATA_PRINCEKELESETH_EVENT, NOT_STARTED); - ShatterFrostTomb = false; + events.Reset(); + events.ScheduleEvent(EVENT_SHADOWBOLT, urand(2,3)*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_FROST_TOMB, urand(14,19)*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SUMMON_SKELETONS, 6*IN_MILLISECONDS); - ResetTimer(); + summons.DespawnAll(); - if (instance) - instance->SetData(DATA_PRINCEKELESETH_EVENT, NOT_STARTED); + onTheRocks = true; } - void KilledUnit(Unit* victim) + void EnterCombat(Unit* /*who*/) { - if (victim == me) - return; - - DoScriptText(SAY_KILL, me); + me->SetInCombatWithZone(); + instance->SetData(DATA_PRINCEKELESETH_EVENT, IN_PROGRESS); + Talk(SAY_START_COMBAT); } void JustDied(Unit* /*killer*/) { - DoScriptText(SAY_DEATH, me); - - if (IsHeroic() && !ShatterFrostTomb) - { - AchievementEntry const* AchievOnTheRocks = GetAchievementStore()->LookupEntry(ACHIEVEMENT_ON_THE_ROCKS); - if (AchievOnTheRocks) - { - Map* map = me->GetMap(); - if (map && map->IsDungeon()) - { - Map::PlayerList const &players = map->GetPlayers(); - for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) - itr->getSource()->CompletedAchievement(AchievOnTheRocks); - } - } - } - - if (instance) - instance->SetData(DATA_PRINCEKELESETH_EVENT, DONE); + instance->SetData(DATA_PRINCEKELESETH_EVENT, DONE); + summons.DespawnAll(); + Talk(SAY_DEATH); } - void EnterCombat(Unit* /*who*/) + void SetData(uint32 data, uint32 value) { - DoScriptText(SAY_AGGRO, me); - DoZoneInCombat(); - - if (instance) - instance->SetData(DATA_PRINCEKELESETH_EVENT, IN_PROGRESS); + if (data == DATA_ON_THE_ROCKS) + onTheRocks = value; } - void ResetTimer(uint32 inc = 0) + uint32 GetData(uint32 data) { - SummonSkeletonsTimer = 5000 + inc; - FrostTombTimer = 28000 + inc; + if (data == DATA_ON_THE_ROCKS) + return onTheRocks; + + return 0; } - void UpdateAI(const uint32 diff) + void ExecuteEvent(uint32 const eventId) { - if (!UpdateVictim()) - return; - - if (ShadowboltTimer <= diff) + switch (eventId) { - Unit* target = SelectTarget(SELECT_TARGET_TOPAGGRO, 0); - if (target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER) - me->CastSpell(target, DUNGEON_MODE(SPELL_SHADOWBOLT, SPELL_SHADOWBOLT_HEROIC), true); - ShadowboltTimer = 10000; - } else ShadowboltTimer -= diff; - - if (!Skeletons) - { - if ((SummonSkeletonsTimer <= diff)) - { - Creature* Skeleton; - DoScriptText(SAY_SKELETONS, me); - for (uint8 i = 0; i < 5; ++i) + case EVENT_SUMMON_SKELETONS: + Talk(SAY_SUMMON_SKELETONS); + SummonSkeletons(); + break; + case EVENT_SHADOWBOLT: + DoCastVictim(SPELL_SHADOWBOLT); + events.ScheduleEvent(EVENT_SHADOWBOLT, urand(2,3)*IN_MILLISECONDS); + break; + case EVENT_FROST_TOMB: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true, -SPELL_FROST_TOMB)) { - Skeleton = me->SummonCreature(CREATURE_SKELETON, SkeletonSpawnPoint[i][0], SkeletonSpawnPoint[i][1], SKELETONSPAWN_Z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000); - if (Skeleton) - { - Skeleton->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); - Skeleton->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()); - Skeleton->AddThreat(me->getVictim(), 0.0f); - DoZoneInCombat(Skeleton); - } - } - Skeletons = true; - } else SummonSkeletonsTimer -= diff; - } + Talk(SAY_FROST_TOMB); + Talk(SAY_FROST_TOMB_EMOTE, target->GetGUID()); - if (FrostTombTimer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) - if (target->isAlive()) - { - //DoCast(target, SPELL_FROST_TOMB_SUMMON, true); - if (Creature* pChains = me->SummonCreature(CREATURE_FROSTTOMB, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 20000)) - { - CAST_AI(mob_frost_tomb::mob_frost_tombAI, pChains->AI())->SetPrisoner(target); - pChains->CastSpell(target, SPELL_FROST_TOMB, true); - - DoScriptText(SAY_FROST_TOMB, me); - } + DoCast(target, SPELL_FROST_TOMB_STUN, true); + // checked from sniffs - the player casts the spell + target->CastSpell(target, SPELL_FROST_TOMB_SUMMON, true); } - FrostTombTimer = 15000; - } else FrostTombTimer -= diff; + events.ScheduleEvent(EVENT_FROST_TOMB, urand(14,19)*IN_MILLISECONDS); + break; + } + } - DoMeleeAttackIfReady(); + void SummonSkeletons() + { + // I could not found any spell casted for this + for (uint8 i = 0; i < 4; ++i) + me->SummonCreature(NPC_SKELETON, SkeletonSpawnPoint[0][0], SkeletonSpawnPoint[0][1], SKELETONSPAWN_Z, 0); } + private: + bool onTheRocks; }; - }; -class mob_vrykul_skeleton : public CreatureScript +class npc_vrykul_skeleton : public CreatureScript { public: - mob_vrykul_skeleton() : CreatureScript("mob_vrykul_skeleton") { } + npc_vrykul_skeleton() : CreatureScript("npc_vrykul_skeleton") {} CreatureAI* GetAI(Creature* creature) const { - return new mob_vrykul_skeletonAI (creature); + return new npc_vrykul_skeletonAI (creature); } - struct mob_vrykul_skeletonAI : public ScriptedAI + struct npc_vrykul_skeletonAI : public ScriptedAI { - mob_vrykul_skeletonAI(Creature* c) : ScriptedAI(c) - { - instance = c->GetInstanceScript(); - } - - InstanceScript* instance; - uint32 Respawn_Time; - uint64 Target_Guid; - uint32 Decrepify_Timer; - - bool isDead; + npc_vrykul_skeletonAI(Creature* creature) : ScriptedAI(creature) {} void Reset() { - Respawn_Time = 12000; - Decrepify_Timer = urand(10000, 20000); - isDead = false; + events.Reset(); + events.ScheduleEvent(EVENT_DECREPIFY, urand(4,6)*IN_MILLISECONDS); + + DoCast(SPELL_BONE_ARMOR); } - void EnterCombat(Unit* /*who*/){} - void DamageTaken(Unit* done_by, uint32 &damage) + void DamageTaken(Unit* /*done_by*/, uint32 &damage) { - if (done_by->GetGUID() == me->GetGUID()) - return; - if (damage >= me->GetHealth()) { - PretendToDie(); damage = 0; - } - } - void PretendToDie() - { - isDead = true; - me->InterruptNonMeleeSpells(true); - me->RemoveAllAuras(); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - me->GetMotionMaster()->MovementExpired(false); - me->GetMotionMaster()->MoveIdle(); - me->SetStandState(UNIT_STAND_STATE_DEAD); - }; + // There are some issues with pets + // they will still attack. I would say it is a PetAI bug + if (!me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) + { + // from sniffs + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetFlag(UNIT_FIELD_BYTES_1, UNIT_STAND_STATE_DEAD); - void Resurrect() - { - isDead = false; - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - me->SetStandState(UNIT_STAND_STATE_STAND); - DoCast(me, SPELL_SCOURGE_RESSURRECTION, true); + events.Reset(); + events.ScheduleEvent(EVENT_RESURRECT, urand(18,22)*IN_MILLISECONDS); - if (me->getVictim()) - { - me->GetMotionMaster()->MoveChase(me->getVictim()); - me->AI()->AttackStart(me->getVictim()); + me->GetMotionMaster()->MovementExpired(false); + me->GetMotionMaster()->MoveIdle(); + } } - else - me->GetMotionMaster()->Initialize(); - }; + } void UpdateAI(const uint32 diff) { - if (instance && instance->GetData(DATA_PRINCEKELESETH_EVENT) == IN_PROGRESS) + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - if (isDead) + switch (eventId) { - if (Respawn_Time <= diff) - { - Resurrect(); - Respawn_Time = 12000; - } else Respawn_Time -= diff; + case EVENT_DECREPIFY: + DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_DECREPIFY), SPELL_DECREPIFY); + events.ScheduleEvent(EVENT_DECREPIFY, urand(1,5)*IN_MILLISECONDS); + break; + case EVENT_RESURRECT: + events.ScheduleEvent(EVENT_FULL_HEAL, 1*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SHADOW_FISSURE, 1*IN_MILLISECONDS); + break; + case EVENT_FULL_HEAL: + DoCast(me, SPELL_FULL_HEAL, true); + break; + case EVENT_SHADOW_FISSURE: + DoCast(me, SPELL_SHADOW_FISSURE, true); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->RemoveFlag(UNIT_FIELD_BYTES_1, UNIT_STAND_STATE_DEAD); + me->GetMotionMaster()->MoveChase(me->getVictim()); + events.ScheduleEvent(EVENT_DECREPIFY, urand(4,6)*IN_MILLISECONDS); + break; } - else - { - if (!UpdateVictim()) - return; + } - if (Decrepify_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_DECREPIFY); - Decrepify_Timer = 30000; - } else Decrepify_Timer -= diff; + if (!me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) + DoMeleeAttackIfReady(); + } - DoMeleeAttackIfReady(); - } - }else + private: + EventMap events; + }; +}; + +class spell_frost_tomb : public SpellScriptLoader +{ + public: + spell_frost_tomb() : SpellScriptLoader("spell_frost_tomb") {} + + class spell_frost_tomb_AuraScript : public AuraScript + { + PrepareAuraScript(spell_frost_tomb_AuraScript); + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - if (me->isAlive()) - me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEATH) + if (Unit* caster = GetCaster()) + if (caster->ToCreature() && caster->isAlive()) + caster->ToCreature()->DespawnOrUnsummon(); } + void Register() + { + AfterEffectRemove += AuraEffectRemoveFn(spell_frost_tomb_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_frost_tomb_AuraScript(); } - }; +}; + +class achievement_on_the_rocks : public AchievementCriteriaScript +{ + public: + achievement_on_the_rocks() : AchievementCriteriaScript("achievement_on_the_rocks") {} + + bool OnCheck(Player* source, Unit* target) + { + if (!source->GetMap()->IsHeroic()) + return false; + + if (Creature* boss = target->ToCreature()) + if (boss->AI()) + return boss->AI()->GetData(DATA_ON_THE_ROCKS); + + return false; + } }; void AddSC_boss_keleseth() { new boss_keleseth(); - new mob_frost_tomb(); - new mob_vrykul_skeleton(); + new npc_frost_tomb(); + new npc_vrykul_skeleton(); + new spell_frost_tomb(); + new achievement_on_the_rocks(); } -- cgit v1.2.3 From e6d5b21778762fec1ae21d3ce093102373cc8ec5 Mon Sep 17 00:00:00 2001 From: click Date: Tue, 24 Jan 2012 00:24:39 +0100 Subject: Core: Fix non-PCH build and remove a few warnings. --- src/server/game/AI/CoreAI/GameObjectAI.h | 2 +- src/server/game/Entities/Player/Player.cpp | 2 +- src/server/game/Entities/Player/Player.h | 2 +- .../game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp | 1 + .../game/Movement/MovementGenerators/PointMovementGenerator.cpp | 1 + .../game/Movement/MovementGenerators/TargetedMovementGenerator.cpp | 1 + .../game/Movement/MovementGenerators/TargetedMovementGenerator.h | 1 + src/server/scripts/Commands/cs_reload.cpp | 2 +- .../scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp | 6 +++--- .../Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp | 3 +++ src/server/shared/Cryptography/HMACSHA1.cpp | 1 + 11 files changed, 15 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/server/game/AI/CoreAI/GameObjectAI.h b/src/server/game/AI/CoreAI/GameObjectAI.h index bfdd887de3e..b9d385ba675 100644 --- a/src/server/game/AI/CoreAI/GameObjectAI.h +++ b/src/server/game/AI/CoreAI/GameObjectAI.h @@ -50,7 +50,7 @@ class GameObjectAI virtual void Destroyed(Player* /*player*/, uint32 /*eventId*/) {} virtual void SetData(uint32 /*id*/, uint32 /*value*/) {} virtual void OnGameEvent(bool /*start*/, uint16 /*eventId*/) {} - virtual void OnStateChanged(uint32 state, Unit* unit) { } + virtual void OnStateChanged(uint32 /*state*/, Unit* /*unit*/) { } }; class NullGameObjectAI : public GameObjectAI diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 00fbab8ceb3..44186dad95c 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -305,7 +305,7 @@ bool TradeData::HasItem(uint64 itemGuid) const return false; } -TradeSlots const TradeData::GetTradeSlotForItem(uint64 itemGuid) +TradeSlots TradeData::GetTradeSlotForItem(uint64 itemGuid) const { for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) if (m_items[i] == itemGuid) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index fccd380bd29..c39d29db12a 100755 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1003,7 +1003,7 @@ class TradeData Item* GetItem(TradeSlots slot) const; bool HasItem(uint64 itemGuid) const; - TradeSlots const GetTradeSlotForItem(uint64 itemGuid); + TradeSlots GetTradeSlotForItem(uint64 itemGuid) const; void SetItem(TradeSlots slot, Item* item); uint32 GetSpell() const { return m_spell; } diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp index ac09f2d403a..94608d85420 100755 --- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp @@ -22,6 +22,7 @@ #include "VMapFactory.h" #include "MoveSplineInit.h" #include "MoveSpline.h" +#include "Player.h" #ifdef MAP_BASED_RAND_GEN #define rand_norm() unit.rand_norm() diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp index 505615c07b8..88465017dc2 100755 --- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp @@ -23,6 +23,7 @@ #include "World.h" #include "MoveSplineInit.h" #include "MoveSpline.h" +#include "Player.h" //----- Point Movement Generator template diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp index b03e13f91f4..0d2982ab6b7 100755 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp @@ -24,6 +24,7 @@ #include "World.h" #include "MoveSplineInit.h" #include "MoveSpline.h" +#include "Player.h" #include diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h index 982f7fc875c..696c99e1460 100755 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h @@ -22,6 +22,7 @@ #include "MovementGenerator.h" #include "FollowerReference.h" #include "Timer.h" +#include "Unit.h" class TargetedMovementGeneratorBase { diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index 35b590fe404..363f7645f6f 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -992,7 +992,7 @@ public: return true; } - static bool HandleReloadWpCommand(ChatHandler* handler, const char* args) + static bool HandleReloadWpCommand(ChatHandler* /*handler*/, const char* args) { if (*args != 'a') sLog->outString("Re-Loading Waypoints data from 'waypoints_data'"); diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp index 542243293de..5c1ec15030c 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp @@ -276,7 +276,7 @@ public: me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); } - void JustDied(Unit* killer) + void JustDied(Unit* /*killer*/) { summons.DespawnAll(); @@ -285,8 +285,8 @@ public: Talk(SAY_DEATH); } - - void SpellHitTarget(Unit* target, const SpellInfo* spell) + + void SpellHitTarget(Unit* /*target*/, const SpellInfo* spell) { if (spell->Id == SPELL_RITUAL_STRIKE_EFF_1 && Phase != NORMAL && Phase != SVALADEAD) { diff --git a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp index 070c107e61d..ed818fb13be 100644 --- a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp +++ b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp @@ -17,6 +17,9 @@ //! TODO - Boss not scripted, just ported required spellscript from core +#include "ScriptMgr.h" +#include "SpellScript.h" + enum Spells { SPELL_POSITIVE_CHARGE = 39090, diff --git a/src/server/shared/Cryptography/HMACSHA1.cpp b/src/server/shared/Cryptography/HMACSHA1.cpp index 3f21aa4582d..447d0b58efc 100755 --- a/src/server/shared/Cryptography/HMACSHA1.cpp +++ b/src/server/shared/Cryptography/HMACSHA1.cpp @@ -18,6 +18,7 @@ #include "HMACSHA1.h" #include "BigNumber.h" +#include "Common.h" HmacHash::HmacHash(uint32 len, uint8 *seed) { -- cgit v1.2.3 From 78ede251b05c4e9a4fa6c21dfd0bc65892d3788a Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Date: Mon, 23 Jan 2012 23:15:57 -0300 Subject: Scripts/UK: Improvements to my last commit. Thanks to Vincent-Michael --- .../world/2012_01_23_06_world_achievement_criteria_data.sql | 3 +++ sql/updates/world/2012_01_23_07_world_creature_text.sql | 5 +++++ .../Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp | 13 +++---------- 3 files changed, 11 insertions(+), 10 deletions(-) create mode 100644 sql/updates/world/2012_01_23_06_world_achievement_criteria_data.sql create mode 100644 sql/updates/world/2012_01_23_07_world_creature_text.sql (limited to 'src') diff --git a/sql/updates/world/2012_01_23_06_world_achievement_criteria_data.sql b/sql/updates/world/2012_01_23_06_world_achievement_criteria_data.sql new file mode 100644 index 00000000000..33899c3f512 --- /dev/null +++ b/sql/updates/world/2012_01_23_06_world_achievement_criteria_data.sql @@ -0,0 +1,3 @@ +DELETE FROM `achievement_criteria_data` WHERE `criteria_id`=7231 AND `type`=12; +INSERT INTO `achievement_criteria_data` (`criteria_id`, `type`, `value1`, `value2`, `ScriptName`) VALUES +(7231,12,1,0,''); diff --git a/sql/updates/world/2012_01_23_07_world_creature_text.sql b/sql/updates/world/2012_01_23_07_world_creature_text.sql new file mode 100644 index 00000000000..90ac11e363c --- /dev/null +++ b/sql/updates/world/2012_01_23_07_world_creature_text.sql @@ -0,0 +1,5 @@ +UPDATE `creature_text` SET `comment`='Prince Keleseth - SAY_DEATH' WHERE `groupid`=5 AND `entry`=23953; +UPDATE `creature_text` SET `comment`='Prince Keleseth - SAY_FROST_TOMB_EMOTE' WHERE `groupid`=4 AND `entry`=23953; +UPDATE `creature_text` SET `comment`='Prince Keleseth - SAY_FROST_TOMB' WHERE `groupid`=3 AND `entry`=23953; +UPDATE `creature_text` SET `comment`='Prince Keleseth - SAY_SUMMON_SKELETONS' WHERE `groupid`=2 AND `entry`=23953; +UPDATE `creature_text` SET `comment`='Prince Keleseth - SAY_START_COMBAT' WHERE `groupid`=1 AND `entry`=23953; diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp index 639d1852c15..ea54fc16095 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp @@ -60,7 +60,7 @@ enum KelsethEncounter #define SKELETONSPAWN_Z 42.8668f -const float SkeletonSpawnPoint[1][2] = +float const SkeletonSpawnPoint[1][2] = { {156.2559f, 259.2093f}, }; @@ -323,16 +323,9 @@ class achievement_on_the_rocks : public AchievementCriteriaScript public: achievement_on_the_rocks() : AchievementCriteriaScript("achievement_on_the_rocks") {} - bool OnCheck(Player* source, Unit* target) + bool OnCheck(Player* /*source*/, Unit* target) { - if (!source->GetMap()->IsHeroic()) - return false; - - if (Creature* boss = target->ToCreature()) - if (boss->AI()) - return boss->AI()->GetData(DATA_ON_THE_ROCKS); - - return false; + return target && target->IsAIEnabled && target->GetAI()->GetData(DATA_ON_THE_ROCKS); } }; -- cgit v1.2.3 From e552b1744c28fb80b90eb29246682787974f0f6e Mon Sep 17 00:00:00 2001 From: Souler Date: Tue, 24 Jan 2012 15:12:47 +0100 Subject: DB/Conditions: Convert Dame Evniki Kapsalis script into conditions DB/SAI: Convert Priestess Alorah and Grimmin scripts into SmartAI --- sql/updates/world/2012_01_24_00_world_misc.sql | 18 +++++ src/server/scripts/Northrend/icecrown.cpp | 93 -------------------------- 2 files changed, 18 insertions(+), 93 deletions(-) create mode 100644 sql/updates/world/2012_01_24_00_world_misc.sql (limited to 'src') diff --git a/sql/updates/world/2012_01_24_00_world_misc.sql b/sql/updates/world/2012_01_24_00_world_misc.sql new file mode 100644 index 00000000000..b66a0bd91ca --- /dev/null +++ b/sql/updates/world/2012_01_24_00_world_misc.sql @@ -0,0 +1,18 @@ +-- Make Dame Evniki Kapsalis show vendor gossip option only to players with Crusader title +UPDATE `creature_template` SET `AIName` = 'SmartAI',`ScriptName` = '' WHERE `entry` = 34885; +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=10598; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`ErrorTextId`,`ScriptName`,`COMMENT`) VALUES +(15,10598,0,0,17,2816,0,0,0,'',"Evniki Kapsalis should only sell to Crusaders"), +(15,10598,0,1,17,2817,0,0,0,'',"Evniki Kapsalis should only sell to Crusaders"); + +SET @SPELL_CHAIN = 68341; +SET @NPC_FJOLA_LIGHTBANE = 36065; +SET @NPC_EYDIS_DARKBANE = 36066; +SET @NPC_PRIESTESS_ALORAH = 36101; +SET @NPC_PRIEST_GRIMMIN = 36102; + +UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName` = '' WHERE `entry` IN(@NPC_PRIESTESS_ALORAH,@NPC_PRIEST_GRIMMIN); +DELETE FROM `smart_scripts` WHERE (`entryorguid` IN(@NPC_PRIESTESS_ALORAH,@NPC_PRIEST_GRIMMIN) AND `source_type`=0); +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@NPC_PRIESTESS_ALORAH,0,0,0,1,0,100,1,100,100,0,0,11,@SPELL_CHAIN,0,0,0,0,0,19,@NPC_EYDIS_DARKBANE,0,0,0,0,0,0,'Priestess Alorah - Cast chain on Eydis Darkbane'), +(@NPC_PRIEST_GRIMMIN,0,0,0,1,0,100,1,100,100,0,0,11,@SPELL_CHAIN,0,0,0,0,0,19,@NPC_FJOLA_LIGHTBANE,0,0,0,0,0,0,'Priestess Grimmin - Cast chain on Fjola Lightbane'); \ No newline at end of file diff --git a/src/server/scripts/Northrend/icecrown.cpp b/src/server/scripts/Northrend/icecrown.cpp index 28384455616..91522503d65 100644 --- a/src/server/scripts/Northrend/icecrown.cpp +++ b/src/server/scripts/Northrend/icecrown.cpp @@ -114,38 +114,6 @@ public: } }; -/*###### -## npc_dame_evniki_kapsalis -######*/ - -enum eDameEnvikiKapsalis -{ - TITLE_CRUSADER = 123 -}; - -class npc_dame_evniki_kapsalis : public CreatureScript -{ -public: - npc_dame_evniki_kapsalis() : CreatureScript("npc_dame_evniki_kapsalis") { } - - bool OnGossipHello(Player* player, Creature* creature) - { - if (player->HasTitle(TITLE_CRUSADER)) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - - player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); - return true; - } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*uiSender*/, uint32 uiAction) - { - player->PlayerTalkClass->ClearMenus(); - if (uiAction == GOSSIP_ACTION_TRADE) - player->GetSession()->SendListInventory(creature->GetGUID()); - return true; - } -}; - /*###### ## npc_squire_david ######*/ @@ -275,65 +243,6 @@ public: } }; -/*###### -## npc_alorah_and_grimmin -######*/ - -enum ealorah_and_grimmin -{ - SPELL_CHAIN = 68341, - NPC_FJOLA_LIGHTBANE = 36065, - NPC_EYDIS_DARKBANE = 36066, - NPC_PRIESTESS_ALORAH = 36101, - NPC_PRIEST_GRIMMIN = 36102 -}; - -class npc_alorah_and_grimmin : public CreatureScript -{ -public: - npc_alorah_and_grimmin() : CreatureScript("npc_alorah_and_grimmin") { } - - struct npc_alorah_and_grimminAI : public ScriptedAI - { - npc_alorah_and_grimminAI(Creature* creature) : ScriptedAI(creature) {} - - bool uiCast; - - void Reset() - { - uiCast = false; - } - - void UpdateAI(const uint32 /*uiDiff*/) - { - if (uiCast) - return; - uiCast = true; - Creature* target = NULL; - - switch (me->GetEntry()) - { - case NPC_PRIESTESS_ALORAH: - target = me->FindNearestCreature(NPC_EYDIS_DARKBANE, 10.0f); - break; - case NPC_PRIEST_GRIMMIN: - target = me->FindNearestCreature(NPC_FJOLA_LIGHTBANE, 10.0f); - break; - } - if (target) - DoCast(target, SPELL_CHAIN); - - if (!UpdateVictim()) - return; - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_alorah_and_grimminAI(creature); - } -}; - /*###### ## npc_guardian_pavilion ######*/ @@ -429,10 +338,8 @@ public: void AddSC_icecrown() { new npc_arete; - new npc_dame_evniki_kapsalis; new npc_squire_david; new npc_argent_valiant; - new npc_alorah_and_grimmin; new npc_guardian_pavilion; new npc_vereth_the_cunning; } -- cgit v1.2.3 From e28dbe9f884ec1171abe88fbd567da6d6b68a79f Mon Sep 17 00:00:00 2001 From: leak Date: Tue, 24 Jan 2012 20:56:16 +0100 Subject: Core/AuthServer: Streamlined authserver log messages (added client port for easier identification and matching for multiple connections from same IP) --- src/server/authserver/Server/AuthSocket.cpp | 37 +++++++++++++++------------- src/server/authserver/Server/RealmSocket.cpp | 14 ++++++++--- src/server/authserver/Server/RealmSocket.h | 7 ++++-- 3 files changed, 35 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/server/authserver/Server/AuthSocket.cpp b/src/server/authserver/Server/AuthSocket.cpp index 1f85cb6bc5b..6d295a0bbee 100755 --- a/src/server/authserver/Server/AuthSocket.cpp +++ b/src/server/authserver/Server/AuthSocket.cpp @@ -209,7 +209,7 @@ AuthSocket::~AuthSocket(void) {} // Accept the connection and set the s random value for SRP6 void AuthSocket::OnAccept(void) { - sLog->outBasic("Accepting connection from '%s'", socket().get_remote_address().c_str()); + sLog->outBasic("'%s:%d' Accepting connection", socket().getRemoteAddress().c_str(), socket().getRemotePort()); } void AuthSocket::OnClose(void) @@ -247,7 +247,7 @@ void AuthSocket::OnRead() // Report unknown packets in the error log if (i == AUTH_TOTAL_COMMANDS) { - sLog->outError("[Auth] got unknown packet from '%s'", socket().get_remote_address().c_str()); + sLog->outError("[Auth] got unknown packet from '%s'", socket().getRemoteAddress().c_str()); socket().shutdown(); return; } @@ -350,14 +350,14 @@ bool AuthSocket::_HandleLogonChallenge() // Verify that this IP is not in the ip_banned table LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); - const std::string& ip_address = socket().get_remote_address(); + const std::string& ip_address = socket().getRemoteAddress(); PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_BANNED); stmt->setString(0, ip_address); PreparedQueryResult result = LoginDatabase.Query(stmt); if (result) { pkt << (uint8)WOW_FAIL_BANNED; - sLog->outBasic("[AuthChallenge] Banned ip %s tried to login!", ip_address.c_str()); + sLog->outBasic("'%s:%d' [AuthChallenge] Banned ip tries to login!",socket().getRemoteAddress().c_str(), socket().getRemotePort()); } else { @@ -404,12 +404,12 @@ bool AuthSocket::_HandleLogonChallenge() if ((*banresult)[0].GetUInt64() == (*banresult)[1].GetUInt64()) { pkt << (uint8)WOW_FAIL_BANNED; - sLog->outBasic("[AuthChallenge] Banned account %s tried to login!", _login.c_str()); + sLog->outBasic("'%s:%d' [AuthChallenge] Banned account %s tried to login!", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str ()); } else { pkt << (uint8)WOW_FAIL_SUSPENDED; - sLog->outBasic("[AuthChallenge] Temporarily banned account %s tried to login!", _login.c_str()); + sLog->outBasic("'%s:%d' [AuthChallenge] Temporarily banned account %s tried to login!", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str ()); } } else @@ -480,7 +480,9 @@ bool AuthSocket::_HandleLogonChallenge() for (int i = 0; i < 4; ++i) _localizationName[i] = ch->country[4-i-1]; - sLog->outBasic("[AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", _login.c_str (), ch->country[3], ch->country[2], ch->country[1], ch->country[0], GetLocaleByName(_localizationName)); + sLog->outBasic("'%s:%d' [AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", socket().getRemoteAddress().c_str(), socket().getRemotePort(), + _login.c_str (), ch->country[3], ch->country[2], ch->country[1], ch->country[0], GetLocaleByName(_localizationName) + ); } } } @@ -590,7 +592,7 @@ bool AuthSocket::_HandleLogonProof() // Check if SRP6 results match (password is correct), else send an error if (!memcmp(M.AsByteArray(), lp.M1, 20)) { - sLog->outBasic("User '%s' successfully authenticated", _login.c_str()); + sLog->outBasic("'%s:%d' User '%s' successfully authenticated", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); // Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account // No SQL injection (escaped user name) and IP address as received by socket @@ -598,7 +600,7 @@ bool AuthSocket::_HandleLogonProof() PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF); stmt->setString(0, K_hex); - stmt->setString(1, socket().get_remote_address().c_str()); + stmt->setString(1, socket().getRemoteAddress().c_str()); stmt->setUInt32(2, GetLocaleByName(_localizationName)); stmt->setString(3, _login); LoginDatabase.Execute(stmt); @@ -638,7 +640,7 @@ bool AuthSocket::_HandleLogonProof() char data[4] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 }; socket().send(data, sizeof(data)); - sLog->outBasic("[AuthChallenge] account %s tried to login with wrong password!", _login.c_str()); + sLog->outBasic("'%s:%d' [AuthChallenge] account %s tried to login with invalid password!", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str ()); uint32 MaxWrongPassCount = ConfigMgr::GetIntDefault("WrongPass.MaxCount", 0); if (MaxWrongPassCount > 0) @@ -668,17 +670,18 @@ bool AuthSocket::_HandleLogonProof() stmt->setUInt32(1, WrongPassBanTime); LoginDatabase.Execute(stmt); - sLog->outBasic("[AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times", - _login.c_str(), WrongPassBanTime, failed_logins); + sLog->outBasic("'%s:%d' [AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times", + socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str(), WrongPassBanTime, failed_logins); } else { stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_AUTO_BANNED); - stmt->setString(0, socket().get_remote_address()); + stmt->setString(0, socket().getRemoteAddress()); stmt->setUInt32(1, WrongPassBanTime); LoginDatabase.Execute(stmt); - sLog->outBasic("[AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times", socket().get_remote_address().c_str(), WrongPassBanTime, _login.c_str(), failed_logins); + sLog->outBasic("'%s:%d' [AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times", + socket().getRemoteAddress().c_str(), socket().getRemotePort(), socket().getRemoteAddress().c_str(), WrongPassBanTime, _login.c_str(), failed_logins); } } } @@ -730,7 +733,7 @@ bool AuthSocket::_HandleReconnectChallenge() // Stop if the account is not found if (!result) { - sLog->outError("[ERROR] user %s tried to login and we cannot find his session key in the database.", _login.c_str()); + sLog->outError("'%s:%d' [ERROR] user %s tried to login and we cannot find his session key in the database.", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); socket().shutdown(); return false; } @@ -790,7 +793,7 @@ bool AuthSocket::_HandleReconnectProof() } else { - sLog->outError("[ERROR] user %s tried to login, but session invalid.", _login.c_str()); + sLog->outError("'%s:%d' [ERROR] user %s tried to login, but session is invalid.", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); socket().shutdown(); return false; } @@ -812,7 +815,7 @@ bool AuthSocket::_HandleRealmList() PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) { - sLog->outError("[ERROR] user %s tried to login and we cannot find him in the database.", _login.c_str()); + sLog->outError("'%s:%d' [ERROR] user %s tried to login but we cannot find him in the database.", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); socket().shutdown(); return false; } diff --git a/src/server/authserver/Server/RealmSocket.cpp b/src/server/authserver/Server/RealmSocket.cpp index a796daae17d..72c36fc6646 100755 --- a/src/server/authserver/Server/RealmSocket.cpp +++ b/src/server/authserver/Server/RealmSocket.cpp @@ -31,7 +31,7 @@ RealmSocket::Session::Session(void) {} RealmSocket::Session::~Session(void) { } -RealmSocket::RealmSocket(void) : input_buffer_(4096), session_(NULL), remote_address_() +RealmSocket::RealmSocket(void) : input_buffer_(4096), session_(NULL), _remoteAddress() { reference_counting_policy().value(ACE_Event_Handler::Reference_Counting_Policy::ENABLED); @@ -63,7 +63,8 @@ int RealmSocket::open(void * arg) return -1; } - remote_address_ = addr.get_host_addr(); + _remoteAddress = addr.get_host_addr(); + _remotePort = addr.get_port_number(); // Register with ACE Reactor if (Base::open(arg) == -1) @@ -89,9 +90,14 @@ int RealmSocket::close(int) return 0; } -const std::string& RealmSocket::get_remote_address(void) const +const std::string& RealmSocket::getRemoteAddress(void) const { - return remote_address_; + return _remoteAddress; +} + +const uint16 RealmSocket::getRemotePort(void) const +{ + return _remotePort; } size_t RealmSocket::recv_len(void) const diff --git a/src/server/authserver/Server/RealmSocket.h b/src/server/authserver/Server/RealmSocket.h index c532f016dcb..9682b5e4559 100755 --- a/src/server/authserver/Server/RealmSocket.h +++ b/src/server/authserver/Server/RealmSocket.h @@ -52,7 +52,9 @@ public: bool send(const char *buf, size_t len); - const std::string& get_remote_address(void) const; + const std::string& getRemoteAddress(void) const; + + const uint16 getRemotePort(void) const; virtual int open(void *); @@ -70,7 +72,8 @@ private: ACE_Message_Block input_buffer_; Session* session_; - std::string remote_address_; + std::string _remoteAddress; + uint16 _remotePort; }; #endif /* __REALMSOCKET_H__ */ -- cgit v1.2.3 From 126d3c8339a220de2c29bfd74de10b637470069d Mon Sep 17 00:00:00 2001 From: Discover- Date: Tue, 24 Jan 2012 21:23:05 +0100 Subject: Scripts/Spells: Script spell Refocus --- .../2012_01_24_00_world_spell_script_names.sql | 4 ++ src/server/scripts/Spells/spell_item.cpp | 46 ++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 sql/updates/world/2012_01_24_00_world_spell_script_names.sql (limited to 'src') diff --git a/sql/updates/world/2012_01_24_00_world_spell_script_names.sql b/sql/updates/world/2012_01_24_00_world_spell_script_names.sql new file mode 100644 index 00000000000..3bf6ddd71ae --- /dev/null +++ b/sql/updates/world/2012_01_24_00_world_spell_script_names.sql @@ -0,0 +1,4 @@ +-- Scriptname for Refocus spell +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_item_refocus'; +INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES +(24531,'spell_item_refocus'); \ No newline at end of file diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp index 5a0ffbd2c90..b40879d500e 100644 --- a/src/server/scripts/Spells/spell_item.cpp +++ b/src/server/scripts/Spells/spell_item.cpp @@ -1128,6 +1128,51 @@ class spell_magic_eater_food : public SpellScriptLoader } }; +enum Refocus +{ + SPELL_AIMED_SHOT = 19434, + SPELL_MULTISHOT = 2643, + SPELL_VOLLEY = 42243, +}; + +class spell_item_refocus : public SpellScriptLoader +{ + public: + spell_item_refocus() : SpellScriptLoader("spell_item_refocus") { } + + class spell_item_refocus_SpellScript : public SpellScript + { + PrepareSpellScript(spell_item_refocus_SpellScript); + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + Player* caster = GetCaster()->ToPlayer(); + + if (!caster || caster->getClass() != CLASS_HUNTER) + return; + + if (caster->HasSpellCooldown(SPELL_AIMED_SHOT)) + caster->RemoveSpellCooldown(SPELL_AIMED_SHOT, true); + + if (caster->HasSpellCooldown(SPELL_MULTISHOT)) + caster->RemoveSpellCooldown(SPELL_MULTISHOT, true); + + if (caster->HasSpellCooldown(SPELL_VOLLEY)) + caster->RemoveSpellCooldown(SPELL_VOLLEY, true); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_item_refocus_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_item_refocus_SpellScript(); + } +}; + void AddSC_item_spell_scripts() { // 23074 Arcanite Dragonling @@ -1160,4 +1205,5 @@ void AddSC_item_spell_scripts() new spell_item_ashbringer(); new spell_magic_eater_food(); + new spell_item_refocus(); } -- cgit v1.2.3 From 79c2390f8157108d474c2b893535bd44bfed5ab9 Mon Sep 17 00:00:00 2001 From: Bootz Date: Wed, 25 Jan 2012 00:39:37 -0600 Subject: Scripts/EasterKingdoms: Blackwing Lair * code-style cleanup * Fixed copyright header * Fixed defines in enums todo: make the necessary changes for script_text-> Creature_texts. --- .../BlackwingLair/boss_broodlord_lashlayer.cpp | 32 ++++---- .../BlackwingLair/boss_chromaggus.cpp | 9 +-- .../EasternKingdoms/BlackwingLair/boss_ebonroc.cpp | 5 +- .../EasternKingdoms/BlackwingLair/boss_firemaw.cpp | 5 +- .../BlackwingLair/boss_flamegor.cpp | 19 +++-- .../BlackwingLair/boss_nefarian.cpp | 93 ++++++++++++---------- .../BlackwingLair/boss_razorgore.cpp | 27 ++++--- .../BlackwingLair/boss_vaelastrasz.cpp | 73 +++++++++-------- .../BlackwingLair/boss_victor_nefarius.cpp | 82 ++++++++++--------- .../BlackwingLair/instance_blackwing_lair.cpp | 3 +- 10 files changed, 187 insertions(+), 161 deletions(-) (limited to 'src') diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp index a2e41f1af70..4cac1a941af 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2006-2009 ScriptDev2 + * Copyright (C) 2006-2012 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -24,14 +24,19 @@ SDCategory: Blackwing Lair EndScriptData */ #include "ScriptPCH.h" +enum Say +{ + SAY_AGGRO = -1469000, + SAY_LEASH = -1469001 +}; -#define SAY_AGGRO -1469000 -#define SAY_LEASH -1469001 - -#define SPELL_CLEAVE 26350 -#define SPELL_BLASTWAVE 23331 -#define SPELL_MORTALSTRIKE 24573 -#define SPELL_KNOCKBACK 25778 +enum Spells +{ + SPELL_CLEAVE = 26350, + SPELL_BLASTWAVE = 23331, + SPELL_MORTALSTRIKE = 24573, + SPELL_KNOCKBACK = 25778 +}; class boss_broodlord : public CreatureScript { @@ -45,7 +50,7 @@ public: struct boss_broodlordAI : public ScriptedAI { - boss_broodlordAI(Creature* c) : ScriptedAI(c) {} + boss_broodlordAI(Creature* creature) : ScriptedAI(creature) {} uint32 Cleave_Timer; uint32 BlastWave_Timer; @@ -54,10 +59,10 @@ public: void Reset() { - Cleave_Timer = 8000; //These times are probably wrong - BlastWave_Timer = 12000; - MortalStrike_Timer = 20000; - KnockBack_Timer = 30000; + Cleave_Timer = 8000; // These times are probably wrong + BlastWave_Timer = 12000; + MortalStrike_Timer = 20000; + KnockBack_Timer = 30000; } void EnterCombat(Unit* /*who*/) @@ -108,7 +113,6 @@ public: DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_broodlord() diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_chromaggus.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_chromaggus.cpp index 50bda73cfc6..a60ff0a13e0 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_chromaggus.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_chromaggus.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2006-2009 ScriptDev2 + * Copyright (C) 2006-2012 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -71,7 +71,7 @@ public: struct boss_chromaggusAI : public ScriptedAI { - boss_chromaggusAI(Creature* c) : ScriptedAI(c) + boss_chromaggusAI(Creature* creature) : ScriptedAI(creature) { //Select the 2 breaths that we are going to use until despawned //5 possiblities for the first breath, 4 for the second, 20 total possiblites @@ -197,9 +197,7 @@ public: Enraged = false; } - void EnterCombat(Unit* /*who*/) - { - } + void EnterCombat(Unit* /*who*/) {} void UpdateAI(const uint32 diff) { @@ -297,7 +295,6 @@ public: DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_chromaggus() diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_ebonroc.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_ebonroc.cpp index 09dd0138db8..6f7f62d666d 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_ebonroc.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_ebonroc.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2006-2009 ScriptDev2 + * Copyright (C) 2006-2012 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -42,7 +42,7 @@ public: struct boss_ebonrocAI : public ScriptedAI { - boss_ebonrocAI(Creature* c) : ScriptedAI(c) {} + boss_ebonrocAI(Creature* creature) : ScriptedAI(creature) {} uint32 ShadowFlame_Timer; uint32 WingBuffet_Timer; @@ -100,7 +100,6 @@ public: DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_ebonroc() diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp index 133d61422b2..370b52d927c 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2006-2009 ScriptDev2 + * Copyright (C) 2006-2012 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -41,7 +41,7 @@ public: struct boss_firemawAI : public ScriptedAI { - boss_firemawAI(Creature* c) : ScriptedAI(c) {} + boss_firemawAI(Creature* creature) : ScriptedAI(creature) {} uint32 ShadowFlame_Timer; uint32 WingBuffet_Timer; @@ -91,7 +91,6 @@ public: DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_firemaw() diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp index b71249dc3a3..5be8950f368 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2006-2009 ScriptDev2 + * Copyright (C) 2006-2012 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -25,11 +25,17 @@ EndScriptData */ #include "ScriptPCH.h" -#define EMOTE_FRENZY -1469031 +enum Emotes +{ + EMOTE_FRENZY = -1469031 +}; -#define SPELL_SHADOWFLAME 22539 -#define SPELL_WINGBUFFET 23339 -#define SPELL_FRENZY 23342 //This spell periodically triggers fire nova +enum Spells +{ + SPELL_SHADOWFLAME = 22539, + SPELL_WINGBUFFET = 23339, + SPELL_FRENZY = 23342 //This spell periodically triggers fire nova +}; class boss_flamegor : public CreatureScript { @@ -43,7 +49,7 @@ public: struct boss_flamegorAI : public ScriptedAI { - boss_flamegorAI(Creature* c) : ScriptedAI(c) {} + boss_flamegorAI(Creature* creature) : ScriptedAI(creature) {} uint32 ShadowFlame_Timer; uint32 WingBuffet_Timer; @@ -94,7 +100,6 @@ public: DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_flamegor() diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_nefarian.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_nefarian.cpp index 506189697fe..522b4c28e34 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_nefarian.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_nefarian.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2006-2009 ScriptDev2 + * Copyright (C) 2006-2012 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -25,40 +25,46 @@ EndScriptData */ #include "ScriptPCH.h" -#define SAY_AGGRO -1469007 -#define SAY_XHEALTH -1469008 -#define SAY_SHADOWFLAME -1469009 -#define SAY_RAISE_SKELETONS -1469010 -#define SAY_SLAY -1469011 -#define SAY_DEATH -1469012 - -#define SAY_MAGE -1469013 -#define SAY_WARRIOR -1469014 -#define SAY_DRUID -1469015 -#define SAY_PRIEST -1469016 -#define SAY_PALADIN -1469017 -#define SAY_SHAMAN -1469018 -#define SAY_WARLOCK -1469019 -#define SAY_HUNTER -1469020 -#define SAY_ROGUE -1469021 - -#define SPELL_SHADOWFLAME_INITIAL 22972 -#define SPELL_SHADOWFLAME 22539 -#define SPELL_BELLOWINGROAR 22686 -#define SPELL_VEILOFSHADOW 7068 -#define SPELL_CLEAVE 20691 -#define SPELL_TAILLASH 23364 -#define SPELL_BONECONTRUST 23363 //23362, 23361 - -#define SPELL_MAGE 23410 //wild magic -#define SPELL_WARRIOR 23397 //beserk -#define SPELL_DRUID 23398 // cat form -#define SPELL_PRIEST 23401 // corrupted healing -#define SPELL_PALADIN 23418 //syphon blessing -#define SPELL_SHAMAN 23425 //totems -#define SPELL_WARLOCK 23427 //infernals -#define SPELL_HUNTER 23436 //bow broke -#define SPELL_ROGUE 23414 //Paralise +enum Say +{ + SAY_AGGRO = -1469007, + SAY_XHEALTH = -1469008, + SAY_SHADOWFLAME = -1469009, + SAY_RAISE_SKELETONS = -1469010, + SAY_SLAY = -1469011, + SAY_DEATH = -1469012, + + SAY_MAGE = -1469013, + SAY_WARRIOR = -1469014, + SAY_DRUID = -1469015, + SAY_PRIEST = -1469016, + SAY_PALADIN = -1469017, + SAY_SHAMAN = -1469018, + SAY_WARLOCK = -1469019, + SAY_HUNTER = -1469020, + SAY_ROGUE = -1469021 +}; + +enum Spells +{ + SPELL_SHADOWFLAME_INITIAL = 22972, + SPELL_SHADOWFLAME = 22539, + SPELL_BELLOWINGROAR = 22686, + SPELL_VEILOFSHADOW = 7068, + SPELL_CLEAVE = 20691, + SPELL_TAILLASH = 23364, + SPELL_BONECONTRUST = 23363, //23362, 23361 + + SPELL_MAGE = 23410, //wild magic + SPELL_WARRIOR = 23397, //beserk + SPELL_DRUID = 23398, // cat form + SPELL_PRIEST = 23401, // corrupted healing + SPELL_PALADIN = 23418, //syphon blessing + SPELL_SHAMAN = 23425, //totems + SPELL_WARLOCK = 23427, //infernals + SPELL_HUNTER = 23436, //bow broke + SPELL_ROGUE = 23414 //Paralise +}; class boss_nefarian : public CreatureScript { @@ -72,7 +78,7 @@ public: struct boss_nefarianAI : public ScriptedAI { - boss_nefarianAI(Creature* c) : ScriptedAI(c) {} + boss_nefarianAI(Creature* creature) : ScriptedAI(creature) {} uint32 ShadowFlame_Timer; uint32 BellowingRoar_Timer; @@ -86,15 +92,15 @@ public: void Reset() { - ShadowFlame_Timer = 12000; //These times are probably wrong - BellowingRoar_Timer = 30000; - VeilOfShadow_Timer = 15000; - Cleave_Timer = 7000; - TailLash_Timer = 10000; - ClassCall_Timer = 35000; //35-40 seconds + ShadowFlame_Timer = 12000; // These times are probably wrong + BellowingRoar_Timer = 30000; + VeilOfShadow_Timer = 15000; + Cleave_Timer = 7000; + TailLash_Timer = 10000; + ClassCall_Timer = 35000; // 35-40 seconds Phase3 = false; - DespawnTimer = 5000; + DespawnTimer = 5000; } void KilledUnit(Unit* Victim) @@ -227,7 +233,6 @@ public: DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_nefarian() diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_razorgore.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_razorgore.cpp index b643139a71e..ec13ea31615 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_razorgore.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_razorgore.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2006-2009 ScriptDev2 + * Copyright (C) 2006-2012 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -27,15 +27,21 @@ EndScriptData */ //Razorgore Phase 2 Script -#define SAY_EGGS_BROKEN1 -1469022 -#define SAY_EGGS_BROKEN2 -1469023 -#define SAY_EGGS_BROKEN3 -1469024 -#define SAY_DEATH -1469025 +enum Say +{ + SAY_EGGS_BROKEN1 = -1469022, + SAY_EGGS_BROKEN2 = -1469023, + SAY_EGGS_BROKEN3 = -1469024, + SAY_DEATH = -1469025 +}; -#define SPELL_CLEAVE 22540 -#define SPELL_WARSTOMP 24375 -#define SPELL_FIREBALLVOLLEY 22425 -#define SPELL_CONFLAGRATION 23023 +enum Spells +{ + SPELL_CLEAVE = 22540, + SPELL_WARSTOMP = 24375, + SPELL_FIREBALLVOLLEY = 22425, + SPELL_CONFLAGRATION = 23023 +}; class boss_razorgore : public CreatureScript { @@ -49,7 +55,7 @@ public: struct boss_razorgoreAI : public ScriptedAI { - boss_razorgoreAI(Creature* c) : ScriptedAI(c) {} + boss_razorgoreAI(Creature* creature) : ScriptedAI(creature) {} uint32 Cleave_Timer; uint32 WarStomp_Timer; @@ -120,7 +126,6 @@ public: DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_razorgore() diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_vaelastrasz.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_vaelastrasz.cpp index 4961d253a26..62dd1edbef2 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_vaelastrasz.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_vaelastrasz.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2006-2009 ScriptDev2 + * Copyright (C) 2006-2012 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -25,40 +25,46 @@ EndScriptData */ #include "ScriptPCH.h" -#define SAY_LINE1 -1469026 -#define SAY_LINE2 -1469027 -#define SAY_LINE3 -1469028 -#define SAY_HALFLIFE -1469029 -#define SAY_KILLTARGET -1469030 +enum Says +{ + SAY_LINE1 = -1469026, + SAY_LINE2 = -1469027, + SAY_LINE3 = -1469028, + SAY_HALFLIFE = -1469029, + SAY_KILLTARGET = -1469030 +}; #define GOSSIP_ITEM "Start Event " -#define SPELL_ESSENCEOFTHERED 23513 -#define SPELL_FLAMEBREATH 23461 -#define SPELL_FIRENOVA 23462 -#define SPELL_TAILSWIPE 15847 -#define SPELL_BURNINGADRENALINE 23620 -#define SPELL_CLEAVE 20684 //Chain cleave is most likely named something different and contains a dummy effect +enum Spells +{ + SPELL_ESSENCEOFTHERED = 23513, + SPELL_FLAMEBREATH = 23461, + SPELL_FIRENOVA = 23462, + SPELL_TAILSWIPE = 15847, + SPELL_BURNINGADRENALINE = 23620, + SPELL_CLEAVE = 20684 //Chain cleave is most likely named something different and contains a dummy effect +}; class boss_vaelastrasz : public CreatureScript { public: boss_vaelastrasz() : CreatureScript("boss_vaelastrasz") { } - void SendDefaultMenu(Player* player, Creature* creature, uint32 uiAction) + void SendDefaultMenu(Player* player, Creature* creature, uint32 Action) { - if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) //Fight time + if (Action == GOSSIP_ACTION_INFO_DEF + 1) //Fight time { player->CLOSE_GOSSIP_MENU(); CAST_AI(boss_vaelastrasz::boss_vaelAI, creature->AI())->BeginSpeech(player); } } - bool OnGossipSelect(Player* player, Creature* creature, uint32 uiSender, uint32 uiAction) + bool OnGossipSelect(Player* player, Creature* creature, uint32 Sender, uint32 Action) { player->PlayerTalkClass->ClearMenus(); - if (uiSender == GOSSIP_SENDER_MAIN) - SendDefaultMenu(player, creature, uiAction); + if (Sender == GOSSIP_SENDER_MAIN) + SendDefaultMenu(player, creature, Action); return true; } @@ -81,11 +87,11 @@ public: struct boss_vaelAI : public ScriptedAI { - boss_vaelAI(Creature* c) : ScriptedAI(c) + boss_vaelAI(Creature* creature) : ScriptedAI(creature) { - c->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - c->setFaction(35); - c->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + creature->setFaction(35); + creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } uint64 PlayerGUID; @@ -102,17 +108,17 @@ public: void Reset() { - PlayerGUID = 0; - SpeechTimer = 0; - SpeechNum = 0; - Cleave_Timer = 8000; //These times are probably wrong - FlameBreath_Timer = 11000; - BurningAdrenalineCaster_Timer = 15000; - BurningAdrenalineTank_Timer = 45000; - FireNova_Timer = 5000; - TailSwipe_Timer = 20000; - HasYelled = false; - DoingSpeech = false; + PlayerGUID = 0; + SpeechTimer = 0; + SpeechNum = 0; + Cleave_Timer = 8000; //These times are probably wrong + FlameBreath_Timer = 11000; + BurningAdrenalineCaster_Timer = 15000; + BurningAdrenalineTank_Timer = 45000; + FireNova_Timer = 5000; + TailSwipe_Timer = 20000; + HasYelled = false; + DoingSpeech = false; } void BeginSpeech(Unit* target) @@ -213,7 +219,7 @@ public: Unit* target = NULL; uint8 i = 0; - while (i < 3) // max 3 tries to get a random target with power_mana + while (i < 3) // max 3 tries to get a random target with power_mana { ++i; target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100, true); //not aggro leader @@ -258,7 +264,6 @@ public: DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_vael() diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_victor_nefarius.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_victor_nefarius.cpp index 89b34aada66..15403494cc6 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_victor_nefarius.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_victor_nefarius.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2006-2009 ScriptDev2 + * Copyright (C) 2006-2012 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -25,40 +25,49 @@ EndScriptData */ #include "ScriptPCH.h" -#define SAY_GAMESBEGIN_1 -1469004 -#define SAY_GAMESBEGIN_2 -1469005 -#define SAY_VAEL_INTRO -1469006 //when he corrupts Vaelastrasz +enum Says +{ + SAY_GAMESBEGIN_1 = -1469004, + SAY_GAMESBEGIN_2 = -1469005, + SAY_VAEL_INTRO = -1469006 //when he corrupts Vaelastrasz +}; #define GOSSIP_ITEM_1 "I've made no mistakes." #define GOSSIP_ITEM_2 "You have lost your mind, Nefarius. You speak in riddles." #define GOSSIP_ITEM_3 "Please do." -#define CREATURE_BRONZE_DRAKANOID 14263 -#define CREATURE_BLUE_DRAKANOID 14261 -#define CREATURE_RED_DRAKANOID 14264 -#define CREATURE_GREEN_DRAKANOID 14262 -#define CREATURE_BLACK_DRAKANOID 14265 - -#define CREATURE_CHROMATIC_DRAKANOID 14302 -#define CREATURE_NEFARIAN 11583 +enum Creatures +{ + CREATURE_BRONZE_DRAKANOID = 14263, + CREATURE_BLUE_DRAKANOID = 14261, + CREATURE_RED_DRAKANOID = 14264, + CREATURE_GREEN_DRAKANOID = 14262, + CREATURE_BLACK_DRAKANOID = 14265, + + CREATURE_CHROMATIC_DRAKANOID = 14302, + CREATURE_NEFARIAN = 11583 +}; -#define ADD_X1 -7591.151855f -#define ADD_X2 -7514.598633f -#define ADD_Y1 -1204.051880f -#define ADD_Y2 -1150.448853f -#define ADD_Z1 476.800476f -#define ADD_Z2 476.796570f +#define ADD_X1 -7591.151855f +#define ADD_X2 -7514.598633f +#define ADD_Y1 -1204.051880f +#define ADD_Y2 -1150.448853f +#define ADD_Z1 476.800476f +#define ADD_Z2 476.796570f -#define NEF_X -7445 -#define NEF_Y -1332 -#define NEF_Z 536 +#define NEF_X -7445 +#define NEF_Y -1332 +#define NEF_Z 536 -#define HIDE_X -7592 -#define HIDE_Y -1264 -#define HIDE_Z 481 +#define HIDE_X -7592 +#define HIDE_Y -1264 +#define HIDE_Z 481 -#define SPELL_SHADOWBOLT 21077 -#define SPELL_FEAR 26070 +enum Spells +{ + SPELL_SHADOWBOLT = 21077, + SPELL_FEAR = 26070 +}; //This script is complicated //Instead of morphing Victor Nefarius we will have him control phase 1 @@ -74,10 +83,10 @@ class boss_victor_nefarius : public CreatureScript public: boss_victor_nefarius() : CreatureScript("boss_victor_nefarius") { } - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*uiSender*/, uint32 uiAction) + bool OnGossipSelect(Player* player, Creature* creature, uint32 /*Sender*/, uint32 Action) { player->PlayerTalkClass->ClearMenus(); - switch (uiAction) + switch (Action) { case GOSSIP_ACTION_INFO_DEF+1: player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); @@ -110,7 +119,7 @@ public: struct boss_victor_nefariusAI : public ScriptedAI { - boss_victor_nefariusAI(Creature* c) : ScriptedAI(c) + boss_victor_nefariusAI(Creature* creature) : ScriptedAI(creature) { NefarianGUID = 0; switch (urand(0, 19)) @@ -211,13 +220,13 @@ public: void Reset() { - SpawnedAdds = 0; - AddSpawnTimer = 10000; - ShadowBoltTimer = 5000; - FearTimer = 8000; - ResetTimer = 900000; //On official it takes him 15 minutes(900 seconds) to reset. We are only doing 1 minute to make testing easier - NefarianGUID = 0; - NefCheckTime = 2000; + SpawnedAdds = 0; + AddSpawnTimer = 10000; + ShadowBoltTimer = 5000; + FearTimer = 8000; + ResetTimer = 900000; //On official it takes him 15 minutes(900 seconds) to reset. We are only doing 1 minute to make testing easier + NefarianGUID = 0; + NefCheckTime = 2000; me->SetUInt32Value(UNIT_NPC_FLAGS, 1); me->setFaction(35); @@ -378,7 +387,6 @@ public: } } }; - }; void AddSC_boss_victor_nefarius() diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/instance_blackwing_lair.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/instance_blackwing_lair.cpp index 54c0855512f..13dd05da450 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/instance_blackwing_lair.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/instance_blackwing_lair.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2006-2009 ScriptDev2 + * Copyright (C) 2006-2012 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -24,4 +24,3 @@ SDCategory: Blackwing Lair EndScriptData */ #include "ScriptPCH.h" - -- cgit v1.2.3 From e0930b1a37552d9a48a83e33cdd6d8515d1378f8 Mon Sep 17 00:00:00 2001 From: Bootz Date: Wed, 25 Jan 2012 01:13:07 -0600 Subject: Scripts/EasternKingdoms: Blackwing Lair * Adjusted copyright headers back to '09 these need updated b4 can use 2012 --- .../scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp | 2 +- src/server/scripts/EasternKingdoms/BlackwingLair/boss_chromaggus.cpp | 2 +- src/server/scripts/EasternKingdoms/BlackwingLair/boss_ebonroc.cpp | 2 +- src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp | 2 +- src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp | 2 +- src/server/scripts/EasternKingdoms/BlackwingLair/boss_nefarian.cpp | 2 +- src/server/scripts/EasternKingdoms/BlackwingLair/boss_razorgore.cpp | 2 +- src/server/scripts/EasternKingdoms/BlackwingLair/boss_vaelastrasz.cpp | 2 +- .../scripts/EasternKingdoms/BlackwingLair/boss_victor_nefarius.cpp | 2 +- .../scripts/EasternKingdoms/BlackwingLair/instance_blackwing_lair.cpp | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp index 4cac1a941af..7a4ba5777d1 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2006-2012 ScriptDev2 + * Copyright (C) 2006-2009 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_chromaggus.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_chromaggus.cpp index a60ff0a13e0..818dcace078 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_chromaggus.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_chromaggus.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2006-2012 ScriptDev2 + * Copyright (C) 2006-2009 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_ebonroc.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_ebonroc.cpp index 6f7f62d666d..c91e0fb3303 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_ebonroc.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_ebonroc.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2006-2012 ScriptDev2 + * Copyright (C) 2006-2009 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp index 370b52d927c..c2a2350c0e8 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2006-2012 ScriptDev2 + * Copyright (C) 2006-2009 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp index 5be8950f368..41bcb6c5427 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2006-2012 ScriptDev2 + * Copyright (C) 2006-2009 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_nefarian.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_nefarian.cpp index 522b4c28e34..c4e0d6ea715 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_nefarian.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_nefarian.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2006-2012 ScriptDev2 + * Copyright (C) 2006-2009 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_razorgore.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_razorgore.cpp index ec13ea31615..a4fb4ad22a3 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_razorgore.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_razorgore.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2006-2012 ScriptDev2 + * Copyright (C) 2006-2009 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_vaelastrasz.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_vaelastrasz.cpp index 62dd1edbef2..4a72bd0ca38 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_vaelastrasz.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_vaelastrasz.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2006-2012 ScriptDev2 + * Copyright (C) 2006-2009 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_victor_nefarius.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_victor_nefarius.cpp index 15403494cc6..5222270df1a 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_victor_nefarius.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_victor_nefarius.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2006-2012 ScriptDev2 + * Copyright (C) 2006-2009 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/instance_blackwing_lair.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/instance_blackwing_lair.cpp index 13dd05da450..8a9b930aa09 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/instance_blackwing_lair.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/instance_blackwing_lair.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2006-2012 ScriptDev2 + * Copyright (C) 2006-2009 ScriptDev2 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the -- cgit v1.2.3 From 2db052b109fad1a2c8f6561ee04f83fe147c474c Mon Sep 17 00:00:00 2001 From: Bootz Date: Thu, 26 Jan 2012 02:21:15 -0600 Subject: Scripts/EasternKingdoms: ScareltMonastery * Script Standardizations done, - Removed SD2 Hieroglyphics. - Removed Hungarian Notations. - Fixed Enums in Defines. --- .../ScarletMonastery/boss_arcanist_doan.cpp | 3 +- .../ScarletMonastery/boss_azshir_the_sleepless.cpp | 17 +- .../ScarletMonastery/boss_bloodmage_thalnos.cpp | 3 +- .../ScarletMonastery/boss_headless_horseman.cpp | 128 +++++++------- .../ScarletMonastery/boss_herod.cpp | 42 +++-- .../boss_high_inquisitor_fairbanks.cpp | 7 +- .../ScarletMonastery/boss_houndmaster_loksey.cpp | 3 +- .../ScarletMonastery/boss_interrogator_vishas.cpp | 12 +- .../boss_mograine_and_whitemane.cpp | 183 +++++++++++---------- .../ScarletMonastery/boss_scorn.cpp | 18 +- .../instance_scarlet_monastery.cpp | 24 +-- .../ScarletMonastery/scarlet_monastery.h | 19 ++- 12 files changed, 236 insertions(+), 223 deletions(-) (limited to 'src') diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp index b3102f2dde7..5054472c671 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp @@ -49,7 +49,7 @@ public: struct boss_arcanist_doanAI : public ScriptedAI { - boss_arcanist_doanAI(Creature* c) : ScriptedAI(c) {} + boss_arcanist_doanAI(Creature* creature) : ScriptedAI(creature) {} uint32 Polymorph_Timer; uint32 AoESilence_Timer; @@ -124,7 +124,6 @@ public: DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_arcanist_doan() diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp index 36beecb2029..1802d828a1b 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp @@ -24,10 +24,12 @@ SDCategory: Scarlet Monastery EndScriptData */ #include "ScriptPCH.h" - -#define SPELL_CALLOFTHEGRAVE 17831 -#define SPELL_TERRIFY 7399 -#define SPELL_SOULSIPHON 7290 +enum Spells +{ + SPELL_CALLOFTHEGRAVE = 17831, + SPELL_TERRIFY = 7399, + SPELL_SOULSIPHON = 7290 +}; class boss_azshir_the_sleepless : public CreatureScript { @@ -41,7 +43,7 @@ public: struct boss_azshir_the_sleeplessAI : public ScriptedAI { - boss_azshir_the_sleeplessAI(Creature* c) : ScriptedAI(c) {} + boss_azshir_the_sleeplessAI(Creature* creature) : ScriptedAI(creature) {} uint32 SoulSiphon_Timer; uint32 CallOftheGrave_Timer; @@ -54,9 +56,7 @@ public: Terrify_Timer = 20000; } - void EnterCombat(Unit* /*who*/) - { - } + void EnterCombat(Unit* /*who*/) {} void UpdateAI(const uint32 diff) { @@ -93,7 +93,6 @@ public: DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_azshir_the_sleepless() diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp index 794a686a550..669d7bb16f3 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp @@ -49,7 +49,7 @@ public: struct boss_bloodmage_thalnosAI : public ScriptedAI { - boss_bloodmage_thalnosAI(Creature* c) : ScriptedAI(c) {} + boss_bloodmage_thalnosAI(Creature* creature) : ScriptedAI(creature) {} bool HpYell; uint32 FlameShock_Timer; @@ -119,7 +119,6 @@ public: DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_bloodmage_thalnos() diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp index 14b21504be5..f53779ea5da 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp @@ -28,59 +28,66 @@ EndScriptData */ #include "scarlet_monastery.h" //this texts are already used by 3975 and 3976 -#define SAY_ENTRANCE -1189001 -#define SAY_REJOINED -1189002 -#define SAY_LOST_HEAD -1189003 -#define SAY_CONFLAGRATION -1189004 -#define SAY_SPROUTING_PUMPKINS -1189005 -#define SAY_PLAYER_DEATH -1189006 -#define SAY_DEATH -1189007 +enum Says +{ + SAY_ENTRANCE = -1189001, + SAY_REJOINED = -1189002, + SAY_LOST_HEAD = -1189003, + SAY_CONFLAGRATION = -1189004, + SAY_SPROUTING_PUMPKINS = -1189005, + SAY_PLAYER_DEATH = -1189006, + SAY_DEATH = -1189007 +}; uint32 RandomLaugh[] = {11965, 11975, 11976}; - // Entryes -#define HH_MOUNTED 23682 -#define HH_UNHORSED 23800 -#define HEAD 23775 -#define PULSING_PUMPKIN 23694 -#define PUMPKIN_FIEND 23545 -#define HELPER 23686 -#define WISP_INVIS 24034 - - //Spells -#define SPELL_CLEAVE 42587 -#define SPELL_CONFLAGRATION 42380 //Phase 2, can't find real spell(Dim Fire?) -//#define SPELL_CONFL_SPEED 22587 //8% increase speed, value 22587 from SPELL_CONFLAGRATION mains that spell? -#define SPELL_SUMMON_PUMPKIN 42394 - -#define SPELL_WHIRLWIND 43116 -#define SPELL_IMMUNE 42556 -#define SPELL_BODY_REGEN 42403 -#define SPELL_CONFUSE 43105 - -#define SPELL_FLYING_HEAD 42399 //visual flying head -#define SPELL_HEAD 42413 //visual buff, "head" -#define SPELL_HEAD_IS_DEAD 42428 //at killing head, Phase 3 - -#define SPELL_PUMPKIN_AURA 42280 -#define SPELL_PUMPKIN_AURA_GREEN 42294 -#define SPELL_SQUASH_SOUL 42514 -#define SPELL_SPROUTING 42281 -#define SPELL_SPROUT_BODY 42285 +enum Entry +{ + HH_MOUNTED = 23682, + HH_DISMOUNTED = 23800, // unhorsed?? wtf type of engrish was that? + HEAD = 23775, + PULSING_PUMPKIN = 23694, + PUMPKIN_FIEND = 23545, + HELPER = 23686, + WISP_INVIS = 24034 +}; + +enum Spells +{ + SPELL_CLEAVE = 42587, + SPELL_CONFLAGRATION = 42380, //Phase 2, can't find real spell(Dim Fire?) + // SPELL_CONFL_SPEED = 22587, //8% increase speed, value 22587 from SPELL_CONFLAGRATION mains that spell? + SPELL_SUMMON_PUMPKIN = 42394, + + SPELL_WHIRLWIND = 43116, + SPELL_IMMUNE = 42556, + SPELL_BODY_REGEN = 42403, + SPELL_CONFUSE = 43105, + + SPELL_FLYING_HEAD = 42399, //visual flying head + SPELL_HEAD = 42413, //visual buff, "head" + SPELL_HEAD_IS_DEAD = 42428, //at killing head, Phase 3 + + SPELL_PUMPKIN_AURA = 42280, + SPELL_PUMPKIN_AURA_GREEN = 42294, + SPELL_SQUASH_SOUL = 42514, + SPELL_SPROUTING = 42281, + SPELL_SPROUT_BODY = 42285, //Effects -#define SPELL_RHYME_BIG 42909 -//#define SPELL_RHYME_SMALL 42910 -#define SPELL_HEAD_SPEAKS 43129 -#define SPELL_HEAD_LANDS 42400 -#define SPELL_BODY_FLAME 42074 -#define SPELL_HEAD_FLAME 42971 -//#define SPELL_ENRAGE_VISUAL 42438 // he uses this spell? -#define SPELL_WISP_BLUE 42821 -#define SPELL_WISP_FLIGHT_PORT 42818 -//#define SPELL_WISP_INVIS 42823 -#define SPELL_SMOKE 42355 -#define SPELL_DEATH 42566 //not correct spell + SPELL_RHYME_BIG = 42909, + // SPELL_RHYME_SMALL = 42910, + SPELL_HEAD_SPEAKS = 43129, + SPELL_HEAD_LANDS = 42400, + SPELL_BODY_FLAME = 42074, + SPELL_HEAD_FLAME = 42971, + // SPELL_ENRAGE_VISUAL = 42438, // he uses this spell? + SPELL_WISP_BLUE = 42821, + SPELL_WISP_FLIGHT_PORT = 42818, + // SPELL_WISP_INVIS = 42823, + SPELL_SMOKE = 42355, + SPELL_DEATH = 42566 //not correct spell +}; struct Locations { @@ -114,7 +121,7 @@ static Locations FlightPoint[]= static Locations Spawn[]= { - {1776.27f, 1348.74f, 19.20f}, //spawn point for pumpkin shrine mob + {1776.27f, 1348.74f, 19.20f}, //spawn point for pumpkin shrine mob {1765.28f, 1347.46f, 17.55f} //spawn point for smoke }; @@ -126,7 +133,7 @@ static const char* Text[]= "Now, know demise!" }; -#define EMOTE_LAUGHS "Headless Horseman laughs" +#define EMOTE_LAUGHS "Headless Horseman laughs" // needs assigned to db. class mob_wisp_invis : public CreatureScript { @@ -140,7 +147,7 @@ public: struct mob_wisp_invisAI : public ScriptedAI { - mob_wisp_invisAI(Creature* c) : ScriptedAI(c) + mob_wisp_invisAI(Creature* creature) : ScriptedAI(creature) { Creaturetype = delay = spell = spell2 = 0; } @@ -149,8 +156,8 @@ public: uint32 delay; uint32 spell; uint32 spell2; - void Reset(){} - void EnterCombat(Unit* /*who*/){} + void Reset() {} + void EnterCombat(Unit* /*who*/) {} void SetType(uint32 _type) { switch (Creaturetype = _type) @@ -205,7 +212,6 @@ public: } } }; - }; class mob_head : public CreatureScript @@ -220,7 +226,7 @@ public: struct mob_headAI : public ScriptedAI { - mob_headAI(Creature* c) : ScriptedAI(c) {} + mob_headAI(Creature* creature) : ScriptedAI(creature) {} uint64 bodyGUID; @@ -344,7 +350,6 @@ public: } } }; - }; class boss_headless_horseman : public CreatureScript @@ -359,9 +364,9 @@ public: struct boss_headless_horsemanAI : public ScriptedAI { - boss_headless_horsemanAI(Creature* c) : ScriptedAI(c) + boss_headless_horsemanAI(Creature* creature) : ScriptedAI(creature) { - instance = c->GetInstanceScript(); + instance = creature->GetInstanceScript(); } InstanceScript* instance; @@ -731,7 +736,6 @@ public: } } }; - }; class mob_pulsing_pumpkin : public CreatureScript @@ -746,7 +750,7 @@ public: struct mob_pulsing_pumpkinAI : public ScriptedAI { - mob_pulsing_pumpkinAI(Creature* c) : ScriptedAI(c) {} + mob_pulsing_pumpkinAI(Creature* creature) : ScriptedAI(creature) {} bool sprouted; uint64 debuffGUID; @@ -771,7 +775,7 @@ public: me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); } - void EnterCombat(Unit* /*who*/){} + void EnterCombat(Unit* /*who*/) {} void SpellHit(Unit* /*caster*/, const SpellInfo* spell) { @@ -813,7 +817,6 @@ public: DoMeleeAttackIfReady(); } }; - }; class go_loosely_turned_soil : public GameObjectScript @@ -846,7 +849,6 @@ public: //} return true; } - }; void mob_head::mob_headAI::Disappear() diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp index d99aabd60e8..e87581a3bbd 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp @@ -26,19 +26,31 @@ EndScriptData */ #include "ScriptPCH.h" #include "ScriptedEscortAI.h" -#define SAY_AGGRO -1189000 -#define SAY_WHIRLWIND -1189001 -#define SAY_ENRAGE -1189002 -#define SAY_KILL -1189003 -#define EMOTE_ENRAGE -1189004 +enum Says +{ + SAY_AGGRO = -1189000, + SAY_WHIRLWIND = -1189001, + SAY_ENRAGE = -1189002, + SAY_KILL = -1189003 +}; +enum Emotes +{ + EMOTE_ENRAGE = -1189004 +}; -#define SPELL_RUSHINGCHARGE 8260 -#define SPELL_CLEAVE 15496 -#define SPELL_WHIRLWIND 8989 -#define SPELL_FRENZY 8269 +enum Spells +{ + SPELL_RUSHINGCHARGE = 8260, + SPELL_CLEAVE = 15496, + SPELL_WHIRLWIND = 8989, + SPELL_FRENZY = 8269 +}; -#define ENTRY_SCARLET_TRAINEE 6575 -#define ENTRY_SCARLET_MYRMIDON 4295 +enum Entry +{ + ENTRY_SCARLET_TRAINEE = 6575, + ENTRY_SCARLET_MYRMIDON = 4295 +}; class boss_herod : public CreatureScript { @@ -52,7 +64,7 @@ public: struct boss_herodAI : public ScriptedAI { - boss_herodAI(Creature* c) : ScriptedAI(c) {} + boss_herodAI(Creature* creature) : ScriptedAI(creature) {} bool Enrage; @@ -115,7 +127,6 @@ public: DoMeleeAttackIfReady(); } }; - }; class mob_scarlet_trainee : public CreatureScript @@ -130,7 +141,7 @@ public: struct mob_scarlet_traineeAI : public npc_escortAI { - mob_scarlet_traineeAI(Creature* c) : npc_escortAI(c) + mob_scarlet_traineeAI(Creature* creature) : npc_escortAI(creature) { Start_Timer = urand(1000, 6000); } @@ -138,7 +149,7 @@ public: uint32 Start_Timer; void Reset() {} - void WaypointReached(uint32 /*uiPoint*/) {} + void WaypointReached(uint32 /*point*/) {} void EnterCombat(Unit* /*who*/) {} void UpdateAI(const uint32 diff) @@ -155,7 +166,6 @@ public: npc_escortAI::UpdateAI(diff); } }; - }; void AddSC_boss_herod() diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp index 327c84327c5..22624fd6066 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp @@ -47,7 +47,7 @@ public: struct boss_high_inquisitor_fairbanksAI : public ScriptedAI { - boss_high_inquisitor_fairbanksAI(Creature* c) : ScriptedAI(c) {} + boss_high_inquisitor_fairbanksAI(Creature* creature) : ScriptedAI(creature) {} uint32 CurseOfBlood_Timer; uint32 DispelMagic_Timer; @@ -68,9 +68,7 @@ public: PowerWordShield = false; } - void EnterCombat(Unit* /*who*/) - { - } + void EnterCombat(Unit* /*who*/) {} void UpdateAI(const uint32 diff) { @@ -128,7 +126,6 @@ public: DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_high_inquisitor_fairbanks() diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp index b070a31d6ee..4bd3c134c61 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp @@ -44,7 +44,7 @@ public: struct boss_houndmaster_lokseyAI : public ScriptedAI { - boss_houndmaster_lokseyAI(Creature* c) : ScriptedAI(c) {} + boss_houndmaster_lokseyAI(Creature* creature) : ScriptedAI(creature) {} uint32 BloodLust_Timer; @@ -72,7 +72,6 @@ public: DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_houndmaster_loksey() diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp index 28c9b7ea434..a5c1f48a11b 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp @@ -26,15 +26,18 @@ EndScriptData */ #include "ScriptPCH.h" #include "scarlet_monastery.h" -enum eEnums +enum Says { SAY_AGGRO = -1189011, SAY_HEALTH1 = -1189012, SAY_HEALTH2 = -1189013, SAY_KILL = -1189014, - SAY_TRIGGER_VORREL = -1189015, + SAY_TRIGGER_VORREL = -1189015 +}; - SPELL_SHADOWWORDPAIN = 2767, +enum Spells +{ + SPELL_SHADOWWORDPAIN = 2767 }; class boss_interrogator_vishas : public CreatureScript @@ -49,7 +52,7 @@ public: struct boss_interrogator_vishasAI : public ScriptedAI { - boss_interrogator_vishasAI(Creature* c) : ScriptedAI(c) + boss_interrogator_vishasAI(Creature* creature) : ScriptedAI(creature) { instance = me->GetInstanceScript(); } @@ -113,7 +116,6 @@ public: DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_interrogator_vishas() diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp index 7e2d3cb6788..87bee1ca6ad 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp @@ -26,7 +26,7 @@ EndScriptData */ #include "ScriptPCH.h" #include "scarlet_monastery.h" -enum eEnums +enum Says { //Mograine says SAY_MO_AGGRO = -1189005, @@ -37,7 +37,10 @@ enum eEnums SAY_WH_INTRO = -1189008, SAY_WH_KILL = -1189009, SAY_WH_RESSURECT = -1189010, +}; +enum Spells +{ //Mograine Spells SPELL_CRUSADERSTRIKE = 14518, SPELL_HAMMEROFJUSTICE = 5589, @@ -67,43 +70,43 @@ public: { boss_scarlet_commander_mograineAI(Creature* creature) : ScriptedAI(creature) { - m_instance = creature->GetInstanceScript(); + instance = creature->GetInstanceScript(); } - InstanceScript* m_instance; + InstanceScript* instance; - uint32 m_uiCrusaderStrike_Timer; - uint32 m_uiHammerOfJustice_Timer; + uint32 CrusaderStrike_Timer; + uint32 HammerOfJustice_Timer; - bool m_bHasDied; - bool m_bHeal; - bool m_bFakeDeath; + bool _bHasDied; + bool _bHeal; + bool _bFakeDeath; void Reset() { - m_uiCrusaderStrike_Timer = 10000; - m_uiHammerOfJustice_Timer = 10000; + CrusaderStrike_Timer = 10000; + HammerOfJustice_Timer = 10000; //Incase wipe during phase that mograine fake death me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); me->SetStandState(UNIT_STAND_STATE_STAND); - if (m_instance) + if (instance) if (me->isAlive()) - m_instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, NOT_STARTED); + instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, NOT_STARTED); - m_bHasDied = false; - m_bHeal = false; - m_bFakeDeath = false; + _bHasDied = false; + _bHeal = false; + _bFakeDeath = false; } void JustReachedHome() { - if (m_instance) + if (instance) { - if (m_instance->GetData(TYPE_MOGRAINE_AND_WHITE_EVENT) != NOT_STARTED) - m_instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, FAIL); + if (instance->GetData(TYPE_MOGRAINE_AND_WHITE_EVENT) != NOT_STARTED) + instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, FAIL); } } @@ -120,18 +123,18 @@ public: DoScriptText(SAY_MO_KILL, me); } - void DamageTaken(Unit* /*pDoneBy*/, uint32 &uiDamage) + void DamageTaken(Unit* /*doneBy*/, uint32 &damage) { - if (uiDamage < me->GetHealth() || m_bHasDied || m_bFakeDeath) + if (damage < me->GetHealth() || _bHasDied || _bFakeDeath) return; - if (!m_instance) + if (!instance) return; //On first death, fake death and open door, as well as initiate whitemane if exist - if (Unit* Whitemane = Unit::GetUnit((*me), m_instance->GetData64(DATA_WHITEMANE))) + if (Unit* Whitemane = Unit::GetUnit((*me), instance->GetData64(DATA_WHITEMANE))) { - m_instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, IN_PROGRESS); + instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, IN_PROGRESS); Whitemane->GetMotionMaster()->MovePoint(1, 1163.113370f, 1398.856812f, 32.527786f); @@ -150,72 +153,71 @@ public: me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); me->SetStandState(UNIT_STAND_STATE_DEAD); - m_bHasDied = true; - m_bFakeDeath = true; + _bHasDied = true; + _bFakeDeath = true; - uiDamage = 0; + damage = 0; } } - void SpellHit(Unit* /*who*/, const SpellInfo* pSpell) + void SpellHit(Unit* /*who*/, const SpellInfo* spell) { //When hit with ressurection say text - if (pSpell->Id == SPELL_SCARLETRESURRECTION) + if (spell->Id == SPELL_SCARLETRESURRECTION) { DoScriptText(SAY_MO_RESSURECTED, me); - m_bFakeDeath = false; + _bFakeDeath = false; - if (m_instance) - m_instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, SPECIAL); + if (instance) + instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, SPECIAL); } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 diff) { if (!UpdateVictim()) return; - if (m_bHasDied && !m_bHeal && m_instance && m_instance->GetData(TYPE_MOGRAINE_AND_WHITE_EVENT) == SPECIAL) + if (_bHasDied && !_bHeal && instance && instance->GetData(TYPE_MOGRAINE_AND_WHITE_EVENT) == SPECIAL) { //On ressurection, stop fake death and heal whitemane and resume fight - if (Unit* Whitemane = Unit::GetUnit((*me), m_instance->GetData64(DATA_WHITEMANE))) + if (Unit* Whitemane = Unit::GetUnit((*me), instance->GetData64(DATA_WHITEMANE))) { me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); me->SetStandState(UNIT_STAND_STATE_STAND); DoCast(Whitemane, SPELL_LAYONHANDS); - m_uiCrusaderStrike_Timer = 10000; - m_uiHammerOfJustice_Timer = 10000; + CrusaderStrike_Timer = 10000; + HammerOfJustice_Timer = 10000; if (me->getVictim()) me->GetMotionMaster()->MoveChase(me->getVictim()); - m_bHeal = true; + _bHeal = true; } } //This if-check to make sure mograine does not attack while fake death - if (m_bFakeDeath) + if (_bFakeDeath) return; - //m_uiCrusaderStrike_Timer - if (m_uiCrusaderStrike_Timer <= uiDiff) + //CrusaderStrike_Timer + if (CrusaderStrike_Timer <= diff) { DoCast(me->getVictim(), SPELL_CRUSADERSTRIKE); - m_uiCrusaderStrike_Timer = 10000; - } else m_uiCrusaderStrike_Timer -= uiDiff; + CrusaderStrike_Timer = 10000; + } else CrusaderStrike_Timer -= diff; - //m_uiHammerOfJustice_Timer - if (m_uiHammerOfJustice_Timer <= uiDiff) + //HammerOfJustice_Timer + if (HammerOfJustice_Timer <= diff) { DoCast(me->getVictim(), SPELL_HAMMEROFJUSTICE); - m_uiHammerOfJustice_Timer = 60000; - } else m_uiHammerOfJustice_Timer -= uiDiff; + HammerOfJustice_Timer = 60000; + } else HammerOfJustice_Timer -= diff; DoMeleeAttackIfReady(); } }; - }; class boss_high_inquisitor_whitemane : public CreatureScript @@ -232,37 +234,37 @@ public: { boss_high_inquisitor_whitemaneAI(Creature* creature) : ScriptedAI(creature) { - m_instance = creature->GetInstanceScript(); + instance = creature->GetInstanceScript(); } - InstanceScript* m_instance; + InstanceScript* instance; - uint32 m_uiHeal_Timer; - uint32 m_uiPowerWordShield_Timer; - uint32 m_uiHolySmite_Timer; - uint32 m_uiWait_Timer; + uint32 Heal_Timer; + uint32 PowerWordShield_Timer; + uint32 HolySmite_Timer; + uint32 Wait_Timer; - bool m_bCanResurrectCheck; - bool m_bCanResurrect; + bool _bCanResurrectCheck; + bool _bCanResurrect; void Reset() { - m_uiWait_Timer = 7000; - m_uiHeal_Timer = 10000; - m_uiPowerWordShield_Timer = 15000; - m_uiHolySmite_Timer = 6000; + Wait_Timer = 7000; + Heal_Timer = 10000; + PowerWordShield_Timer = 15000; + HolySmite_Timer = 6000; - m_bCanResurrectCheck = false; - m_bCanResurrect = false; + _bCanResurrectCheck = false; + _bCanResurrect = false; - if (m_instance) + if (instance) if (me->isAlive()) - m_instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, NOT_STARTED); + instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, NOT_STARTED); } void AttackStart(Unit* who) { - if (m_instance && m_instance->GetData(TYPE_MOGRAINE_AND_WHITE_EVENT) == NOT_STARTED) + if (instance && instance->GetData(TYPE_MOGRAINE_AND_WHITE_EVENT) == NOT_STARTED) return; ScriptedAI::AttackStart(who); @@ -278,84 +280,83 @@ public: DoScriptText(SAY_WH_KILL, me); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 diff) { if (!UpdateVictim()) return; - if (m_bCanResurrect) + if (_bCanResurrect) { //When casting resuruction make sure to delay so on rez when reinstate battle deepsleep runs out - if (m_instance && m_uiWait_Timer <= uiDiff) + if (instance && Wait_Timer <= diff) { - if (Unit* Mograine = Unit::GetUnit((*me), m_instance->GetData64(DATA_MOGRAINE))) + if (Unit* Mograine = Unit::GetUnit((*me), instance->GetData64(DATA_MOGRAINE))) { DoCast(Mograine, SPELL_SCARLETRESURRECTION); DoScriptText(SAY_WH_RESSURECT, me); - m_bCanResurrect = false; + _bCanResurrect = false; } } - else m_uiWait_Timer -= uiDiff; + else Wait_Timer -= diff; } //Cast Deep sleep when health is less than 50% - if (!m_bCanResurrectCheck && !HealthAbovePct(50)) + if (!_bCanResurrectCheck && !HealthAbovePct(50)) { if (me->IsNonMeleeSpellCasted(false)) me->InterruptNonMeleeSpells(false); DoCast(me->getVictim(), SPELL_DEEPSLEEP); - m_bCanResurrectCheck = true; - m_bCanResurrect = true; + _bCanResurrectCheck = true; + _bCanResurrect = true; return; } //while in "resurrect-mode", don't do anything - if (m_bCanResurrect) + if (_bCanResurrect) return; //If we are <75% hp cast healing spells at self or Mograine - if (m_uiHeal_Timer <= uiDiff) + if (Heal_Timer <= diff) { Creature* target = NULL; if (!HealthAbovePct(75)) target = me; - if (m_instance) + if (instance) { - if (Creature* pMograine = Unit::GetCreature((*me), m_instance->GetData64(DATA_MOGRAINE))) + if (Creature* mograine = Unit::GetCreature((*me), instance->GetData64(DATA_MOGRAINE))) { - // checking m_bCanResurrectCheck prevents her healing Mograine while he is "faking death" - if (m_bCanResurrectCheck && pMograine->isAlive() && !pMograine->HealthAbovePct(75)) - target = pMograine; + // checking _bCanResurrectCheck prevents her healing Mograine while he is "faking death" + if (_bCanResurrectCheck && mograine->isAlive() && !mograine->HealthAbovePct(75)) + target = mograine; } } if (target) DoCast(target, SPELL_HEAL); - m_uiHeal_Timer = 13000; - } else m_uiHeal_Timer -= uiDiff; + Heal_Timer = 13000; + } else Heal_Timer -= diff; - //m_uiPowerWordShield_Timer - if (m_uiPowerWordShield_Timer <= uiDiff) + //PowerWordShield_Timer + if (PowerWordShield_Timer <= diff) { DoCast(me, SPELL_POWERWORDSHIELD); - m_uiPowerWordShield_Timer = 15000; - } else m_uiPowerWordShield_Timer -= uiDiff; + PowerWordShield_Timer = 15000; + } else PowerWordShield_Timer -= diff; - //m_uiHolySmite_Timer - if (m_uiHolySmite_Timer <= uiDiff) + //HolySmite_Timer + if (HolySmite_Timer <= diff) { DoCast(me->getVictim(), SPELL_HOLYSMITE); - m_uiHolySmite_Timer = 6000; - } else m_uiHolySmite_Timer -= uiDiff; + HolySmite_Timer = 6000; + } else HolySmite_Timer -= diff; DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_mograine_and_whitemane() diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp index dc10cb4d60f..63ccd29f263 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp @@ -25,10 +25,13 @@ EndScriptData */ #include "ScriptPCH.h" -#define SPELL_LICHSLAP 28873 -#define SPELL_FROSTBOLTVOLLEY 8398 -#define SPELL_MINDFLAY 17313 -#define SPELL_FROSTNOVA 15531 +enum Spells +{ + SPELL_LICHSLAP = 28873, + SPELL_FROSTBOLTVOLLEY = 8398, + SPELL_MINDFLAY = 17313, + SPELL_FROSTNOVA = 15531 +}; class boss_scorn : public CreatureScript { @@ -42,7 +45,7 @@ public: struct boss_scornAI : public ScriptedAI { - boss_scornAI(Creature* c) : ScriptedAI(c) {} + boss_scornAI(Creature* creature) : ScriptedAI(creature) {} uint32 LichSlap_Timer; uint32 FrostboltVolley_Timer; @@ -57,9 +60,7 @@ public: FrostNova_Timer = 30000; } - void EnterCombat(Unit* /*who*/) - { - } + void EnterCombat(Unit* /*who*/) {} void UpdateAI(const uint32 diff) { @@ -97,7 +98,6 @@ public: DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_scorn() diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp index f1cddb08a69..ba0b854754e 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp @@ -26,10 +26,13 @@ EndScriptData */ #include "ScriptPCH.h" #include "scarlet_monastery.h" -#define ENTRY_PUMPKIN_SHRINE 186267 -#define ENTRY_HORSEMAN 23682 -#define ENTRY_HEAD 23775 -#define ENTRY_PUMPKIN 23694 +enum Entry +{ + ENTRY_PUMPKIN_SHRINE = 186267, + ENTRY_HORSEMAN = 23682, + ENTRY_HEAD = 23775, + ENTRY_PUMPKIN = 23694 +}; #define MAX_ENCOUNTER 2 @@ -57,11 +60,11 @@ public: uint64 VorrelGUID; uint64 DoorHighInquisitorGUID; - uint32 m_auiEncounter[MAX_ENCOUNTER]; + uint32 encounter[MAX_ENCOUNTER]; void Initialize() { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + memset(&encounter, 0, sizeof(encounter)); PumpkinShrineGUID = 0; HorsemanGUID = 0; @@ -106,13 +109,13 @@ public: if (data == FAIL) DoUseDoorOrButton(DoorHighInquisitorGUID); - m_auiEncounter[0] = data; + encounter[0] = data; break; case GAMEOBJECT_PUMPKIN_SHRINE: HandleGameObject(PumpkinShrineGUID, false); break; case DATA_HORSEMAN_EVENT: - m_auiEncounter[1] = data; + encounter[1] = data; if (data == DONE) { for (std::set::const_iterator itr = HorsemanAdds.begin(); itr != HorsemanAdds.end(); ++itr) @@ -146,13 +149,12 @@ public: uint32 GetData(uint32 type) { if (type == TYPE_MOGRAINE_AND_WHITE_EVENT) - return m_auiEncounter[0]; + return encounter[0]; if (type == DATA_HORSEMAN_EVENT) - return m_auiEncounter[1]; + return encounter[1]; return 0; } }; - }; void AddSC_instance_scarlet_monastery() diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h b/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h index ca6bd1d185a..70b18919704 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h @@ -19,14 +19,17 @@ #ifndef DEF_SCARLET_M #define DEF_SCARLET_M -#define TYPE_MOGRAINE_AND_WHITE_EVENT 1 -#define DATA_MOGRAINE 2 -#define DATA_WHITEMANE 3 -#define DATA_DOOR_WHITEMANE 4 +enum eEnums +{ + TYPE_MOGRAINE_AND_WHITE_EVENT = 1, -#define DATA_HORSEMAN_EVENT 5 -#define GAMEOBJECT_PUMPKIN_SHRINE 6 + DATA_MOGRAINE = 2, + DATA_WHITEMANE = 3, + DATA_DOOR_WHITEMANE = 4, -#define DATA_VORREL 7 -#endif + DATA_HORSEMAN_EVENT = 5, + GAMEOBJECT_PUMPKIN_SHRINE = 6, + DATA_VORREL = 7 +}; +#endif -- cgit v1.2.3 From c0cd16e51d76bb2ac48853ddd1c2f3cc97a833df Mon Sep 17 00:00:00 2001 From: Bootz Date: Thu, 26 Jan 2012 02:40:15 -0600 Subject: Scripts/EasternKingdoms: ScarletMonastery * Fixed a few derps i missed on last patch --- .../ScarletMonastery/boss_arcanist_doan.cpp | 9 +++-- .../ScarletMonastery/boss_azshir_the_sleepless.cpp | 10 ++++-- .../ScarletMonastery/boss_bloodmage_thalnos.cpp | 12 ++++--- .../ScarletMonastery/boss_headless_horseman.cpp | 38 ++++++++++++++-------- .../ScarletMonastery/boss_herod.cpp | 7 ++-- .../boss_high_inquisitor_fairbanks.cpp | 15 ++++++--- .../ScarletMonastery/boss_houndmaster_loksey.cpp | 3 +- .../ScarletMonastery/boss_interrogator_vishas.cpp | 3 +- .../boss_mograine_and_whitemane.cpp | 15 ++++++--- .../ScarletMonastery/boss_scorn.cpp | 12 ++++--- 10 files changed, 83 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp index 5054472c671..a9a9c67e6df 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp @@ -105,21 +105,24 @@ public: DoCast(target, SPELL_POLYMORPH); Polymorph_Timer = 20000; - } else Polymorph_Timer -= diff; + } + else Polymorph_Timer -= diff; //AoESilence_Timer if (AoESilence_Timer <= diff) { DoCast(me->getVictim(), SPELL_AOESILENCE); AoESilence_Timer = urand(15000, 20000); - } else AoESilence_Timer -= diff; + } + else AoESilence_Timer -= diff; //ArcaneExplosion_Timer if (ArcaneExplosion_Timer <= diff) { DoCast(me->getVictim(), SPELL_ARCANEEXPLOSION); ArcaneExplosion_Timer = 8000; - } else ArcaneExplosion_Timer -= diff; + } + else ArcaneExplosion_Timer -= diff; DoMeleeAttackIfReady(); } diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp index 1802d828a1b..6a8a1f8fc61 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp @@ -24,6 +24,7 @@ SDCategory: Scarlet Monastery EndScriptData */ #include "ScriptPCH.h" + enum Spells { SPELL_CALLOFTHEGRAVE = 17831, @@ -73,7 +74,8 @@ public: return; //SoulSiphon_Timer = 20000; - } else SoulSiphon_Timer -= diff; + } + else SoulSiphon_Timer -= diff; } //CallOfTheGrave_Timer @@ -81,14 +83,16 @@ public: { DoCast(me->getVictim(), SPELL_CALLOFTHEGRAVE); CallOftheGrave_Timer = 30000; - } else CallOftheGrave_Timer -= diff; + } + else CallOftheGrave_Timer -= diff; //Terrify_Timer if (Terrify_Timer <= diff) { DoCast(me->getVictim(), SPELL_TERRIFY); Terrify_Timer = 20000; - } else Terrify_Timer -= diff; + } + else Terrify_Timer -= diff; DoMeleeAttackIfReady(); } diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp index 669d7bb16f3..f54e93eba21 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp @@ -93,28 +93,32 @@ public: { DoCast(me->getVictim(), SPELL_FLAMESHOCK); FlameShock_Timer = urand(10000, 15000); - } else FlameShock_Timer -= diff; + } + else FlameShock_Timer -= diff; //FlameSpike_Timer if (FlameSpike_Timer <= diff) { DoCast(me->getVictim(), SPELL_FLAMESPIKE); FlameSpike_Timer = 30000; - } else FlameSpike_Timer -= diff; + } + else FlameSpike_Timer -= diff; //FireNova_Timer if (FireNova_Timer <= diff) { DoCast(me->getVictim(), SPELL_FIRENOVA); FireNova_Timer = 40000; - } else FireNova_Timer -= diff; + } + else FireNova_Timer -= diff; //ShadowBolt_Timer if (ShadowBolt_Timer <= diff) { DoCast(me->getVictim(), SPELL_SHADOWBOLT); ShadowBolt_Timer = 2000; - } else ShadowBolt_Timer -= diff; + } + else ShadowBolt_Timer -= diff; DoMeleeAttackIfReady(); } diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp index f53779ea5da..834b1a8ac75 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp @@ -322,7 +322,8 @@ public: if (!me->getVictim()) return; me->GetMotionMaster()->Clear(false); me->GetMotionMaster()->MoveFleeing(me->getVictim()); - } else wait -= diff; + } + else wait -= diff; if (laugh <= diff) { @@ -333,7 +334,8 @@ public: if (speaker) speaker->CastSpell(speaker, SPELL_HEAD_SPEAKS, false); me->MonsterTextEmote(EMOTE_LAUGHS, 0); - } else laugh -= diff; + } + else laugh -= diff; } else { @@ -345,7 +347,8 @@ public: if (Unit* body = Unit::GetUnit((*me), bodyGUID)) body->Kill(body); me->Kill(me); - } else wait -= diff; + } + else wait -= diff; } } } @@ -641,7 +644,8 @@ public: break; } ++count; - } else say_timer -= diff; + } + else say_timer -= diff; } else { @@ -662,7 +666,8 @@ public: if (Creature* flame = me->SummonCreature(HELPER, Spawn[0].x, Spawn[0].y, Spawn[0].z, 0, TEMPSUMMON_TIMED_DESPAWN, 17000)) CAST_AI(mob_wisp_invis::mob_wisp_invisAI, flame->AI())->SetType(2); burned = true; - } else burn -= diff; + } + else burn -= diff; break; case 2: if (conflagrate <= diff) @@ -670,7 +675,8 @@ public: if (Unit* player = SelectRandomPlayer(30.0f)) DoCast(player, SPELL_CONFLAGRATION, false); conflagrate = urand(10000, 16000); - } else conflagrate -= diff; + } + else conflagrate -= diff; break; case 3: if (summonadds <= diff) @@ -679,7 +685,8 @@ public: DoCast(me, SPELL_SUMMON_PUMPKIN); SaySound(SAY_SPROUTING_PUMPKINS); summonadds = urand(25000, 35000); - } else summonadds -= diff; + } + else summonadds -= diff; break; } @@ -688,7 +695,8 @@ public: laugh = urand(11000, 22000); me->MonsterTextEmote(EMOTE_LAUGHS, 0); DoPlaySoundToSet(me, RandomLaugh[rand()%3]); - } else laugh -= diff; + } + else laugh -= diff; if (UpdateVictim()) { @@ -697,7 +705,8 @@ public: { DoCast(me->getVictim(), SPELL_CLEAVE); cleave = urand(2000, 6000); //1 cleave per 2.0f-6.0fsec - } else cleave -= diff; + } + else cleave -= diff; } } else @@ -730,9 +739,11 @@ public: me->RemoveAurasDueToSpell(SPELL_CONFUSE); DoCast(me, SPELL_WHIRLWIND, true); DoCast(me, SPELL_CONFUSE); - } else + } + else me->RemoveAurasDueToSpell(SPELL_WHIRLWIND); - } else whirlwind -= diff; + } + else whirlwind -= diff; } } }; @@ -832,12 +843,12 @@ public: if (instance->GetData(DATA_HORSEMAN_EVENT) != NOT_STARTED) return true; instance->SetData(DATA_HORSEMAN_EVENT, IN_PROGRESS); - } + } /* if (soil->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER && player->getLevel() > 64) { player->PrepareQuestMenu(soil->GetGUID()); player->SendPreparedQuest(soil->GetGUID()); - } + } if (player->GetQuestStatus(11405) == QUEST_STATUS_INCOMPLETE && player->getLevel() > 64) { */ player->AreaExploredOrEventHappens(11405); @@ -855,6 +866,7 @@ void mob_head::mob_headAI::Disappear() { if (withbody) return; + if (bodyGUID) { Creature* body = Unit::GetCreature((*me), bodyGUID); diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp index e87581a3bbd..e194f064d85 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp @@ -33,6 +33,7 @@ enum Says SAY_ENRAGE = -1189002, SAY_KILL = -1189003 }; + enum Emotes { EMOTE_ENRAGE = -1189004 @@ -114,7 +115,8 @@ public: { DoCast(me->getVictim(), SPELL_CLEAVE); Cleave_Timer = 12000; - } else Cleave_Timer -= diff; + } + else Cleave_Timer -= diff; // Whirlwind_Timer if (Whirlwind_Timer <= diff) @@ -122,7 +124,8 @@ public: DoScriptText(SAY_WHIRLWIND, me); DoCast(me->getVictim(), SPELL_WHIRLWIND); Whirlwind_Timer = 30000; - } else Whirlwind_Timer -= diff; + } + else Whirlwind_Timer -= diff; DoMeleeAttackIfReady(); } diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp index 22624fd6066..e2c14f97381 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp @@ -80,7 +80,8 @@ public: { DoCast(me, SPELL_HEAL); Heal_Timer = 30000; - } else Heal_Timer -= diff; + } + else Heal_Timer -= diff; //Fear_Timer if (Fear_Timer <= diff) @@ -89,7 +90,8 @@ public: DoCast(target, SPELL_FEAR); Fear_Timer = 40000; - } else Fear_Timer -= diff; + } + else Fear_Timer -= diff; //Sleep_Timer if (Sleep_Timer <= diff) @@ -98,7 +100,8 @@ public: DoCast(target, SPELL_SLEEP); Sleep_Timer = 30000; - } else Sleep_Timer -= diff; + } + else Sleep_Timer -= diff; //PowerWordShield_Timer if (!PowerWordShield && !HealthAbovePct(25)) @@ -114,14 +117,16 @@ public: DoCast(target, SPELL_DISPELMAGIC); DispelMagic_Timer = 30000; - } else DispelMagic_Timer -= diff; + } + else DispelMagic_Timer -= diff; //CurseOfBlood_Timer if (CurseOfBlood_Timer <= diff) { DoCast(me->getVictim(), SPELL_CURSEOFBLOOD); CurseOfBlood_Timer = 25000; - } else CurseOfBlood_Timer -= diff; + } + else CurseOfBlood_Timer -= diff; DoMeleeAttackIfReady(); } diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp index 4bd3c134c61..f8ccc44aede 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp @@ -67,7 +67,8 @@ public: { DoCast(me, SPELL_BLOODLUST); BloodLust_Timer = 20000; - } else BloodLust_Timer -= diff; + } + else BloodLust_Timer -= diff; DoMeleeAttackIfReady(); } diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp index a5c1f48a11b..c3eccaa7871 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp @@ -111,7 +111,8 @@ public: { DoCast(me->getVictim(), SPELL_SHADOWWORDPAIN); ShadowWordPain_Timer = urand(5000, 15000); - } else ShadowWordPain_Timer -= diff; + } + else ShadowWordPain_Timer -= diff; DoMeleeAttackIfReady(); } diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp index 87bee1ca6ad..9547a152337 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp @@ -206,14 +206,16 @@ public: { DoCast(me->getVictim(), SPELL_CRUSADERSTRIKE); CrusaderStrike_Timer = 10000; - } else CrusaderStrike_Timer -= diff; + } + else CrusaderStrike_Timer -= diff; //HammerOfJustice_Timer if (HammerOfJustice_Timer <= diff) { DoCast(me->getVictim(), SPELL_HAMMEROFJUSTICE); HammerOfJustice_Timer = 60000; - } else HammerOfJustice_Timer -= diff; + } + else HammerOfJustice_Timer -= diff; DoMeleeAttackIfReady(); } @@ -338,21 +340,24 @@ public: DoCast(target, SPELL_HEAL); Heal_Timer = 13000; - } else Heal_Timer -= diff; + } + else Heal_Timer -= diff; //PowerWordShield_Timer if (PowerWordShield_Timer <= diff) { DoCast(me, SPELL_POWERWORDSHIELD); PowerWordShield_Timer = 15000; - } else PowerWordShield_Timer -= diff; + } + else PowerWordShield_Timer -= diff; //HolySmite_Timer if (HolySmite_Timer <= diff) { DoCast(me->getVictim(), SPELL_HOLYSMITE); HolySmite_Timer = 6000; - } else HolySmite_Timer -= diff; + } + else HolySmite_Timer -= diff; DoMeleeAttackIfReady(); } diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp index 63ccd29f263..d943053a80d 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp @@ -72,28 +72,32 @@ public: { DoCast(me->getVictim(), SPELL_LICHSLAP); LichSlap_Timer = 45000; - } else LichSlap_Timer -= diff; + } + else LichSlap_Timer -= diff; //FrostboltVolley_Timer if (FrostboltVolley_Timer <= diff) { DoCast(me->getVictim(), SPELL_FROSTBOLTVOLLEY); FrostboltVolley_Timer = 20000; - } else FrostboltVolley_Timer -= diff; + } + else FrostboltVolley_Timer -= diff; //MindFlay_Timer if (MindFlay_Timer <= diff) { DoCast(me->getVictim(), SPELL_MINDFLAY); MindFlay_Timer = 20000; - } else MindFlay_Timer -= diff; + } + else MindFlay_Timer -= diff; //FrostNova_Timer if (FrostNova_Timer <= diff) { DoCast(me->getVictim(), SPELL_FROSTNOVA); FrostNova_Timer = 15000; - } else FrostNova_Timer -= diff; + } + else FrostNova_Timer -= diff; DoMeleeAttackIfReady(); } -- cgit v1.2.3 From 74441b12ec8da18212a49b5861b0776ffc06324b Mon Sep 17 00:00:00 2001 From: Bootz Date: Thu, 26 Jan 2012 02:49:10 -0600 Subject: Scripts/EasternKingdoms: ScarletMonastery * Removed trailing white spaces --- .../ScarletMonastery/boss_arcanist_doan.cpp | 4 ++-- .../ScarletMonastery/boss_azshir_the_sleepless.cpp | 6 ++--- .../ScarletMonastery/boss_bloodmage_thalnos.cpp | 8 +++---- .../ScarletMonastery/boss_headless_horseman.cpp | 28 +++++++++++----------- .../ScarletMonastery/boss_herod.cpp | 4 ++-- .../boss_high_inquisitor_fairbanks.cpp | 10 ++++---- .../ScarletMonastery/boss_houndmaster_loksey.cpp | 2 +- .../ScarletMonastery/boss_interrogator_vishas.cpp | 2 +- .../boss_mograine_and_whitemane.cpp | 10 ++++---- .../ScarletMonastery/boss_scorn.cpp | 8 +++---- 10 files changed, 41 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp index a9a9c67e6df..e5886cc39d4 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp @@ -113,7 +113,7 @@ public: { DoCast(me->getVictim(), SPELL_AOESILENCE); AoESilence_Timer = urand(15000, 20000); - } + } else AoESilence_Timer -= diff; //ArcaneExplosion_Timer @@ -121,7 +121,7 @@ public: { DoCast(me->getVictim(), SPELL_ARCANEEXPLOSION); ArcaneExplosion_Timer = 8000; - } + } else ArcaneExplosion_Timer -= diff; DoMeleeAttackIfReady(); diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp index 6a8a1f8fc61..30105cc7315 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp @@ -74,7 +74,7 @@ public: return; //SoulSiphon_Timer = 20000; - } + } else SoulSiphon_Timer -= diff; } @@ -83,7 +83,7 @@ public: { DoCast(me->getVictim(), SPELL_CALLOFTHEGRAVE); CallOftheGrave_Timer = 30000; - } + } else CallOftheGrave_Timer -= diff; //Terrify_Timer @@ -91,7 +91,7 @@ public: { DoCast(me->getVictim(), SPELL_TERRIFY); Terrify_Timer = 20000; - } + } else Terrify_Timer -= diff; DoMeleeAttackIfReady(); diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp index f54e93eba21..466f940621d 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp @@ -93,7 +93,7 @@ public: { DoCast(me->getVictim(), SPELL_FLAMESHOCK); FlameShock_Timer = urand(10000, 15000); - } + } else FlameShock_Timer -= diff; //FlameSpike_Timer @@ -101,7 +101,7 @@ public: { DoCast(me->getVictim(), SPELL_FLAMESPIKE); FlameSpike_Timer = 30000; - } + } else FlameSpike_Timer -= diff; //FireNova_Timer @@ -109,7 +109,7 @@ public: { DoCast(me->getVictim(), SPELL_FIRENOVA); FireNova_Timer = 40000; - } + } else FireNova_Timer -= diff; //ShadowBolt_Timer @@ -117,7 +117,7 @@ public: { DoCast(me->getVictim(), SPELL_SHADOWBOLT); ShadowBolt_Timer = 2000; - } + } else ShadowBolt_Timer -= diff; DoMeleeAttackIfReady(); diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp index 834b1a8ac75..77099f2e2d7 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp @@ -322,7 +322,7 @@ public: if (!me->getVictim()) return; me->GetMotionMaster()->Clear(false); me->GetMotionMaster()->MoveFleeing(me->getVictim()); - } + } else wait -= diff; if (laugh <= diff) @@ -334,7 +334,7 @@ public: if (speaker) speaker->CastSpell(speaker, SPELL_HEAD_SPEAKS, false); me->MonsterTextEmote(EMOTE_LAUGHS, 0); - } + } else laugh -= diff; } else @@ -347,7 +347,7 @@ public: if (Unit* body = Unit::GetUnit((*me), bodyGUID)) body->Kill(body); me->Kill(me); - } + } else wait -= diff; } } @@ -644,7 +644,7 @@ public: break; } ++count; - } + } else say_timer -= diff; } else @@ -666,7 +666,7 @@ public: if (Creature* flame = me->SummonCreature(HELPER, Spawn[0].x, Spawn[0].y, Spawn[0].z, 0, TEMPSUMMON_TIMED_DESPAWN, 17000)) CAST_AI(mob_wisp_invis::mob_wisp_invisAI, flame->AI())->SetType(2); burned = true; - } + } else burn -= diff; break; case 2: @@ -675,7 +675,7 @@ public: if (Unit* player = SelectRandomPlayer(30.0f)) DoCast(player, SPELL_CONFLAGRATION, false); conflagrate = urand(10000, 16000); - } + } else conflagrate -= diff; break; case 3: @@ -685,7 +685,7 @@ public: DoCast(me, SPELL_SUMMON_PUMPKIN); SaySound(SAY_SPROUTING_PUMPKINS); summonadds = urand(25000, 35000); - } + } else summonadds -= diff; break; } @@ -695,7 +695,7 @@ public: laugh = urand(11000, 22000); me->MonsterTextEmote(EMOTE_LAUGHS, 0); DoPlaySoundToSet(me, RandomLaugh[rand()%3]); - } + } else laugh -= diff; if (UpdateVictim()) @@ -705,7 +705,7 @@ public: { DoCast(me->getVictim(), SPELL_CLEAVE); cleave = urand(2000, 6000); //1 cleave per 2.0f-6.0fsec - } + } else cleave -= diff; } } @@ -739,10 +739,10 @@ public: me->RemoveAurasDueToSpell(SPELL_CONFUSE); DoCast(me, SPELL_WHIRLWIND, true); DoCast(me, SPELL_CONFUSE); - } + } else me->RemoveAurasDueToSpell(SPELL_WHIRLWIND); - } + } else whirlwind -= diff; } } @@ -843,12 +843,12 @@ public: if (instance->GetData(DATA_HORSEMAN_EVENT) != NOT_STARTED) return true; instance->SetData(DATA_HORSEMAN_EVENT, IN_PROGRESS); - } + } /* if (soil->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER && player->getLevel() > 64) { player->PrepareQuestMenu(soil->GetGUID()); player->SendPreparedQuest(soil->GetGUID()); - } + } if (player->GetQuestStatus(11405) == QUEST_STATUS_INCOMPLETE && player->getLevel() > 64) { */ player->AreaExploredOrEventHappens(11405); @@ -866,7 +866,7 @@ void mob_head::mob_headAI::Disappear() { if (withbody) return; - + if (bodyGUID) { Creature* body = Unit::GetCreature((*me), bodyGUID); diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp index e194f064d85..16b90f89bb5 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp @@ -115,7 +115,7 @@ public: { DoCast(me->getVictim(), SPELL_CLEAVE); Cleave_Timer = 12000; - } + } else Cleave_Timer -= diff; // Whirlwind_Timer @@ -124,7 +124,7 @@ public: DoScriptText(SAY_WHIRLWIND, me); DoCast(me->getVictim(), SPELL_WHIRLWIND); Whirlwind_Timer = 30000; - } + } else Whirlwind_Timer -= diff; DoMeleeAttackIfReady(); diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp index e2c14f97381..a64636a4223 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp @@ -80,7 +80,7 @@ public: { DoCast(me, SPELL_HEAL); Heal_Timer = 30000; - } + } else Heal_Timer -= diff; //Fear_Timer @@ -90,7 +90,7 @@ public: DoCast(target, SPELL_FEAR); Fear_Timer = 40000; - } + } else Fear_Timer -= diff; //Sleep_Timer @@ -100,7 +100,7 @@ public: DoCast(target, SPELL_SLEEP); Sleep_Timer = 30000; - } + } else Sleep_Timer -= diff; //PowerWordShield_Timer @@ -117,7 +117,7 @@ public: DoCast(target, SPELL_DISPELMAGIC); DispelMagic_Timer = 30000; - } + } else DispelMagic_Timer -= diff; //CurseOfBlood_Timer @@ -125,7 +125,7 @@ public: { DoCast(me->getVictim(), SPELL_CURSEOFBLOOD); CurseOfBlood_Timer = 25000; - } + } else CurseOfBlood_Timer -= diff; DoMeleeAttackIfReady(); diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp index f8ccc44aede..f311da401d4 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp @@ -67,7 +67,7 @@ public: { DoCast(me, SPELL_BLOODLUST); BloodLust_Timer = 20000; - } + } else BloodLust_Timer -= diff; DoMeleeAttackIfReady(); diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp index c3eccaa7871..058c688641f 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp @@ -111,7 +111,7 @@ public: { DoCast(me->getVictim(), SPELL_SHADOWWORDPAIN); ShadowWordPain_Timer = urand(5000, 15000); - } + } else ShadowWordPain_Timer -= diff; DoMeleeAttackIfReady(); diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp index 9547a152337..ec6ac34b0bb 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp @@ -206,7 +206,7 @@ public: { DoCast(me->getVictim(), SPELL_CRUSADERSTRIKE); CrusaderStrike_Timer = 10000; - } + } else CrusaderStrike_Timer -= diff; //HammerOfJustice_Timer @@ -214,7 +214,7 @@ public: { DoCast(me->getVictim(), SPELL_HAMMEROFJUSTICE); HammerOfJustice_Timer = 60000; - } + } else HammerOfJustice_Timer -= diff; DoMeleeAttackIfReady(); @@ -340,7 +340,7 @@ public: DoCast(target, SPELL_HEAL); Heal_Timer = 13000; - } + } else Heal_Timer -= diff; //PowerWordShield_Timer @@ -348,7 +348,7 @@ public: { DoCast(me, SPELL_POWERWORDSHIELD); PowerWordShield_Timer = 15000; - } + } else PowerWordShield_Timer -= diff; //HolySmite_Timer @@ -356,7 +356,7 @@ public: { DoCast(me->getVictim(), SPELL_HOLYSMITE); HolySmite_Timer = 6000; - } + } else HolySmite_Timer -= diff; DoMeleeAttackIfReady(); diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp index d943053a80d..8035adfc33f 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp @@ -72,7 +72,7 @@ public: { DoCast(me->getVictim(), SPELL_LICHSLAP); LichSlap_Timer = 45000; - } + } else LichSlap_Timer -= diff; //FrostboltVolley_Timer @@ -80,7 +80,7 @@ public: { DoCast(me->getVictim(), SPELL_FROSTBOLTVOLLEY); FrostboltVolley_Timer = 20000; - } + } else FrostboltVolley_Timer -= diff; //MindFlay_Timer @@ -88,7 +88,7 @@ public: { DoCast(me->getVictim(), SPELL_MINDFLAY); MindFlay_Timer = 20000; - } + } else MindFlay_Timer -= diff; //FrostNova_Timer @@ -96,7 +96,7 @@ public: { DoCast(me->getVictim(), SPELL_FROSTNOVA); FrostNova_Timer = 15000; - } + } else FrostNova_Timer -= diff; DoMeleeAttackIfReady(); -- cgit v1.2.3 From 6c3bdb1f7097102ba250aab553e71813ff3478d1 Mon Sep 17 00:00:00 2001 From: Bootz Date: Thu, 26 Jan 2012 02:55:23 -0600 Subject: Scripts/EasternKingdoms: MoltenCore * Fixed Enums in defines. --- .../EasternKingdoms/MoltenCore/molten_core.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/server/scripts/EasternKingdoms/MoltenCore/molten_core.cpp b/src/server/scripts/EasternKingdoms/MoltenCore/molten_core.cpp index eafe55d3821..801a11fbfc8 100644 --- a/src/server/scripts/EasternKingdoms/MoltenCore/molten_core.cpp +++ b/src/server/scripts/EasternKingdoms/MoltenCore/molten_core.cpp @@ -30,16 +30,19 @@ EndContentData */ #include "ScriptPCH.h" #include "ScriptedSimpleAI.h" -#define SPELL_CONE_OF_FIRE 19630 -#define SPELL_BITE 19771 +enum Spells +{ + SPELL_CONE_OF_FIRE = 19630, + SPELL_BITE = 19771, -//Random Debuff (each hound has only one of these) -#define SPELL_GROUND_STOMP 19364 -#define SPELL_ANCIENT_DREAD 19365 -#define SPELL_CAUTERIZING_FLAMES 19366 -#define SPELL_WITHERING_HEAT 19367 -#define SPELL_ANCIENT_DESPAIR 19369 -#define SPELL_ANCIENT_HYSTERIA 19372 + //Random Debuff (each hound has only one of these) + SPELL_GROUND_STOMP = 19364, + SPELL_ANCIENT_DREAD = 19365, + SPELL_CAUTERIZING_FLAMES = 19366, + SPELL_WITHERING_HEAT = 19367, + SPELL_ANCIENT_DESPAIR = 19369, + SPELL_ANCIENT_HYSTERIA = 19372 +}; class mob_ancient_core_hound : public CreatureScript { @@ -75,7 +78,6 @@ public: return ai; } - }; void AddSC_molten_core() -- cgit v1.2.3 From bf4b83436aa1ad50a95e799506df5d44f67aca03 Mon Sep 17 00:00:00 2001 From: Bootz Date: Thu, 26 Jan 2012 03:01:23 -0600 Subject: Scripts/Kalimdor: BlackFathomDeep * Code Standardizations. - Removed SD2 hieroglyphics. - Removed Hungarian Notations. - Fixed Enums in Defines. --- .../BlackfathomDeeps/blackfathom_deeps.cpp | 47 +++--- .../Kalimdor/BlackfathomDeeps/boss_aku_mai.cpp | 15 +- .../Kalimdor/BlackfathomDeeps/boss_gelihast.cpp | 15 +- .../Kalimdor/BlackfathomDeeps/boss_kelris.cpp | 25 ++-- .../instance_blackfathom_deeps.cpp | 163 ++++++++++----------- 5 files changed, 130 insertions(+), 135 deletions(-) (limited to 'src') diff --git a/src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp b/src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp index 29029803369..878116ad476 100644 --- a/src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp +++ b/src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp @@ -43,7 +43,6 @@ public: player->AddAura(SPELL_BLESSING_OF_BLACKFATHOM, player); return true; } - }; class go_blackfathom_fire : public GameObjectScript @@ -64,7 +63,6 @@ public: } return false; } - }; class npc_blackfathom_deeps_event : public CreatureScript @@ -92,9 +90,9 @@ public: InstanceScript* instance; - uint32 uiRavageTimer; - uint32 uiFrostNovaTimer; - uint32 uiFrostBoltVolleyTimer; + uint32 ravageTimer; + uint32 frostNovaTimer; + uint32 frostBoltVolleyTimer; bool bFlee; @@ -102,9 +100,9 @@ public: { bFlee = false; - uiRavageTimer = urand(5000, 8000); - uiFrostNovaTimer = urand(9000, 12000); - uiFrostBoltVolleyTimer = urand(2000, 4000); + ravageTimer = urand(5000, 8000); + frostNovaTimer = urand(9000, 12000); + frostBoltVolleyTimer = urand(2000, 4000); } void AttackPlayer() @@ -131,7 +129,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 diff) { if (!UpdateVictim()) return; @@ -140,11 +138,11 @@ public: { case NPC_AKU_MAI_SNAPJAW: { - if (uiRavageTimer <= uiDiff) + if (ravageTimer <= diff) { DoCast(me->getVictim(), SPELL_RAVAGE); - uiRavageTimer = urand(9000, 14000); - } else uiRavageTimer -= uiDiff; + ravageTimer = urand(9000, 14000); + } else ravageTimer -= diff; break; } case NPC_MURKSHALLOW_SOFTSHELL: @@ -159,20 +157,23 @@ public: } case NPC_AKU_MAI_SERVANT: { - if (uiFrostBoltVolleyTimer <= uiDiff) + if (frostBoltVolleyTimer <= diff) { if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) { if (target) DoCast(target, SPELL_FROST_BOLT_VOLLEY); } - uiFrostBoltVolleyTimer = urand(5000, 8000); - } else uiFrostBoltVolleyTimer -= uiDiff; - if (uiFrostNovaTimer <= uiDiff) + frostBoltVolleyTimer = urand(5000, 8000); + } + else frostBoltVolleyTimer -= diff; + + if (frostNovaTimer <= diff) { DoCastAOE(SPELL_FROST_NOVA, false); - uiFrostNovaTimer = urand(25000, 30000); - } else uiFrostNovaTimer -= uiDiff; + frostNovaTimer = urand(25000, 30000); + } + else frostNovaTimer -= diff; break; } } @@ -187,7 +188,6 @@ public: instance->SetData(DATA_EVENT, instance->GetData(DATA_EVENT) + 1); } }; - }; enum eMorridune @@ -201,12 +201,12 @@ class npc_morridune : public CreatureScript public: npc_morridune() : CreatureScript("npc_morridune") { } - bool OnGossipSelect(Player* player, Creature* /*creature*/, uint32 /*uiSender*/, uint32 uiAction) + bool OnGossipSelect(Player* player, Creature* /*creature*/, uint32 /*Sender*/, uint32 action) { player->PlayerTalkClass->ClearMenus(); - switch (uiAction) + switch (action) { - case GOSSIP_ACTION_INFO_DEF+1: + case GOSSIP_ACTION_INFO_DEF + 1: player->TeleportTo(1, 9952.239f, 2284.277f, 1341.394f, 1.595f); player->CLOSE_GOSSIP_MENU(); break; @@ -216,7 +216,7 @@ public: bool OnGossipHello(Player* player, Creature* creature) { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_MORRIDUNE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_MORRIDUNE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); return true; @@ -250,7 +250,6 @@ public: } } }; - }; void AddSC_blackfathom_deeps() diff --git a/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_aku_mai.cpp b/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_aku_mai.cpp index 87e8478532d..32a6bcbde77 100644 --- a/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_aku_mai.cpp +++ b/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_aku_mai.cpp @@ -36,19 +36,19 @@ public: struct boss_aku_maiAI : public ScriptedAI { - boss_aku_maiAI(Creature* c) : ScriptedAI(c) + boss_aku_maiAI(Creature* creature) : ScriptedAI(creature) { - instance = c->GetInstanceScript(); + instance = creature->GetInstanceScript(); } - uint32 uiPoisonCloudTimer; + uint32 poisonCloudTimer; bool bIsEnraged; InstanceScript* instance; void Reset() { - uiPoisonCloudTimer = urand(5000, 9000); + poisonCloudTimer = urand(5000, 9000); bIsEnraged = false; if (instance) instance->SetData(TYPE_AKU_MAI, NOT_STARTED); @@ -71,11 +71,11 @@ public: if (!UpdateVictim()) return; - if (uiPoisonCloudTimer < diff) + if (poisonCloudTimer < diff) { DoCastVictim(SPELL_POISON_CLOUD); - uiPoisonCloudTimer = urand(25000, 50000); - } else uiPoisonCloudTimer -= diff; + poisonCloudTimer = urand(25000, 50000); + } else poisonCloudTimer -= diff; if (!bIsEnraged && HealthBelowPct(30)) { @@ -86,7 +86,6 @@ public: DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_aku_mai() diff --git a/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_gelihast.cpp b/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_gelihast.cpp index e7822a6edb3..5a60a849b75 100644 --- a/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_gelihast.cpp +++ b/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_gelihast.cpp @@ -35,18 +35,18 @@ public: struct boss_gelihastAI : public ScriptedAI { - boss_gelihastAI(Creature* c) : ScriptedAI(c) + boss_gelihastAI(Creature* creature) : ScriptedAI(creature) { - instance = c->GetInstanceScript(); + instance = creature->GetInstanceScript(); } - uint32 uiNetTimer; + uint32 netTimer; InstanceScript* instance; void Reset() { - uiNetTimer = urand(2000, 4000); + netTimer = urand(2000, 4000); if (instance) instance->SetData(TYPE_GELIHAST, NOT_STARTED); } @@ -68,16 +68,15 @@ public: if (!UpdateVictim()) return; - if (uiNetTimer < diff) + if (netTimer < diff) { DoCastVictim(SPELL_NET); - uiNetTimer = urand(4000, 7000); - } else uiNetTimer -= diff; + netTimer = urand(4000, 7000); + } else netTimer -= diff; DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_gelihast() diff --git a/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_kelris.cpp b/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_kelris.cpp index 5823ed15ed5..7ee17172102 100644 --- a/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_kelris.cpp +++ b/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_kelris.cpp @@ -44,20 +44,20 @@ public: struct boss_kelrisAI : public ScriptedAI { - boss_kelrisAI(Creature* c) : ScriptedAI(c) + boss_kelrisAI(Creature* creature) : ScriptedAI(creature) { - instance = c->GetInstanceScript(); + instance = creature->GetInstanceScript(); } - uint32 uiMindBlastTimer; - uint32 uiSleepTimer; + uint32 mindBlastTimer; + uint32 sleepTimer; InstanceScript* instance; void Reset() { - uiMindBlastTimer = urand(2000, 5000); - uiSleepTimer = urand(9000, 12000); + mindBlastTimer = urand(2000, 5000); + sleepTimer = urand(9000, 12000); if (instance) instance->SetData(TYPE_KELRIS, NOT_STARTED); } @@ -81,26 +81,25 @@ public: if (!UpdateVictim()) return; - if (uiMindBlastTimer < diff) + if (mindBlastTimer < diff) { DoCastVictim(SPELL_MIND_BLAST); - uiMindBlastTimer = urand(7000, 9000); - } else uiMindBlastTimer -= diff; + mindBlastTimer = urand(7000, 9000); + } else mindBlastTimer -= diff; - if (uiSleepTimer < diff) + if (sleepTimer < diff) { if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) { DoScriptText(SAY_SLEEP, me); DoCast(target, SPELL_SLEEP); } - uiSleepTimer = urand(15000, 20000); - } else uiSleepTimer -= diff; + sleepTimer = urand(15000, 20000); + } else sleepTimer -= diff; DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_kelris() diff --git a/src/server/scripts/Kalimdor/BlackfathomDeeps/instance_blackfathom_deeps.cpp b/src/server/scripts/Kalimdor/BlackfathomDeeps/instance_blackfathom_deeps.cpp index 8dd4e60f281..ea33499a960 100644 --- a/src/server/scripts/Kalimdor/BlackfathomDeeps/instance_blackfathom_deeps.cpp +++ b/src/server/scripts/Kalimdor/BlackfathomDeeps/instance_blackfathom_deeps.cpp @@ -65,33 +65,33 @@ public: { instance_blackfathom_deeps_InstanceMapScript(Map* map) : InstanceScript(map) {} - uint64 m_uiTwilightLordKelrisGUID; - uint64 m_uiShrine1GUID; - uint64 m_uiShrine2GUID; - uint64 m_uiShrine3GUID; - uint64 m_uiShrine4GUID; - uint64 m_uiShrineOfGelihastGUID; - uint64 m_uiAltarOfTheDeepsGUID; - uint64 m_uiMainDoorGUID; + uint64 twilightLordKelrisGUID; + uint64 shrine1GUID; + uint64 shrine2GUID; + uint64 shrine3GUID; + uint64 shrine4GUID; + uint64 shrineOfGelihastGUID; + uint64 altarOfTheDeepsGUID; + uint64 mainDoorGUID; - uint8 m_auiEncounter[MAX_ENCOUNTER]; - uint8 m_uiCountFires; - uint8 uiDeathTimes; + uint8 encounter[MAX_ENCOUNTER]; + uint8 countFires; + uint8 deathTimes; void Initialize() { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + memset(&encounter, 0, sizeof(encounter)); - m_uiTwilightLordKelrisGUID = 0; - m_uiShrine1GUID = 0; - m_uiShrine2GUID = 0; - m_uiShrine3GUID = 0; - m_uiShrine4GUID = 0; - m_uiShrineOfGelihastGUID = 0; - m_uiAltarOfTheDeepsGUID = 0; - m_uiMainDoorGUID = 0; - m_uiCountFires = 0; - uiDeathTimes = 0; + twilightLordKelrisGUID = 0; + shrine1GUID = 0; + shrine2GUID = 0; + shrine3GUID = 0; + shrine4GUID = 0; + shrineOfGelihastGUID = 0; + altarOfTheDeepsGUID = 0; + mainDoorGUID = 0; + countFires = 0; + deathTimes = 0; } void OnCreatureCreate(Creature* creature) @@ -99,7 +99,7 @@ public: switch (creature->GetEntry()) { case NPC_TWILIGHT_LORD_KELRIS: - m_uiTwilightLordKelrisGUID = creature->GetGUID(); + twilightLordKelrisGUID = creature->GetGUID(); break; case NPC_LORGUS_JETT: creature->SetHomePosition(LorgusPosition[urand(0, 3)]); @@ -112,150 +112,149 @@ public: switch (go->GetEntry()) { case GO_FIRE_OF_AKU_MAI_1: - m_uiShrine1GUID = go->GetGUID(); + shrine1GUID = go->GetGUID(); break; case GO_FIRE_OF_AKU_MAI_2: - m_uiShrine2GUID = go->GetGUID(); + shrine2GUID = go->GetGUID(); break; case GO_FIRE_OF_AKU_MAI_3: - m_uiShrine3GUID = go->GetGUID(); + shrine3GUID = go->GetGUID(); break; case GO_FIRE_OF_AKU_MAI_4: - m_uiShrine4GUID = go->GetGUID(); + shrine4GUID = go->GetGUID(); break; case GO_SHRINE_OF_GELIHAST: - m_uiShrineOfGelihastGUID = go->GetGUID(); - if (m_auiEncounter[0] != DONE) + shrineOfGelihastGUID = go->GetGUID(); + if (encounter[0] != DONE) go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); break; case GO_ALTAR_OF_THE_DEEPS: - m_uiAltarOfTheDeepsGUID = go->GetGUID(); - if (m_auiEncounter[3] != DONE) + altarOfTheDeepsGUID = go->GetGUID(); + if (encounter[3] != DONE) go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); break; case GO_AKU_MAI_DOOR: - if (m_auiEncounter[2] == DONE) + if (encounter[2] == DONE) HandleGameObject(0, true, go); - m_uiMainDoorGUID = go->GetGUID(); + mainDoorGUID = go->GetGUID(); break; } } - void SetData(uint32 uiType, uint32 uiData) + void SetData(uint32 type, uint32 data) { - switch (uiType) + switch (type) { case TYPE_GELIHAST: - m_auiEncounter[0] = uiData; - if (uiData == DONE) - if (GameObject* go = instance->GetGameObject(m_uiShrineOfGelihastGUID)) + encounter[0] = data; + if (data == DONE) + if (GameObject* go = instance->GetGameObject(shrineOfGelihastGUID)) go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); break; case TYPE_AKU_MAI: - m_auiEncounter[3] = uiData; - if (uiData == DONE) - if (GameObject* go = instance->GetGameObject(m_uiAltarOfTheDeepsGUID)) + encounter[3] = data; + if (data == DONE) + if (GameObject* go = instance->GetGameObject(altarOfTheDeepsGUID)) { go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); go->SummonCreature(NPC_MORRIDUNE, SpawnsLocation[4], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); } break; case DATA_FIRE: - m_uiCountFires = uiData; - switch (m_uiCountFires) + countFires = data; + switch (countFires) { case 1: - if (GameObject* pGO = instance->GetGameObject(m_uiShrine1GUID)) + if (GameObject* go = instance->GetGameObject(shrine1GUID)) { - pGO->SummonCreature(NPC_AKU_MAI_SNAPJAW, SpawnsLocation[0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); - pGO->SummonCreature(NPC_AKU_MAI_SNAPJAW, SpawnsLocation[1], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); - pGO->SummonCreature(NPC_AKU_MAI_SNAPJAW, SpawnsLocation[2], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); - pGO->SummonCreature(NPC_AKU_MAI_SNAPJAW, SpawnsLocation[3], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); + go->SummonCreature(NPC_AKU_MAI_SNAPJAW, SpawnsLocation[0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); + go->SummonCreature(NPC_AKU_MAI_SNAPJAW, SpawnsLocation[1], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); + go->SummonCreature(NPC_AKU_MAI_SNAPJAW, SpawnsLocation[2], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); + go->SummonCreature(NPC_AKU_MAI_SNAPJAW, SpawnsLocation[3], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); } break; case 2: - if (GameObject* pGO = instance->GetGameObject(m_uiShrine1GUID)) + if (GameObject* go = instance->GetGameObject(shrine1GUID)) { for (uint8 i = 0; i < 2; ++i) { - pGO->SummonCreature(NPC_MURKSHALLOW_SOFTSHELL, SpawnsLocation[0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); - pGO->SummonCreature(NPC_MURKSHALLOW_SOFTSHELL, SpawnsLocation[1], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); - pGO->SummonCreature(NPC_MURKSHALLOW_SOFTSHELL, SpawnsLocation[2], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); - pGO->SummonCreature(NPC_MURKSHALLOW_SOFTSHELL, SpawnsLocation[3], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); + go->SummonCreature(NPC_MURKSHALLOW_SOFTSHELL, SpawnsLocation[0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); + go->SummonCreature(NPC_MURKSHALLOW_SOFTSHELL, SpawnsLocation[1], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); + go->SummonCreature(NPC_MURKSHALLOW_SOFTSHELL, SpawnsLocation[2], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); + go->SummonCreature(NPC_MURKSHALLOW_SOFTSHELL, SpawnsLocation[3], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); } } break; case 3: - if (GameObject* pGO = instance->GetGameObject(m_uiShrine1GUID)) + if (GameObject* go = instance->GetGameObject(shrine1GUID)) { - pGO->SummonCreature(NPC_AKU_MAI_SERVANT, SpawnsLocation[1], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); - pGO->SummonCreature(NPC_AKU_MAI_SERVANT, SpawnsLocation[2], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); + go->SummonCreature(NPC_AKU_MAI_SERVANT, SpawnsLocation[1], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); + go->SummonCreature(NPC_AKU_MAI_SERVANT, SpawnsLocation[2], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); } break; case 4: - if (GameObject* pGO = instance->GetGameObject(m_uiShrine1GUID)) + if (GameObject* go = instance->GetGameObject(shrine1GUID)) { - pGO->SummonCreature(NPC_BARBED_CRUSTACEAN, SpawnsLocation[0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); - pGO->SummonCreature(NPC_BARBED_CRUSTACEAN, SpawnsLocation[1], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); - pGO->SummonCreature(NPC_BARBED_CRUSTACEAN, SpawnsLocation[2], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); - pGO->SummonCreature(NPC_BARBED_CRUSTACEAN, SpawnsLocation[3], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); + go->SummonCreature(NPC_BARBED_CRUSTACEAN, SpawnsLocation[0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); + go->SummonCreature(NPC_BARBED_CRUSTACEAN, SpawnsLocation[1], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); + go->SummonCreature(NPC_BARBED_CRUSTACEAN, SpawnsLocation[2], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); + go->SummonCreature(NPC_BARBED_CRUSTACEAN, SpawnsLocation[3], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); } break; } break; case DATA_EVENT: - uiDeathTimes = uiData; - if (uiDeathTimes == 18) - HandleGameObject(m_uiMainDoorGUID, true); + deathTimes = data; + if (deathTimes == 18) + HandleGameObject(mainDoorGUID, true); break; } } - uint32 GetData(uint32 uiType) + uint32 GetData(uint32 type) { - switch (uiType) + switch (type) { case TYPE_GELIHAST: - return m_auiEncounter[0]; + return encounter[0]; case TYPE_KELRIS: - return m_auiEncounter[1]; + return encounter[1]; case TYPE_SHRINE: - return m_auiEncounter[2]; + return encounter[2]; case TYPE_AKU_MAI: - return m_auiEncounter[3]; + return encounter[3]; case DATA_FIRE: - return m_uiCountFires; + return countFires; case DATA_EVENT: - return uiDeathTimes; + return deathTimes; } return 0; } - uint64 GetData64(uint32 uiData) + uint64 GetData64(uint32 data) { - switch (uiData) + switch (data) { case DATA_TWILIGHT_LORD_KELRIS: - return m_uiTwilightLordKelrisGUID; + return twilightLordKelrisGUID; case DATA_SHRINE1: - return m_uiShrine1GUID; + return shrine1GUID; case DATA_SHRINE2: - return m_uiShrine2GUID; + return shrine2GUID; case DATA_SHRINE3: - return m_uiShrine3GUID; + return shrine3GUID; case DATA_SHRINE4: - return m_uiShrine4GUID; + return shrine4GUID; case DATA_SHRINE_OF_GELIHAST: - return m_uiShrineOfGelihastGUID; + return shrineOfGelihastGUID; case DATA_MAINDOOR: - return m_uiMainDoorGUID; + return mainDoorGUID; } return 0; } }; - }; void AddSC_instance_blackfathom_deeps() -- cgit v1.2.3 From b83aa17126bc877de5d1d0363194d3361968bb97 Mon Sep 17 00:00:00 2001 From: Bootz Date: Thu, 26 Jan 2012 03:06:48 -0600 Subject: Scripts/Kalimdor: Maraudon * Fixed basic coding standards. - Fixed Enums in Defines. --- .../Kalimdor/Maraudon/boss_celebras_the_cursed.cpp | 21 +++++++++------ .../scripts/Kalimdor/Maraudon/boss_landslide.cpp | 21 +++++++++------ .../scripts/Kalimdor/Maraudon/boss_noxxion.cpp | 23 ++++++++++------- .../Kalimdor/Maraudon/boss_princess_theradras.cpp | 30 ++++++++++++---------- 4 files changed, 57 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/server/scripts/Kalimdor/Maraudon/boss_celebras_the_cursed.cpp b/src/server/scripts/Kalimdor/Maraudon/boss_celebras_the_cursed.cpp index 0010db68673..74e7a919263 100644 --- a/src/server/scripts/Kalimdor/Maraudon/boss_celebras_the_cursed.cpp +++ b/src/server/scripts/Kalimdor/Maraudon/boss_celebras_the_cursed.cpp @@ -25,9 +25,12 @@ EndScriptData */ #include "ScriptPCH.h" -#define SPELL_WRATH 21807 -#define SPELL_ENTANGLINGROOTS 12747 -#define SPELL_CORRUPT_FORCES 21968 +enum Spells +{ + SPELL_WRATH = 21807, + SPELL_ENTANGLINGROOTS = 12747, + SPELL_CORRUPT_FORCES = 21968 +}; class celebras_the_cursed : public CreatureScript { @@ -41,7 +44,7 @@ public: struct celebras_the_cursedAI : public ScriptedAI { - celebras_the_cursedAI(Creature* c) : ScriptedAI(c) {} + celebras_the_cursedAI(Creature* creature) : ScriptedAI(creature) {} uint32 Wrath_Timer; uint32 EntanglingRoots_Timer; @@ -74,14 +77,16 @@ public: if (target) DoCast(target, SPELL_WRATH); Wrath_Timer = 8000; - } else Wrath_Timer -= diff; + } + else Wrath_Timer -= diff; //EntanglingRoots if (EntanglingRoots_Timer <= diff) { DoCast(me->getVictim(), SPELL_ENTANGLINGROOTS); EntanglingRoots_Timer = 20000; - } else EntanglingRoots_Timer -= diff; + } + else EntanglingRoots_Timer -= diff; //CorruptForces if (CorruptForces_Timer <= diff) @@ -89,12 +94,12 @@ public: me->InterruptNonMeleeSpells(false); DoCast(me, SPELL_CORRUPT_FORCES); CorruptForces_Timer = 20000; - } else CorruptForces_Timer -= diff; + } + else CorruptForces_Timer -= diff; DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_celebras_the_cursed() diff --git a/src/server/scripts/Kalimdor/Maraudon/boss_landslide.cpp b/src/server/scripts/Kalimdor/Maraudon/boss_landslide.cpp index fdb5207acd5..418bf3a09ce 100644 --- a/src/server/scripts/Kalimdor/Maraudon/boss_landslide.cpp +++ b/src/server/scripts/Kalimdor/Maraudon/boss_landslide.cpp @@ -25,9 +25,12 @@ EndScriptData */ #include "ScriptPCH.h" -#define SPELL_KNOCKAWAY 18670 -#define SPELL_TRAMPLE 5568 -#define SPELL_LANDSLIDE 21808 +enum Spells +{ + SPELL_KNOCKAWAY = 18670, + SPELL_TRAMPLE = 5568, + SPELL_LANDSLIDE = 21808 +}; class boss_landslide : public CreatureScript { @@ -41,7 +44,7 @@ public: struct boss_landslideAI : public ScriptedAI { - boss_landslideAI(Creature* c) : ScriptedAI(c) {} + boss_landslideAI(Creature* creature) : ScriptedAI(creature) {} uint32 KnockAway_Timer; uint32 Trample_Timer; @@ -68,14 +71,16 @@ public: { DoCast(me->getVictim(), SPELL_KNOCKAWAY); KnockAway_Timer = 15000; - } else KnockAway_Timer -= diff; + } + else KnockAway_Timer -= diff; //Trample_Timer if (Trample_Timer <= diff) { DoCast(me, SPELL_TRAMPLE); Trample_Timer = 8000; - } else Trample_Timer -= diff; + } + else Trample_Timer -= diff; //Landslide if (HealthBelowPct(50)) @@ -85,13 +90,13 @@ public: me->InterruptNonMeleeSpells(false); DoCast(me, SPELL_LANDSLIDE); Landslide_Timer = 60000; - } else Landslide_Timer -= diff; + } + else Landslide_Timer -= diff; } DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_landslide() diff --git a/src/server/scripts/Kalimdor/Maraudon/boss_noxxion.cpp b/src/server/scripts/Kalimdor/Maraudon/boss_noxxion.cpp index 2d4c817ffe2..0e3ee5dc52b 100644 --- a/src/server/scripts/Kalimdor/Maraudon/boss_noxxion.cpp +++ b/src/server/scripts/Kalimdor/Maraudon/boss_noxxion.cpp @@ -24,9 +24,11 @@ SDCategory: Maraudon EndScriptData */ #include "ScriptPCH.h" - -#define SPELL_TOXICVOLLEY 21687 -#define SPELL_UPPERCUT 22916 +enum Spells +{ + SPELL_TOXICVOLLEY = 21687, + SPELL_UPPERCUT = 22916 +}; class boss_noxxion : public CreatureScript { @@ -40,7 +42,7 @@ public: struct boss_noxxionAI : public ScriptedAI { - boss_noxxionAI(Creature* c) : ScriptedAI(c) {} + boss_noxxionAI(Creature* creature) : ScriptedAI(creature) {} uint32 ToxicVolley_Timer; uint32 Uppercut_Timer; @@ -78,7 +80,8 @@ public: me->SetDisplayId(11172); Invisible = false; //me->m_canMove = true; - } else if (Invisible) + } + else if (Invisible) { Invisible_Timer -= diff; //Do nothing while invisible @@ -94,14 +97,16 @@ public: { DoCast(me->getVictim(), SPELL_TOXICVOLLEY); ToxicVolley_Timer = 9000; - } else ToxicVolley_Timer -= diff; + } + else ToxicVolley_Timer -= diff; //Uppercut_Timer if (Uppercut_Timer <= diff) { DoCast(me->getVictim(), SPELL_UPPERCUT); Uppercut_Timer = 12000; - } else Uppercut_Timer -= diff; + } + else Uppercut_Timer -= diff; //Adds_Timer if (!Invisible && Adds_Timer <= diff) @@ -122,12 +127,12 @@ public: Invisible_Timer = 15000; Adds_Timer = 40000; - } else Adds_Timer -= diff; + } + else Adds_Timer -= diff; DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_noxxion() diff --git a/src/server/scripts/Kalimdor/Maraudon/boss_princess_theradras.cpp b/src/server/scripts/Kalimdor/Maraudon/boss_princess_theradras.cpp index cb2c7b320e0..bade5655f36 100644 --- a/src/server/scripts/Kalimdor/Maraudon/boss_princess_theradras.cpp +++ b/src/server/scripts/Kalimdor/Maraudon/boss_princess_theradras.cpp @@ -25,10 +25,13 @@ EndScriptData */ #include "ScriptPCH.h" -#define SPELL_DUSTFIELD 21909 -#define SPELL_BOULDER 21832 -#define SPELL_THRASH 3391 -#define SPELL_REPULSIVEGAZE 21869 +enum Spells +{ + SPELL_DUSTFIELD = 21909, + SPELL_BOULDER = 21832, + SPELL_THRASH = 3391, + SPELL_REPULSIVEGAZE = 21869 +}; class boss_princess_theradras : public CreatureScript { @@ -42,7 +45,7 @@ public: struct boss_ptheradrasAI : public ScriptedAI { - boss_ptheradrasAI(Creature* c) : ScriptedAI(c) {} + boss_ptheradrasAI(Creature* creature) : ScriptedAI(creature) {} uint32 Dustfield_Timer; uint32 Boulder_Timer; @@ -57,9 +60,7 @@ public: RepulsiveGaze_Timer = 23000; } - void EnterCombat(Unit* /*who*/) - { - } + void EnterCombat(Unit* /*who*/) {} void JustDied(Unit* /*killer*/) { @@ -76,7 +77,8 @@ public: { DoCast(me, SPELL_DUSTFIELD); Dustfield_Timer = 14000; - } else Dustfield_Timer -= diff; + } + else Dustfield_Timer -= diff; //Boulder_Timer if (Boulder_Timer <= diff) @@ -86,26 +88,28 @@ public: if (target) DoCast(target, SPELL_BOULDER); Boulder_Timer = 10000; - } else Boulder_Timer -= diff; + } + else Boulder_Timer -= diff; //RepulsiveGaze_Timer if (RepulsiveGaze_Timer <= diff) { DoCast(me->getVictim(), SPELL_REPULSIVEGAZE); RepulsiveGaze_Timer = 20000; - } else RepulsiveGaze_Timer -= diff; + } + else RepulsiveGaze_Timer -= diff; //Thrash_Timer if (Thrash_Timer <= diff) { DoCast(me, SPELL_THRASH); Thrash_Timer = 18000; - } else Thrash_Timer -= diff; + } + else Thrash_Timer -= diff; DoMeleeAttackIfReady(); } }; - }; void AddSC_boss_ptheradras() -- cgit v1.2.3 From c9762b0e385243ec383672e5785b1f45b16bb93b Mon Sep 17 00:00:00 2001 From: Spp Date: Thu, 26 Jan 2012 10:54:53 +0100 Subject: Core: Change Handlers location --- src/server/game/CMakeLists.txt | 4 +- src/server/game/Handlers/AddonHandler.cpp | 142 ++ src/server/game/Handlers/AddonHandler.h | 40 + src/server/game/Handlers/ArenaTeamHandler.cpp | 408 +++++ src/server/game/Handlers/AuctionHouseHandler.cpp | 639 +++++++ src/server/game/Handlers/AuthHandler.cpp | 45 + src/server/game/Handlers/BattleGroundHandler.cpp | 790 ++++++++ src/server/game/Handlers/CalendarHandler.cpp | 309 ++++ src/server/game/Handlers/ChannelHandler.cpp | 302 +++ src/server/game/Handlers/CharacterHandler.cpp | 1915 ++++++++++++++++++++ src/server/game/Handlers/ChatHandler.cpp | 635 +++++++ src/server/game/Handlers/CombatHandler.cpp | 97 + src/server/game/Handlers/DuelHandler.cpp | 79 + src/server/game/Handlers/GroupHandler.cpp | 996 ++++++++++ src/server/game/Handlers/GuildHandler.cpp | 570 ++++++ src/server/game/Handlers/ItemHandler.cpp | 1432 +++++++++++++++ src/server/game/Handlers/LFGHandler.cpp | 664 +++++++ src/server/game/Handlers/LootHandler.cpp | 508 ++++++ src/server/game/Handlers/MailHandler.cpp | 773 ++++++++ src/server/game/Handlers/MiscHandler.cpp | 1729 ++++++++++++++++++ src/server/game/Handlers/MovementHandler.cpp | 573 ++++++ src/server/game/Handlers/NPCHandler.cpp | 909 ++++++++++ src/server/game/Handlers/NPCHandler.h | 59 + src/server/game/Handlers/PetHandler.cpp | 879 +++++++++ src/server/game/Handlers/PetitionsHandler.cpp | 937 ++++++++++ src/server/game/Handlers/QueryHandler.cpp | 477 +++++ src/server/game/Handlers/QuestHandler.cpp | 779 ++++++++ src/server/game/Handlers/ReferAFriendHandler.cpp | 86 + src/server/game/Handlers/SkillHandler.cpp | 93 + src/server/game/Handlers/SpellHandler.cpp | 686 +++++++ src/server/game/Handlers/TaxiHandler.cpp | 294 +++ src/server/game/Handlers/TicketHandler.cpp | 202 +++ src/server/game/Handlers/TradeHandler.cpp | 731 ++++++++ src/server/game/Handlers/VehicleHandler.cpp | 225 +++ src/server/game/Handlers/VoiceChatHandler.cpp | 45 + .../game/Server/Protocol/Handlers/AddonHandler.cpp | 142 -- .../game/Server/Protocol/Handlers/AddonHandler.h | 40 - .../Server/Protocol/Handlers/ArenaTeamHandler.cpp | 408 ----- .../Protocol/Handlers/AuctionHouseHandler.cpp | 639 ------- .../game/Server/Protocol/Handlers/AuthHandler.cpp | 45 - .../Protocol/Handlers/BattleGroundHandler.cpp | 790 -------- .../Server/Protocol/Handlers/CalendarHandler.cpp | 309 ---- .../Server/Protocol/Handlers/ChannelHandler.cpp | 302 --- .../Server/Protocol/Handlers/CharacterHandler.cpp | 1915 -------------------- .../game/Server/Protocol/Handlers/ChatHandler.cpp | 635 ------- .../Server/Protocol/Handlers/CombatHandler.cpp | 97 - .../game/Server/Protocol/Handlers/DuelHandler.cpp | 79 - .../game/Server/Protocol/Handlers/GroupHandler.cpp | 996 ---------- .../game/Server/Protocol/Handlers/GuildHandler.cpp | 570 ------ .../game/Server/Protocol/Handlers/ItemHandler.cpp | 1432 --------------- .../game/Server/Protocol/Handlers/LFGHandler.cpp | 664 ------- .../game/Server/Protocol/Handlers/LootHandler.cpp | 508 ------ .../game/Server/Protocol/Handlers/MailHandler.cpp | 773 -------- .../game/Server/Protocol/Handlers/MiscHandler.cpp | 1729 ------------------ .../Server/Protocol/Handlers/MovementHandler.cpp | 573 ------ .../game/Server/Protocol/Handlers/NPCHandler.cpp | 909 ---------- .../game/Server/Protocol/Handlers/NPCHandler.h | 59 - .../game/Server/Protocol/Handlers/PetHandler.cpp | 879 --------- .../Server/Protocol/Handlers/PetitionsHandler.cpp | 937 ---------- .../game/Server/Protocol/Handlers/QueryHandler.cpp | 477 ----- .../game/Server/Protocol/Handlers/QuestHandler.cpp | 779 -------- .../Protocol/Handlers/ReferAFriendHandler.cpp | 86 - .../game/Server/Protocol/Handlers/SkillHandler.cpp | 93 - .../game/Server/Protocol/Handlers/SpellHandler.cpp | 686 ------- .../game/Server/Protocol/Handlers/TaxiHandler.cpp | 294 --- .../Server/Protocol/Handlers/TicketHandler.cpp | 202 --- .../game/Server/Protocol/Handlers/TradeHandler.cpp | 731 -------- .../Server/Protocol/Handlers/VehicleHandler.cpp | 225 --- .../Server/Protocol/Handlers/VoiceChatHandler.cpp | 45 - src/server/scripts/CMakeLists.txt | 2 +- src/server/worldserver/CMakeLists.txt | 2 +- 71 files changed, 19053 insertions(+), 19051 deletions(-) create mode 100755 src/server/game/Handlers/AddonHandler.cpp create mode 100755 src/server/game/Handlers/AddonHandler.h create mode 100755 src/server/game/Handlers/ArenaTeamHandler.cpp create mode 100755 src/server/game/Handlers/AuctionHouseHandler.cpp create mode 100755 src/server/game/Handlers/AuthHandler.cpp create mode 100755 src/server/game/Handlers/BattleGroundHandler.cpp create mode 100755 src/server/game/Handlers/CalendarHandler.cpp create mode 100755 src/server/game/Handlers/ChannelHandler.cpp create mode 100644 src/server/game/Handlers/CharacterHandler.cpp create mode 100755 src/server/game/Handlers/ChatHandler.cpp create mode 100755 src/server/game/Handlers/CombatHandler.cpp create mode 100755 src/server/game/Handlers/DuelHandler.cpp create mode 100755 src/server/game/Handlers/GroupHandler.cpp create mode 100755 src/server/game/Handlers/GuildHandler.cpp create mode 100755 src/server/game/Handlers/ItemHandler.cpp create mode 100755 src/server/game/Handlers/LFGHandler.cpp create mode 100755 src/server/game/Handlers/LootHandler.cpp create mode 100755 src/server/game/Handlers/MailHandler.cpp create mode 100755 src/server/game/Handlers/MiscHandler.cpp create mode 100755 src/server/game/Handlers/MovementHandler.cpp create mode 100755 src/server/game/Handlers/NPCHandler.cpp create mode 100755 src/server/game/Handlers/NPCHandler.h create mode 100755 src/server/game/Handlers/PetHandler.cpp create mode 100755 src/server/game/Handlers/PetitionsHandler.cpp create mode 100755 src/server/game/Handlers/QueryHandler.cpp create mode 100755 src/server/game/Handlers/QuestHandler.cpp create mode 100644 src/server/game/Handlers/ReferAFriendHandler.cpp create mode 100755 src/server/game/Handlers/SkillHandler.cpp create mode 100755 src/server/game/Handlers/SpellHandler.cpp create mode 100755 src/server/game/Handlers/TaxiHandler.cpp create mode 100755 src/server/game/Handlers/TicketHandler.cpp create mode 100755 src/server/game/Handlers/TradeHandler.cpp create mode 100644 src/server/game/Handlers/VehicleHandler.cpp create mode 100755 src/server/game/Handlers/VoiceChatHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/AddonHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/AddonHandler.h delete mode 100755 src/server/game/Server/Protocol/Handlers/ArenaTeamHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/AuctionHouseHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/AuthHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/BattleGroundHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/CalendarHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp delete mode 100644 src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/ChatHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/CombatHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/DuelHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/GroupHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/GuildHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/ItemHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/LFGHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/LootHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/MailHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/MiscHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/MovementHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/NPCHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/NPCHandler.h delete mode 100755 src/server/game/Server/Protocol/Handlers/PetHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/PetitionsHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/QueryHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/QuestHandler.cpp delete mode 100644 src/server/game/Server/Protocol/Handlers/ReferAFriendHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/SkillHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/SpellHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/TaxiHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/TicketHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/TradeHandler.cpp delete mode 100644 src/server/game/Server/Protocol/Handlers/VehicleHandler.cpp delete mode 100755 src/server/game/Server/Protocol/Handlers/VoiceChatHandler.cpp (limited to 'src') diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index 658e9a15cc8..e97b8961554 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -30,6 +30,7 @@ file(GLOB_RECURSE sources_Globals Globals/*.cpp Globals/*.h) file(GLOB_RECURSE sources_Grids Grids/*.cpp Grids/*.h) file(GLOB_RECURSE sources_Groups Groups/*.cpp Groups/*.h) file(GLOB_RECURSE sources_Guilds Guilds/*.cpp Guilds/*.h) +file(GLOB_RECURSE sources_Handlers Handlers/*.cpp Server/*.h) file(GLOB_RECURSE sources_Instances Instances/*.cpp Instances/*.h) file(GLOB_RECURSE sources_Loot Loot/*.cpp Loot/*.h) file(GLOB_RECURSE sources_Mails Mails/*.cpp Mails/*.h) @@ -79,6 +80,7 @@ set(game_STAT_SRCS ${sources_Grids} ${sources_Groups} ${sources_Guilds} + ${sources_Handlers} ${sources_Instances} ${sources_Loot} ${sources_Mails} @@ -165,6 +167,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/Grids ${CMAKE_CURRENT_SOURCE_DIR}/Groups ${CMAKE_CURRENT_SOURCE_DIR}/Guilds + ${CMAKE_CURRENT_SOURCE_DIR}/Handlers ${CMAKE_CURRENT_SOURCE_DIR}/Instances ${CMAKE_CURRENT_SOURCE_DIR}/Loot ${CMAKE_CURRENT_SOURCE_DIR}/Mails @@ -181,7 +184,6 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/Reputation ${CMAKE_CURRENT_SOURCE_DIR}/Scripting ${CMAKE_CURRENT_SOURCE_DIR}/Server/Protocol - ${CMAKE_CURRENT_SOURCE_DIR}/Server/Protocol/Handlers ${CMAKE_CURRENT_SOURCE_DIR}/Server ${CMAKE_CURRENT_SOURCE_DIR}/Skills ${CMAKE_CURRENT_SOURCE_DIR}/Spells diff --git a/src/server/game/Handlers/AddonHandler.cpp b/src/server/game/Handlers/AddonHandler.cpp new file mode 100755 index 00000000000..ef537cb6198 --- /dev/null +++ b/src/server/game/Handlers/AddonHandler.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "zlib.h" +#include "AddonHandler.h" +#include "DatabaseEnv.h" +#include "Opcodes.h" +#include "Log.h" + +AddonHandler::AddonHandler() +{ +} + +AddonHandler::~AddonHandler() +{ +} + +bool AddonHandler::BuildAddonPacket(WorldPacket* Source, WorldPacket* Target) +{ + ByteBuffer AddOnPacked; + uLongf AddonRealSize; + uint32 CurrentPosition; + uint32 TempValue; + + unsigned char tdata[256] = + { + 0xC3, 0x5B, 0x50, 0x84, 0xB9, 0x3E, 0x32, 0x42, 0x8C, 0xD0, 0xC7, 0x48, 0xFA, 0x0E, 0x5D, 0x54, + 0x5A, 0xA3, 0x0E, 0x14, 0xBA, 0x9E, 0x0D, 0xB9, 0x5D, 0x8B, 0xEE, 0xB6, 0x84, 0x93, 0x45, 0x75, + 0xFF, 0x31, 0xFE, 0x2F, 0x64, 0x3F, 0x3D, 0x6D, 0x07, 0xD9, 0x44, 0x9B, 0x40, 0x85, 0x59, 0x34, + 0x4E, 0x10, 0xE1, 0xE7, 0x43, 0x69, 0xEF, 0x7C, 0x16, 0xFC, 0xB4, 0xED, 0x1B, 0x95, 0x28, 0xA8, + 0x23, 0x76, 0x51, 0x31, 0x57, 0x30, 0x2B, 0x79, 0x08, 0x50, 0x10, 0x1C, 0x4A, 0x1A, 0x2C, 0xC8, + 0x8B, 0x8F, 0x05, 0x2D, 0x22, 0x3D, 0xDB, 0x5A, 0x24, 0x7A, 0x0F, 0x13, 0x50, 0x37, 0x8F, 0x5A, + 0xCC, 0x9E, 0x04, 0x44, 0x0E, 0x87, 0x01, 0xD4, 0xA3, 0x15, 0x94, 0x16, 0x34, 0xC6, 0xC2, 0xC3, + 0xFB, 0x49, 0xFE, 0xE1, 0xF9, 0xDA, 0x8C, 0x50, 0x3C, 0xBE, 0x2C, 0xBB, 0x57, 0xED, 0x46, 0xB9, + 0xAD, 0x8B, 0xC6, 0xDF, 0x0E, 0xD6, 0x0F, 0xBE, 0x80, 0xB3, 0x8B, 0x1E, 0x77, 0xCF, 0xAD, 0x22, + 0xCF, 0xB7, 0x4B, 0xCF, 0xFB, 0xF0, 0x6B, 0x11, 0x45, 0x2D, 0x7A, 0x81, 0x18, 0xF2, 0x92, 0x7E, + 0x98, 0x56, 0x5D, 0x5E, 0x69, 0x72, 0x0A, 0x0D, 0x03, 0x0A, 0x85, 0xA2, 0x85, 0x9C, 0xCB, 0xFB, + 0x56, 0x6E, 0x8F, 0x44, 0xBB, 0x8F, 0x02, 0x22, 0x68, 0x63, 0x97, 0xBC, 0x85, 0xBA, 0xA8, 0xF7, + 0xB5, 0x40, 0x68, 0x3C, 0x77, 0x86, 0x6F, 0x4B, 0xD7, 0x88, 0xCA, 0x8A, 0xD7, 0xCE, 0x36, 0xF0, + 0x45, 0x6E, 0xD5, 0x64, 0x79, 0x0F, 0x17, 0xFC, 0x64, 0xDD, 0x10, 0x6F, 0xF3, 0xF5, 0xE0, 0xA6, + 0xC3, 0xFB, 0x1B, 0x8C, 0x29, 0xEF, 0x8E, 0xE5, 0x34, 0xCB, 0xD1, 0x2A, 0xCE, 0x79, 0xC3, 0x9A, + 0x0D, 0x36, 0xEA, 0x01, 0xE0, 0xAA, 0x91, 0x20, 0x54, 0xF0, 0x72, 0xD8, 0x1E, 0xC7, 0x89, 0xD2 + }; + + // broken addon packet, can't be received from real client + if (Source->rpos() + 4 > Source->size()) + return false; + + *Source >> TempValue; // get real size of the packed structure + + // empty addon packet, nothing process, can't be received from real client + if (!TempValue) + return false; + + AddonRealSize = TempValue; // temp value because ZLIB only excepts uLongf + + CurrentPosition = Source->rpos(); // get the position of the pointer in the structure + + AddOnPacked.resize(AddonRealSize); // resize target for zlib action + + if (!uncompress(const_cast(AddOnPacked.contents()), &AddonRealSize, const_cast((*Source).contents() + CurrentPosition), (*Source).size() - CurrentPosition)!= Z_OK) + { + Target->Initialize(SMSG_ADDON_INFO); + + uint32 addonsCount; + AddOnPacked >> addonsCount; // addons count? + + for (uint32 i = 0; i < addonsCount; ++i) + { + std::string addonName; + uint8 enabled; + uint32 crc, unk2; + + // check next addon data format correctness + if (AddOnPacked.rpos()+1 > AddOnPacked.size()) + return false; + + AddOnPacked >> addonName; + + // recheck next addon data format correctness + if (AddOnPacked.rpos()+1+4+4 > AddOnPacked.size()) + return false; + + AddOnPacked >> enabled >> crc >> unk2; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "ADDON: Name: %s, Enabled: 0x%x, CRC: 0x%x, Unknown2: 0x%x", addonName.c_str(), enabled, crc, unk2); + + uint8 state = (enabled ? 2 : 1); + *Target << uint8(state); + + uint8 unk1 = (enabled ? 1 : 0); + *Target << uint8(unk1); + if (unk1) + { + uint8 unk = (crc != 0x4c1c776d); // If addon is Standard addon CRC + *Target << uint8(unk); + if (unk) + Target->append(tdata, sizeof(tdata)); + + *Target << uint32(0); + } + + uint8 unk3 = (enabled ? 0 : 1); + *Target << uint8(unk3); + if (unk3) + { + // String, 256 (null terminated?) + *Target << uint8(0); + } + } + + uint32 unk4; + AddOnPacked >> unk4; + + uint32 count = 0; + *Target << uint32(count); + + if (AddOnPacked.rpos() != AddOnPacked.size()) + sLog->outDebug(LOG_FILTER_NETWORKIO, "packet under read!"); + } + else + { + sLog->outError("Addon packet uncompress error :("); + return false; + } + return true; +} diff --git a/src/server/game/Handlers/AddonHandler.h b/src/server/game/Handlers/AddonHandler.h new file mode 100755 index 00000000000..36cb19e5698 --- /dev/null +++ b/src/server/game/Handlers/AddonHandler.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef __ADDONHANDLER_H +#define __ADDONHANDLER_H + +#include "Common.h" +#include "Config.h" +#include +#include "WorldPacket.h" + +class AddonHandler +{ + /* Construction */ + friend class ACE_Singleton; + AddonHandler(); + + public: + ~AddonHandler(); + //build addon packet + bool BuildAddonPacket(WorldPacket* Source, WorldPacket* Target); +}; +#define sAddOnHandler ACE_Singleton::instance() +#endif + diff --git a/src/server/game/Handlers/ArenaTeamHandler.cpp b/src/server/game/Handlers/ArenaTeamHandler.cpp new file mode 100755 index 00000000000..8fb820713ce --- /dev/null +++ b/src/server/game/Handlers/ArenaTeamHandler.cpp @@ -0,0 +1,408 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Player.h" +#include "World.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "DatabaseEnv.h" + +#include "ArenaTeam.h" +#include "Log.h" +#include "ObjectMgr.h" +#include "SocialMgr.h" +#include "ArenaTeamMgr.h" + +void WorldSession::HandleInspectArenaTeamsOpcode(WorldPacket & recvData) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "MSG_INSPECT_ARENA_TEAMS"); + + uint64 guid; + recvData >> guid; + sLog->outDebug(LOG_FILTER_NETWORKIO, "Inspect Arena stats (GUID: %u TypeId: %u)", GUID_LOPART(guid), GuidHigh2TypeId(GUID_HIPART(guid))); + + if (Player* player = ObjectAccessor::FindPlayer(guid)) + { + for (uint8 i = 0; i < MAX_ARENA_SLOT; ++i) + { + if (uint32 a_id = player->GetArenaTeamId(i)) + { + if (ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(a_id)) + arenaTeam->Inspect(this, player->GetGUID()); + } + } + } +} + +void WorldSession::HandleArenaTeamQueryOpcode(WorldPacket & recvData) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_ARENA_TEAM_QUERY"); + + uint32 arenaTeamId; + recvData >> arenaTeamId; + + if (ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId)) + { + arenaTeam->Query(this); + arenaTeam->SendStats(this); + } +} + +void WorldSession::HandleArenaTeamRosterOpcode(WorldPacket & recvData) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_ARENA_TEAM_ROSTER"); + + uint32 arenaTeamId; // arena team id + recvData >> arenaTeamId; + + if (ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId)) + arenaTeam->Roster(this); +} + +void WorldSession::HandleArenaTeamInviteOpcode(WorldPacket & recvData) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_ARENA_TEAM_INVITE"); + + uint32 arenaTeamId; // arena team id + std::string invitedName; + + Player* player = NULL; + + recvData >> arenaTeamId >> invitedName; + + if (!invitedName.empty()) + { + if (!normalizePlayerName(invitedName)) + return; + + player = sObjectAccessor->FindPlayerByName(invitedName.c_str()); + } + + if (!player) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", invitedName, ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S); + return; + } + + if (player->getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", player->GetName(), ERR_ARENA_TEAM_TARGET_TOO_LOW_S); + return; + } + + ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId); + if (!arenaTeam) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM); + return; + } + + // OK result but don't send invite + if (player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) + return; + + if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && player->GetTeam() != GetPlayer()->GetTeam()) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); + return; + } + + if (player->GetArenaTeamId(arenaTeam->GetSlot())) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", player->GetName(), ERR_ALREADY_IN_ARENA_TEAM_S); + return; + } + + if (player->GetArenaTeamIdInvited()) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S); + return; + } + + if (arenaTeam->GetMembersSize() >= arenaTeam->GetType() * 2) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, arenaTeam->GetName(), "", ERR_ARENA_TEAM_TOO_MANY_MEMBERS_S); + return; + } + + sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Player %s Invited %s to Join his ArenaTeam", GetPlayer()->GetName(), invitedName.c_str()); + + player->SetArenaTeamIdInvited(arenaTeam->GetId()); + + WorldPacket data(SMSG_ARENA_TEAM_INVITE, (8+10)); + data << GetPlayer()->GetName(); + data << arenaTeam->GetName(); + player->GetSession()->SendPacket(&data); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_ARENA_TEAM_INVITE"); +} + +void WorldSession::HandleArenaTeamAcceptOpcode(WorldPacket & /*recv_data*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_ARENA_TEAM_ACCEPT"); // empty opcode + + ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(_player->GetArenaTeamIdInvited()); + if (!arenaTeam) + return; + + // Check if player is already in another team of the same size + if (_player->GetArenaTeamId(arenaTeam->GetSlot())) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ALREADY_IN_ARENA_TEAM); + return; + } + + // Only allow members of the other faction to join the team if cross faction interaction is enabled + if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && _player->GetTeam() != sObjectMgr->GetPlayerTeamByGUID(arenaTeam->GetCaptain())) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_NOT_ALLIED); + return; + } + + // Add player to team + if (!arenaTeam->AddMember(_player->GetGUID())) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_INTERNAL); + return; + } + + // Broadcast event + arenaTeam->BroadcastEvent(ERR_ARENA_TEAM_JOIN_SS, _player->GetGUID(), 2, _player->GetName(), arenaTeam->GetName(), ""); +} + +void WorldSession::HandleArenaTeamDeclineOpcode(WorldPacket & /*recv_data*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_ARENA_TEAM_DECLINE"); // empty opcode + + // Remove invite from player + _player->SetArenaTeamIdInvited(0); +} + +void WorldSession::HandleArenaTeamLeaveOpcode(WorldPacket & recvData) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_ARENA_TEAM_LEAVE"); + + uint32 arenaTeamId; + recvData >> arenaTeamId; + + ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId); + if (!arenaTeam) + return; + + // Disallow leave team while in arena + if (_player->InArena()) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, "", "", ERR_ARENA_TEAM_INTERNAL); + return; + } + + // Team captain can't leave the team if other members are still present + if (_player->GetGUID() == arenaTeam->GetCaptain() && arenaTeam->GetMembersSize() > 1) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, "", "", ERR_ARENA_TEAM_LEADER_LEAVE_S); + return; + } + + // If team consists only of the captain, disband the team + if (_player->GetGUID() == arenaTeam->GetCaptain()) + { + arenaTeam->Disband(this); + delete arenaTeam; + return; + } + else + arenaTeam->DelMember(_player->GetGUID(), true); + + // Broadcast event + arenaTeam->BroadcastEvent(ERR_ARENA_TEAM_LEAVE_SS, _player->GetGUID(), 2, _player->GetName(), arenaTeam->GetName(), ""); + + // Inform player who left + SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, arenaTeam->GetName(), "", 0); +} + +void WorldSession::HandleArenaTeamDisbandOpcode(WorldPacket & recvData) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_ARENA_TEAM_DISBAND"); + + uint32 arenaTeamId; + recvData >> arenaTeamId; + + if (ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId)) + { + // Only captain can disband the team + if (arenaTeam->GetCaptain() != _player->GetGUID()) + return; + + // Teams cannot be disbanded during fights + if (arenaTeam->IsFighting()) + return; + + arenaTeam->Disband(this); + delete arenaTeam; + } +} + +void WorldSession::HandleArenaTeamRemoveOpcode(WorldPacket & recvData) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_ARENA_TEAM_REMOVE"); + + uint32 arenaTeamId; + std::string name; + + recvData >> arenaTeamId; + recvData >> name; + + // Check for valid arena team + ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId); + if (!arenaTeam) + return; + + // Only captain can remove members + if (arenaTeam->GetCaptain() != _player->GetGUID()) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS); + return; + } + + if (!normalizePlayerName(name)) + return; + + // Check if team member exists + ArenaTeamMember* member = arenaTeam->GetMember(name); + if (!member) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", name, ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S); + return; + } + + // Captain cannot be removed + if (arenaTeam->GetCaptain() == member->Guid) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, "", "", ERR_ARENA_TEAM_LEADER_LEAVE_S); + return; + } + + arenaTeam->DelMember(member->Guid, true); + + // Broadcast event + arenaTeam->BroadcastEvent(ERR_ARENA_TEAM_REMOVE_SSS, 0, 3, name, arenaTeam->GetName(), _player->GetName()); +} + +void WorldSession::HandleArenaTeamLeaderOpcode(WorldPacket & recvData) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_ARENA_TEAM_LEADER"); + + uint32 arenaTeamId; + std::string name; + + recvData >> arenaTeamId; + recvData >> name; + + // Check for valid arena team + ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId); + if (!arenaTeam) + return; + + // Only captain can pass leadership + if (arenaTeam->GetCaptain() != _player->GetGUID()) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS); + return; + } + + if (!normalizePlayerName(name)) + return; + + // Check if team member exists + ArenaTeamMember* member = arenaTeam->GetMember(name); + if (!member) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", name, ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S); + return; + } + + // Check if the target is already team captain + if (arenaTeam->GetCaptain() == member->Guid) + return; + + arenaTeam->SetCaptain(member->Guid); + + // Broadcast event + arenaTeam->BroadcastEvent(ERR_ARENA_TEAM_LEADER_CHANGED_SSS, 0, 3, _player->GetName(), name, arenaTeam->GetName()); +} + +void WorldSession::SendArenaTeamCommandResult(uint32 teamAction, const std::string& team, const std::string& player, uint32 errorId) +{ + WorldPacket data(SMSG_ARENA_TEAM_COMMAND_RESULT, 4+team.length()+1+player.length()+1+4); + data << uint32(teamAction); + data << team; + data << player; + data << uint32(errorId); + SendPacket(&data); +} + +void WorldSession::SendNotInArenaTeamPacket(uint8 type) +{ + WorldPacket data(SMSG_ARENA_ERROR, 4+1); // 886 - You are not in a %uv%u arena team + uint32 unk = 0; + data << uint32(unk); // unk(0) + if (!unk) + data << uint8(type); // team type (2=2v2, 3=3v3, 5=5v5), can be used for custom types... + SendPacket(&data); +} + +/* ++ERR_ARENA_NO_TEAM_II "You are not in a %dv%d arena team" + ++ERR_ARENA_TEAM_CREATE_S "%s created. To disband, use /teamdisband [2v2, 3v3, 5v5]." ++ERR_ARENA_TEAM_INVITE_SS "You have invited %s to join %s" ++ERR_ARENA_TEAM_QUIT_S "You are no longer a member of %s" +ERR_ARENA_TEAM_FOUNDER_S "Congratulations, you are a founding member of %s! To leave, use /teamquit [2v2, 3v3, 5v5]." + ++ERR_ARENA_TEAM_INTERNAL "Internal arena team error" ++ERR_ALREADY_IN_ARENA_TEAM "You are already in an arena team of that size" ++ERR_ALREADY_IN_ARENA_TEAM_S "%s is already in an arena team of that size" ++ERR_INVITED_TO_ARENA_TEAM "You have already been invited into an arena team" ++ERR_ALREADY_INVITED_TO_ARENA_TEAM_S "%s has already been invited to an arena team" ++ERR_ARENA_TEAM_NAME_INVALID "That name contains invalid characters, please enter a new name" ++ERR_ARENA_TEAM_NAME_EXISTS_S "There is already an arena team named \"%s\"" ++ERR_ARENA_TEAM_LEADER_LEAVE_S "You must promote a new team captain using /teamcaptain before leaving the team" ++ERR_ARENA_TEAM_PERMISSIONS "You don't have permission to do that" ++ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM "You are not in an arena team of that size" ++ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM_SS "%s is not in %s" ++ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S "\"%s\" not found" ++ERR_ARENA_TEAM_NOT_ALLIED "You cannot invite players from the opposing alliance" + ++ERR_ARENA_TEAM_JOIN_SS "%s has joined %s" ++ERR_ARENA_TEAM_YOU_JOIN_S "You have joined %s. To leave, use /teamquit [2v2, 3v3, 5v5]." + ++ERR_ARENA_TEAM_LEAVE_SS "%s has left %s" + ++ERR_ARENA_TEAM_LEADER_IS_SS "%s is the captain of %s" ++ERR_ARENA_TEAM_LEADER_CHANGED_SSS "%s has made %s the new captain of %s" + ++ERR_ARENA_TEAM_REMOVE_SSS "%s has been kicked out of %s by %s" + ++ERR_ARENA_TEAM_DISBANDED_S "%s has disbanded %s" + +ERR_ARENA_TEAM_TARGET_TOO_LOW_S "%s is not high enough level to join your team" + +ERR_ARENA_TEAM_TOO_MANY_MEMBERS_S "%s is full" + +ERR_ARENA_TEAM_LEVEL_TOO_LOW_I "You must be level %d to form an arena team" +*/ diff --git a/src/server/game/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp new file mode 100755 index 00000000000..59eefb9fa77 --- /dev/null +++ b/src/server/game/Handlers/AuctionHouseHandler.cpp @@ -0,0 +1,639 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "ObjectMgr.h" +#include "Player.h" +#include "World.h" +#include "WorldPacket.h" +#include "WorldSession.h" + +#include "AuctionHouseMgr.h" +#include "Log.h" +#include "Opcodes.h" +#include "UpdateMask.h" +#include "Util.h" +#include "AccountMgr.h" + +//please DO NOT use iterator++, because it is slower than ++iterator!!! +//post-incrementation is always slower than pre-incrementation ! + +//void called when player click on auctioneer npc +void WorldSession::HandleAuctionHelloOpcode(WorldPacket & recv_data) +{ + uint64 guid; //NPC guid + recv_data >> guid; + + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_AUCTIONEER); + if (!unit) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + SendAuctionHello(guid, unit); +} + +//this void causes that auction window is opened +void WorldSession::SendAuctionHello(uint64 guid, Creature* unit) +{ + if (GetPlayer()->getLevel() < sWorld->getIntConfig(CONFIG_AUCTION_LEVEL_REQ)) + { + SendNotification(GetTrinityString(LANG_AUCTION_REQ), sWorld->getIntConfig(CONFIG_AUCTION_LEVEL_REQ)); + return; + } + + AuctionHouseEntry const* ahEntry = AuctionHouseMgr::GetAuctionHouseEntry(unit->getFaction()); + if (!ahEntry) + return; + + WorldPacket data(MSG_AUCTION_HELLO, 12); + data << uint64(guid); + data << uint32(ahEntry->houseId); + data << uint8(1); // 3.3.3: 1 - AH enabled, 0 - AH disabled + SendPacket(&data); +} + +//call this method when player bids, creates, or deletes auction +void WorldSession::SendAuctionCommandResult(uint32 auctionId, uint32 Action, uint32 ErrorCode, uint32 bidError) +{ + WorldPacket data(SMSG_AUCTION_COMMAND_RESULT, 16); + data << auctionId; + data << Action; + data << ErrorCode; + if (!ErrorCode && Action) + data << bidError; //when bid, then send 0, once... + SendPacket(&data); +} + +//this function sends notification, if bidder is online +void WorldSession::SendAuctionBidderNotification(uint32 location, uint32 auctionId, uint64 bidder, uint32 bidSum, uint32 diff, uint32 item_template) +{ + WorldPacket data(SMSG_AUCTION_BIDDER_NOTIFICATION, (8*4)); + data << uint32(location); + data << uint32(auctionId); + data << uint64(bidder); + data << uint32(bidSum); + data << uint32(diff); + data << uint32(item_template); + data << uint32(0); + SendPacket(&data); +} + +//this void causes on client to display: "Your auction sold" +void WorldSession::SendAuctionOwnerNotification(AuctionEntry* auction) +{ + WorldPacket data(SMSG_AUCTION_OWNER_NOTIFICATION, (8*4)); + data << uint32(auction->Id); + data << uint32(auction->bid); + data << uint32(0); //unk + data << uint64(0); //unk (bidder guid?) + data << uint32(auction->item_template); + data << uint32(0); //unk + data << float(0); //unk (time?) + SendPacket(&data); +} + +//this void creates new auction and adds auction to some auctionhouse +void WorldSession::HandleAuctionSellItem(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_SELL_ITEM"); + + uint64 auctioneer, item; + uint32 etime, bid, buyout, count; + recv_data >> auctioneer; + recv_data.read_skip(); // const 1? + recv_data >> item; + recv_data >> count; // 3.2.2, number of items being auctioned + recv_data >> bid; + recv_data >> buyout; + recv_data >> etime; + + Player* player = GetPlayer(); + + if (!item || !bid || !etime) + return; //check for cheaters + + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); + if (!creature) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionSellItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); + return; + } + + AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(creature->getFaction()); + if (!auctionHouseEntry) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionSellItem - Unit (GUID: %u) has wrong faction.", uint32(GUID_LOPART(auctioneer))); + return; + } + + // client send time in minutes, convert to common used sec time + etime *= MINUTE; + + // client understand only 3 auction time + switch (etime) + { + case 1*MIN_AUCTION_TIME: + case 2*MIN_AUCTION_TIME: + case 4*MIN_AUCTION_TIME: + break; + default: + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + Item* it = player->GetItemByGuid(item); + //do not allow to sell already auctioned items + if (sAuctionMgr->GetAItem(GUID_LOPART(item))) + { + sLog->outError("AuctionError, player %s is sending item id: %u, but item is already in another auction", player->GetName(), GUID_LOPART(item)); + SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); + return; + } + // prevent sending bag with items (cheat: can be placed in bag after adding equiped empty bag to auction) + if (!it) + { + SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_ITEM_NOT_FOUND); + return; + } + + if (!it->CanBeTraded()) + { + SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); + return; + } + + if (it->GetTemplate()->Flags & ITEM_PROTO_FLAG_CONJURED || it->GetUInt32Value(ITEM_FIELD_DURATION)) + { + SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); + return; + } + + if (it->IsNotEmptyBag()) + { + SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); + return; + } + + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); + + //we have to take deposit : + uint32 deposit = sAuctionMgr->GetAuctionDeposit(auctionHouseEntry, etime, it, count); + if (!player->HasEnoughMoney(deposit)) + { + SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_NOT_ENOUGHT_MONEY); + return; + } + + if (AccountMgr::IsGMAccount(GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) + { + sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", + GetPlayerName(), GetAccountId(), it->GetTemplate()->Name1.c_str(), it->GetEntry(), count); + } + + player->ModifyMoney(-int32(deposit)); + + uint32 auction_time = uint32(etime * sWorld->getRate(RATE_AUCTION_TIME)); + + AuctionEntry* AH = new AuctionEntry; + AH->Id = sObjectMgr->GenerateAuctionID(); + if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) + AH->auctioneer = 23442; + else + AH->auctioneer = GUID_LOPART(auctioneer); + AH->item_guidlow = GUID_LOPART(item); + AH->item_template = it->GetEntry(); + AH->owner = player->GetGUIDLow(); + AH->startbid = bid; + AH->bidder = 0; + AH->bid = 0; + AH->buyout = buyout; + AH->expire_time = time(NULL) + auction_time; + AH->deposit = deposit; + AH->auctionHouseEntry = auctionHouseEntry; + + sLog->outDetail("selling item %u to auctioneer %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u", GUID_LOPART(item), AH->auctioneer, bid, buyout, auction_time, AH->GetHouseId()); + sAuctionMgr->AddAItem(it); + auctionHouse->AddAuction(AH); + + player->MoveItemFromInventory(it->GetBagSlot(), it->GetSlot(), true); + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + it->DeleteFromInventoryDB(trans); + it->SaveToDB(trans); // recursive and not have transaction guard into self, not in inventiory and can be save standalone + AH->SaveToDB(trans); + player->SaveInventoryAndGoldToDB(trans); + CharacterDatabase.CommitTransaction(trans); + + SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, AUCTION_OK); + + GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); +} + +//this function is called when client bids or buys out auction +void WorldSession::HandleAuctionPlaceBid(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_PLACE_BID"); + + uint64 auctioneer; + uint32 auctionId; + uint32 price; + recv_data >> auctioneer; + recv_data >> auctionId >> price; + + if (!auctionId || !price) + return; //check for cheaters + + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); + if (!creature) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionPlaceBid - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); + + AuctionEntry* auction = auctionHouse->GetAuction(auctionId); + Player* player = GetPlayer(); + + if (!auction || auction->owner == player->GetGUIDLow()) + { + //you cannot bid your own auction: + SendAuctionCommandResult(0, AUCTION_PLACE_BID, CANNOT_BID_YOUR_AUCTION_ERROR); + return; + } + + // impossible have online own another character (use this for speedup check in case online owner) + Player* auction_owner = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)); + if (!auction_owner && sObjectMgr->GetPlayerAccountIdByGUID(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)) == player->GetSession()->GetAccountId()) + { + //you cannot bid your another character auction: + SendAuctionCommandResult(0, AUCTION_PLACE_BID, CANNOT_BID_YOUR_AUCTION_ERROR); + return; + } + + // cheating + if (price <= auction->bid || price < auction->startbid) + return; + + // price too low for next bid if not buyout + if ((price < auction->buyout || auction->buyout == 0) && + price < auction->bid + auction->GetAuctionOutBid()) + { + //auction has already higher bid, client tests it! + return; + } + + if (!player->HasEnoughMoney(price)) + { + //you don't have enought money!, client tests! + //SendAuctionCommandResult(auction->auctionId, AUCTION_PLACE_BID, ???); + return; + } + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + + if (price < auction->buyout || auction->buyout == 0) + { + if (auction->bidder > 0) + { + if (auction->bidder == player->GetGUIDLow()) + player->ModifyMoney(-int32(price - auction->bid)); + else + { + // mail to last bidder and return money + sAuctionMgr->SendAuctionOutbiddedMail(auction, price, GetPlayer(), trans); + player->ModifyMoney(-int32(price)); + } + } + else + player->ModifyMoney(-int32(price)); + + auction->bidder = player->GetGUIDLow(); + auction->bid = price; + GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, price); + + trans->PAppend("UPDATE auctionhouse SET buyguid = '%u', lastbid = '%u' WHERE id = '%u'", auction->bidder, auction->bid, auction->Id); + + SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, AUCTION_OK, 0); + } + else + { + //buyout: + if (player->GetGUIDLow() == auction->bidder) + player->ModifyMoney(-int32(auction->buyout - auction->bid)); + else + { + player->ModifyMoney(-int32(auction->buyout)); + if (auction->bidder) //buyout for bidded auction .. + sAuctionMgr->SendAuctionOutbiddedMail(auction, auction->buyout, GetPlayer(), trans); + } + auction->bidder = player->GetGUIDLow(); + auction->bid = auction->buyout; + GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, auction->buyout); + + //- Mails must be under transaction control too to prevent data loss + sAuctionMgr->SendAuctionSalePendingMail(auction, trans); + sAuctionMgr->SendAuctionSuccessfulMail(auction, trans); + sAuctionMgr->SendAuctionWonMail(auction, trans); + + SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, AUCTION_OK); + + auction->DeleteFromDB(trans); + + uint32 item_template = auction->item_template; + sAuctionMgr->RemoveAItem(auction->item_guidlow); + auctionHouse->RemoveAuction(auction, item_template); + } + player->SaveInventoryAndGoldToDB(trans); + CharacterDatabase.CommitTransaction(trans); +} + +//this void is called when auction_owner cancels his auction +void WorldSession::HandleAuctionRemoveItem(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_REMOVE_ITEM"); + + uint64 auctioneer; + uint32 auctionId; + recv_data >> auctioneer; + recv_data >> auctionId; + //sLog->outDebug("Cancel AUCTION AuctionID: %u", auctionId); + + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); + if (!creature) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionRemoveItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); + + AuctionEntry* auction = auctionHouse->GetAuction(auctionId); + Player* player = GetPlayer(); + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + if (auction && auction->owner == player->GetGUIDLow()) + { + Item* pItem = sAuctionMgr->GetAItem(auction->item_guidlow); + if (pItem) + { + if (auction->bidder > 0) // If we have a bidder, we have to send him the money he paid + { + uint32 auctionCut = auction->GetAuctionCut(); + if (!player->HasEnoughMoney(auctionCut)) //player doesn't have enough money, maybe message needed + return; + //some auctionBidderNotification would be needed, but don't know that parts.. + sAuctionMgr->SendAuctionCancelledToBidderMail(auction, trans); + player->ModifyMoney(-int32(auctionCut)); + } + // Return the item by mail + std::ostringstream msgAuctionCanceledOwner; + msgAuctionCanceledOwner << auction->item_template << ":0:" << AUCTION_CANCELED << ":0:0"; + + // item will deleted or added to received mail list + MailDraft(msgAuctionCanceledOwner.str(), "") // TODO: fix body + .AddItem(pItem) + .SendMailTo(trans, player, auction, MAIL_CHECK_MASK_COPIED); + } + else + { + sLog->outError("Auction id: %u has non-existed item (item guid : %u)!!!", auction->Id, auction->item_guidlow); + SendAuctionCommandResult(0, AUCTION_CANCEL, AUCTION_INTERNAL_ERROR); + return; + } + } + else + { + SendAuctionCommandResult(0, AUCTION_CANCEL, AUCTION_INTERNAL_ERROR); + //this code isn't possible ... maybe there should be assert + sLog->outError("CHEATER : %u, he tried to cancel auction (id: %u) of another player, or auction is NULL", player->GetGUIDLow(), auctionId); + return; + } + + //inform player, that auction is removed + SendAuctionCommandResult(auction->Id, AUCTION_CANCEL, AUCTION_OK); + + // Now remove the auction + + player->SaveInventoryAndGoldToDB(trans); + auction->DeleteFromDB(trans); + CharacterDatabase.CommitTransaction(trans); + + uint32 item_template = auction->item_template; + sAuctionMgr->RemoveAItem(auction->item_guidlow); + auctionHouse->RemoveAuction(auction, item_template); +} + +//called when player lists his bids +void WorldSession::HandleAuctionListBidderItems(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_LIST_BIDDER_ITEMS"); + + uint64 guid; //NPC guid + uint32 listfrom; //page of auctions + uint32 outbiddedCount; //count of outbidded auctions + + recv_data >> guid; + recv_data >> listfrom; // not used in fact (this list not have page control in client) + recv_data >> outbiddedCount; + if (recv_data.size() != (16 + outbiddedCount * 4)) + { + sLog->outError("Client sent bad opcode!!! with count: %u and size : %lu (must be: %u)", outbiddedCount, (unsigned long)recv_data.size(), (16 + outbiddedCount * 4)); + outbiddedCount = 0; + } + + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_AUCTIONEER); + if (!creature) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionListBidderItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + recv_data.rfinish(); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); + + WorldPacket data(SMSG_AUCTION_BIDDER_LIST_RESULT, (4+4+4)); + Player* player = GetPlayer(); + data << (uint32) 0; //add 0 as count + uint32 count = 0; + uint32 totalcount = 0; + while (outbiddedCount > 0) //add all data, which client requires + { + --outbiddedCount; + uint32 outbiddedAuctionId; + recv_data >> outbiddedAuctionId; + AuctionEntry* auction = auctionHouse->GetAuction(outbiddedAuctionId); + if (auction && auction->BuildAuctionInfo(data)) + { + ++totalcount; + ++count; + } + } + + auctionHouse->BuildListBidderItems(data, player, count, totalcount); + data.put(0, count); // add count to placeholder + data << totalcount; + data << (uint32)300; //unk 2.3.0 + SendPacket(&data); +} + +//this void sends player info about his auctions +void WorldSession::HandleAuctionListOwnerItems(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_LIST_OWNER_ITEMS"); + + uint32 listfrom; + uint64 guid; + + recv_data >> guid; + recv_data >> listfrom; // not used in fact (this list not have page control in client) + + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_AUCTIONEER); + if (!creature) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionListOwnerItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); + + WorldPacket data(SMSG_AUCTION_OWNER_LIST_RESULT, (4+4+4)); + data << (uint32) 0; // amount place holder + + uint32 count = 0; + uint32 totalcount = 0; + + auctionHouse->BuildListOwnerItems(data, _player, count, totalcount); + data.put(0, count); + data << (uint32) totalcount; + data << (uint32) 0; + SendPacket(&data); +} + +//this void is called when player clicks on search button +void WorldSession::HandleAuctionListItems(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_LIST_ITEMS"); + + std::string searchedname; + uint8 levelmin, levelmax, usable; + uint32 listfrom, auctionSlotID, auctionMainCategory, auctionSubCategory, quality; + uint64 guid; + + recv_data >> guid; + recv_data >> listfrom; // start, used for page control listing by 50 elements + recv_data >> searchedname; + + recv_data >> levelmin >> levelmax; + recv_data >> auctionSlotID >> auctionMainCategory >> auctionSubCategory; + recv_data >> quality >> usable; + + recv_data.read_skip(); // unk + + // this block looks like it uses some lame byte packing or similar... + uint8 unkCnt; + recv_data >> unkCnt; + for (uint8 i = 0; i < unkCnt; i++) + { + recv_data.read_skip(); + recv_data.read_skip(); + } + + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_AUCTIONEER); + if (!creature) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionListItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); + + //sLog->outDebug("Auctionhouse search (GUID: %u TypeId: %u)",, list from: %u, searchedname: %s, levelmin: %u, levelmax: %u, auctionSlotID: %u, auctionMainCategory: %u, auctionSubCategory: %u, quality: %u, usable: %u", + // GUID_LOPART(guid), GuidHigh2TypeId(GUID_HIPART(guid)), listfrom, searchedname.c_str(), levelmin, levelmax, auctionSlotID, auctionMainCategory, auctionSubCategory, quality, usable); + + WorldPacket data(SMSG_AUCTION_LIST_RESULT, (4+4+4)); + uint32 count = 0; + uint32 totalcount = 0; + data << (uint32) 0; + + // converting string that we try to find to lower case + std::wstring wsearchedname; + if (!Utf8toWStr(searchedname, wsearchedname)) + return; + + wstrToLower(wsearchedname); + + auctionHouse->BuildListAuctionItems(data, _player, + wsearchedname, listfrom, levelmin, levelmax, usable, + auctionSlotID, auctionMainCategory, auctionSubCategory, quality, + count, totalcount); + + data.put(0, count); + data << (uint32) totalcount; + data << (uint32) 300; // unk 2.3.0 const? + SendPacket(&data); +} + +void WorldSession::HandleAuctionListPendingSales(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_LIST_PENDING_SALES"); + + recv_data.read_skip(); + + uint32 count = 0; + + WorldPacket data(SMSG_AUCTION_LIST_PENDING_SALES, 4); + data << uint32(count); // count + /*for (uint32 i = 0; i < count; ++i) + { + data << ""; // string + data << ""; // string + data << uint32(0); + data << uint32(0); + data << float(0); + }*/ + SendPacket(&data); +} diff --git a/src/server/game/Handlers/AuthHandler.cpp b/src/server/game/Handlers/AuthHandler.cpp new file mode 100755 index 00000000000..9a3e756dda3 --- /dev/null +++ b/src/server/game/Handlers/AuthHandler.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Opcodes.h" +#include "WorldSession.h" +#include "WorldPacket.h" + +void WorldSession::SendAuthResponse(uint8 code, bool shortForm, uint32 queuePos) +{ + WorldPacket packet(SMSG_AUTH_RESPONSE, 1 + 4 + 1 + 4 + 1 + (shortForm ? 0 : (4 + 1))); + packet << uint8(code); + packet << uint32(0); // BillingTimeRemaining + packet << uint8(0); // BillingPlanFlags + packet << uint32(0); // BillingTimeRested + packet << uint8(Expansion()); // 0 - normal, 1 - TBC, 2 - WOTLK, must be set in database manually for each account + + if (!shortForm) + { + packet << uint32(queuePos); // Queue position + packet << uint8(0); // Unk 3.3.0 + } + + SendPacket(&packet); +} + +void WorldSession::SendClientCacheVersion(uint32 version) +{ + WorldPacket data(SMSG_CLIENTCACHE_VERSION, 4); + data << uint32(version); + SendPacket(&data); +} diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp new file mode 100755 index 00000000000..d1aa0021a75 --- /dev/null +++ b/src/server/game/Handlers/BattleGroundHandler.cpp @@ -0,0 +1,790 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "ObjectAccessor.h" +#include "ObjectMgr.h" +#include "ArenaTeamMgr.h" +#include "WorldPacket.h" +#include "WorldSession.h" + +#include "ArenaTeam.h" +#include "BattlegroundMgr.h" +#include "Battleground.h" +#include "Chat.h" +#include "Language.h" +#include "Log.h" +#include "Player.h" +#include "Object.h" +#include "Opcodes.h" +#include "DisableMgr.h" +#include "Group.h" + +void WorldSession::HandleBattlemasterHelloOpcode(WorldPacket & recv_data) +{ + uint64 guid; + recv_data >> guid; + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_BATTLEMASTER_HELLO Message from (GUID: %u TypeId:%u)", GUID_LOPART(guid), GuidHigh2TypeId(GUID_HIPART(guid))); + + Creature* unit = GetPlayer()->GetMap()->GetCreature(guid); + if (!unit) + return; + + if (!unit->isBattleMaster()) // it's not battlemaster + return; + + // Stop the npc if moving + unit->StopMoving(); + + BattlegroundTypeId bgTypeId = sBattlegroundMgr->GetBattleMasterBG(unit->GetEntry()); + + if (!_player->GetBGAccessByLevel(bgTypeId)) + { + // temp, must be gossip message... + SendNotification(LANG_YOUR_BG_LEVEL_REQ_ERROR); + return; + } + + SendBattlegGroundList(guid, bgTypeId); +} + +void WorldSession::SendBattlegGroundList(uint64 guid, BattlegroundTypeId bgTypeId) +{ + WorldPacket data; + sBattlegroundMgr->BuildBattlegroundListPacket(&data, guid, _player, bgTypeId, 0); + SendPacket(&data); +} + +void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket & recv_data) +{ + uint64 guid; + uint32 bgTypeId_; + uint32 instanceId; + uint8 joinAsGroup; + bool isPremade = false; + Group* grp = NULL; + + recv_data >> guid; // battlemaster guid + recv_data >> bgTypeId_; // battleground type id (DBC id) + recv_data >> instanceId; // instance id, 0 if First Available selected + recv_data >> joinAsGroup; // join as group + + if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) + { + sLog->outError("Battleground: invalid bgtype (%u) received. possible cheater? player guid %u", bgTypeId_, _player->GetGUIDLow()); + return; + } + + if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeId_, NULL)) + { + ChatHandler(this).PSendSysMessage(LANG_BG_DISABLED); + return; + } + + BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from (GUID: %u TypeId:%u)", GUID_LOPART(guid), GuidHigh2TypeId(GUID_HIPART(guid))); + + // can do this, since it's battleground, not arena + BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, 0); + BattlegroundQueueTypeId bgQueueTypeIdRandom = BattlegroundMgr::BGQueueTypeId(BATTLEGROUND_RB, 0); + + // ignore if player is already in BG + if (_player->InBattleground()) + return; + + // get bg instance or bg template if instance not found + Battleground* bg = NULL; + if (instanceId) + bg = sBattlegroundMgr->GetBattlegroundThroughClientInstance(instanceId, bgTypeId); + + if (!bg) + bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); + if (!bg) + return; + + // expected bracket entry + PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); + if (!bracketEntry) + return; + + GroupJoinBattlegroundResult err; + + // check queue conditions + if (!joinAsGroup) + { + if (GetPlayer()->isUsingLfg()) + { + // player is using dungeon finder or raid finder + WorldPacket data; + sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_LFG_CANT_USE_BATTLEGROUND); + GetPlayer()->GetSession()->SendPacket(&data); + return; + } + + // check Deserter debuff + if (!_player->CanJoinToBattleground()) + { + WorldPacket data; + sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); + _player->GetSession()->SendPacket(&data); + return; + } + + if (_player->GetBattlegroundQueueIndex(bgQueueTypeIdRandom) < PLAYER_MAX_BATTLEGROUND_QUEUES) + { + //player is already in random queue + WorldPacket data; + sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_IN_RANDOM_BG); + _player->GetSession()->SendPacket(&data); + return; + } + + if (_player->InBattlegroundQueue() && bgTypeId == BATTLEGROUND_RB) + { + //player is already in queue, can't start random queue + WorldPacket data; + sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_IN_NON_RANDOM_BG); + _player->GetSession()->SendPacket(&data); + return; + } + + // check if already in queue + if (_player->GetBattlegroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES) + //player is already in this queue + return; + + // check if has free queue slots + if (!_player->HasFreeBattlegroundQueueId()) + { + WorldPacket data; + sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_TOO_MANY_QUEUES); + _player->GetSession()->SendPacket(&data); + return; + } + + BattlegroundQueue& bgQueue = sBattlegroundMgr->m_BattlegroundQueues[bgQueueTypeId]; + + GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0); + uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); + // already checked if queueSlot is valid, now just get it + uint32 queueSlot = _player->AddBattlegroundQueueId(bgQueueTypeId); + + WorldPacket data; + // send status packet (in queue) + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType); + SendPacket(&data); + sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, _player->GetGUIDLow(), _player->GetName()); + } + else + { + grp = _player->GetGroup(); + // no group found, error + if (!grp) + return; + if (grp->GetLeaderGUID() != _player->GetGUID()) + return; + err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0); + isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam()); + + BattlegroundQueue& bgQueue = sBattlegroundMgr->m_BattlegroundQueues[bgQueueTypeId]; + GroupQueueInfo* ginfo = NULL; + uint32 avgTime = 0; + + if (err > 0) + { + sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: the following players are joining as group:"); + ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0); + avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); + } + + for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* member = itr->getSource(); + if (!member) continue; // this should never happen + + WorldPacket data; + + if (err <= 0) + { + sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); + member->GetSession()->SendPacket(&data); + continue; + } + + // add to queue + uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId); + + // send status packet (in queue) + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType); + member->GetSession()->SendPacket(&data); + sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); + member->GetSession()->SendPacket(&data); + sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, member->GetGUIDLow(), member->GetName()); + } + sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: group end"); + + } + sBattlegroundMgr->ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); +} + +void WorldSession::HandleBattlegroundPlayerPositionsOpcode(WorldPacket & /*recv_data*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd MSG_BATTLEGROUND_PLAYER_POSITIONS Message"); + + Battleground* bg = _player->GetBattleground(); + if (!bg) // can't be received if player not in battleground + return; + + uint32 count = 0; + Player* aplr = NULL; + Player* hplr = NULL; + + if (uint64 guid = bg->GetFlagPickerGUID(BG_TEAM_ALLIANCE)) + { + aplr = ObjectAccessor::FindPlayer(guid); + if (aplr) + ++count; + } + + if (uint64 guid = bg->GetFlagPickerGUID(BG_TEAM_HORDE)) + { + hplr = ObjectAccessor::FindPlayer(guid); + if (hplr) + ++count; + } + + WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, 4 + 4 + 16 * count); + data << 0; + data << count; + if (aplr) + { + data << uint64(aplr->GetGUID()); + data << float(aplr->GetPositionX()); + data << float(aplr->GetPositionY()); + } + + if (hplr) + { + data << uint64(hplr->GetGUID()); + data << float(hplr->GetPositionX()); + data << float(hplr->GetPositionY()); + } + + SendPacket(&data); +} + +void WorldSession::HandlePVPLogDataOpcode(WorldPacket & /*recv_data*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd MSG_PVP_LOG_DATA Message"); + + Battleground* bg = _player->GetBattleground(); + if (!bg) + return; + + // Prevent players from sending BuildPvpLogDataPacket in an arena except for when sent in BattleGround::EndBattleGround. + if (bg->isArena()) + return; + + WorldPacket data; + sBattlegroundMgr->BuildPvpLogDataPacket(&data, bg); + SendPacket(&data); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent MSG_PVP_LOG_DATA Message"); +} + +void WorldSession::HandleBattlefieldListOpcode(WorldPacket &recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message"); + + uint32 bgTypeId; + recv_data >> bgTypeId; // id from DBC + + uint8 fromWhere; + recv_data >> fromWhere; // 0 - battlemaster (lua: ShowBattlefieldList), 1 - UI (lua: RequestBattlegroundInstanceInfo) + + uint8 unk1; + recv_data >> unk1; // Unknown 3.2.2 + + BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId); + if (!bl) + { + sLog->outDebug(LOG_FILTER_BATTLEGROUND, "BattlegroundHandler: invalid bgtype (%u) with player (Name: %s, GUID: %u) received.", bgTypeId, _player->GetName(), _player->GetGUIDLow()); + return; + } + + WorldPacket data; + sBattlegroundMgr->BuildBattlegroundListPacket(&data, 0, _player, BattlegroundTypeId(bgTypeId), fromWhere); + SendPacket(&data); +} + +void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message"); + + uint8 type; // arenatype if arena + uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1 + uint32 bgTypeId_; // type id from dbc + uint16 unk; // 0x1F90 constant? + uint8 action; // enter battle 0x1, leave queue 0x0 + + recv_data >> type >> unk2 >> bgTypeId_ >> unk >> action; + + if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) + { + sLog->outDebug(LOG_FILTER_BATTLEGROUND, "BattlegroundHandler: invalid bgtype (%u) with player (Name: %s, GUID: %u) received.", bgTypeId_, _player->GetName(), _player->GetGUIDLow()); + return; + } + + if (!_player->InBattlegroundQueue()) + { + sLog->outDebug(LOG_FILTER_BATTLEGROUND, "BattlegroundHandler: Invalid CMSG_BATTLEFIELD_PORT received from player (Name: %s, GUID: %u), he is not in bg_queue.", _player->GetName(), _player->GetGUIDLow()); + return; + } + + //get GroupQueueInfo from BattlegroundQueue + BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_); + BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, type); + BattlegroundQueue& bgQueue = sBattlegroundMgr->m_BattlegroundQueues[bgQueueTypeId]; + //we must use temporary variable, because GroupQueueInfo pointer can be deleted in BattlegroundQueue::RemovePlayer() function + GroupQueueInfo ginfo; + if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) + { + sLog->outError("BattlegroundHandler: itrplayerstatus not found."); + return; + } + // if action == 1, then instanceId is required + if (!ginfo.IsInvitedToBGInstanceGUID && action == 1) + { + sLog->outError("BattlegroundHandler: instance not found."); + return; + } + + Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); + + // bg template might and must be used in case of leaving queue, when instance is not created yet + if (!bg && action == 0) + bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); + if (!bg) + { + sLog->outError("BattlegroundHandler: bg_template not found for type id %u.", bgTypeId); + return; + } + + // expected bracket entry + PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); + if (!bracketEntry) + return; + + //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it + if (action == 1 && ginfo.ArenaType == 0) + { + //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue + if (!_player->CanJoinToBattleground()) + { + //send bg command result to show nice message + WorldPacket data2; + sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data2, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); + _player->GetSession()->SendPacket(&data2); + action = 0; + sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); + } + //if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue + if (_player->getLevel() > bg->GetMaxLevel()) + { + sLog->outError("Battleground: Player %s (%u) has level (%u) higher than maxlevel (%u) of battleground (%u)! Do not port him to battleground!", + _player->GetName(), _player->GetGUIDLow(), _player->getLevel(), bg->GetMaxLevel(), bg->GetTypeID()); + action = 0; + } + } + uint32 queueSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId); + WorldPacket data; + switch (action) + { + case 1: // port to battleground + if (!_player->IsInvitedForBattlegroundQueueType(bgQueueTypeId)) + return; // cheating? + + if (!_player->InBattleground()) + _player->SetBattlegroundEntryPoint(); + + // resurrect the player + if (!_player->isAlive()) + { + _player->ResurrectPlayer(1.0f); + _player->SpawnCorpseBones(); + } + // stop taxi flight at port + if (_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->CleanupAfterTaxiFlight(); + } + + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType()); + _player->GetSession()->SendPacket(&data); + // remove battleground queue status from BGmgr + bgQueue.RemovePlayer(_player->GetGUID(), false); + // this is still needed here if battleground "jumping" shouldn't add deserter debuff + // also this is required to prevent stuck at old battleground after SetBattlegroundId set to new + if (Battleground* currentBg = _player->GetBattleground()) + currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true); + + // set the destination instance id + _player->SetBattlegroundId(bg->GetInstanceID(), bgTypeId); + // set the destination team + _player->SetBGTeam(ginfo.Team); + // bg->HandleBeforeTeleportToBattleground(_player); + sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId); + // add only in HandleMoveWorldPortAck() + // bg->AddPlayer(_player, team); + sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetInstanceID(), bg->GetTypeID(), bgQueueTypeId); + break; + case 0: // leave queue + // if player leaves rated arena match before match start, it is counted as he played but he lost + if (ginfo.IsRated && ginfo.IsInvitedToBGInstanceGUID) + { + ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(ginfo.Team); + if (at) + { + sLog->outDebug(LOG_FILTER_BATTLEGROUND, "UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), ginfo.OpponentsTeamRating); + at->MemberLost(_player, ginfo.OpponentsMatchmakerRating); + at->SaveToDB(); + } + } + _player->RemoveBattlegroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); + bgQueue.RemovePlayer(_player->GetGUID(), true); + // player left queue, we should update it - do not update Arena Queue + if (!ginfo.ArenaType) + sBattlegroundMgr->ScheduleQueueUpdate(ginfo.ArenaMatchmakerRating, ginfo.ArenaType, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); + SendPacket(&data); + sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId); + break; + default: + sLog->outError("Battleground port: unknown action %u", action); + break; + } +} + +void WorldSession::HandleLeaveBattlefieldOpcode(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_LEAVE_BATTLEFIELD Message"); + + recv_data.read_skip(); // unk1 + recv_data.read_skip(); // unk2 + recv_data.read_skip(); // BattlegroundTypeId + recv_data.read_skip(); // unk3 + + // not allow leave battleground in combat + if (_player->isInCombat()) + if (Battleground* bg = _player->GetBattleground()) + if (bg->GetStatus() != STATUS_WAIT_LEAVE) + return; + + _player->LeaveBattleground(); +} + +void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recv_data*/) +{ + // empty opcode + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Battleground status"); + + WorldPacket data; + // we must update all queues here + Battleground* bg = NULL; + for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) + { + BattlegroundQueueTypeId bgQueueTypeId = _player->GetBattlegroundQueueTypeId(i); + if (!bgQueueTypeId) + continue; + BattlegroundTypeId bgTypeId = BattlegroundMgr::BGTemplateId(bgQueueTypeId); + uint8 arenaType = BattlegroundMgr::BGArenaType(bgQueueTypeId); + if (bgTypeId == _player->GetBattlegroundTypeId()) + { + bg = _player->GetBattleground(); + //i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena + //so i must use bg pointer to get that information + if (bg && bg->GetArenaType() == arenaType) + { + // this line is checked, i only don't know if GetStartTime is changing itself after bg end! + // send status in Battleground + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType); + SendPacket(&data); + continue; + } + } + //we are sending update to player about queue - he can be invited there! + //get GroupQueueInfo for queue status + BattlegroundQueue& bgQueue = sBattlegroundMgr->m_BattlegroundQueues[bgQueueTypeId]; + GroupQueueInfo ginfo; + if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) + continue; + if (ginfo.IsInvitedToBGInstanceGUID) + { + bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); + if (!bg) + continue; + uint32 remainingTime = getMSTimeDiff(getMSTime(), ginfo.RemoveInviteTime); + // send status invited to Battleground + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType); + SendPacket(&data); + } + else + { + bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); + if (!bg) + continue; + + // expected bracket entry + PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); + if (!bracketEntry) + continue; + + uint32 avgTime = bgQueue.GetAverageQueueWaitTime(&ginfo, bracketEntry->GetBracketId()); + // send status in Battleground Queue + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(ginfo.JoinTime, getMSTime()), arenaType); + SendPacket(&data); + } + } +} + +void WorldSession::HandleAreaSpiritHealerQueryOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AREA_SPIRIT_HEALER_QUERY"); + + Battleground* bg = _player->GetBattleground(); + + uint64 guid; + recv_data >> guid; + + Creature* unit = GetPlayer()->GetMap()->GetCreature(guid); + if (!unit) + return; + + if (!unit->isSpiritService()) // it's not spirit service + return; + + if (bg) + sBattlegroundMgr->SendAreaSpiritHealerQueryOpcode(_player, bg, guid); +} + +void WorldSession::HandleAreaSpiritHealerQueueOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AREA_SPIRIT_HEALER_QUEUE"); + + Battleground* bg = _player->GetBattleground(); + + uint64 guid; + recv_data >> guid; + + Creature* unit = GetPlayer()->GetMap()->GetCreature(guid); + if (!unit) + return; + + if (!unit->isSpiritService()) // it's not spirit service + return; + + if (bg) + bg->AddPlayerToResurrectQueue(guid, _player->GetGUID()); +} + +void WorldSession::HandleBattlemasterJoinArena(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_BATTLEMASTER_JOIN_ARENA"); + + uint64 guid; // arena Battlemaster guid + uint8 arenaslot; // 2v2, 3v3 or 5v5 + uint8 asGroup; // asGroup + uint8 isRated; // isRated + Group* grp = NULL; + + recv_data >> guid >> arenaslot >> asGroup >> isRated; + + // ignore if we already in BG or BG queue + if (_player->InBattleground()) + return; + + Creature* unit = GetPlayer()->GetMap()->GetCreature(guid); + if (!unit) + return; + + if (!unit->isBattleMaster()) // it's not battle master + return; + + uint8 arenatype = 0; + uint32 arenaRating = 0; + uint32 matchmakerRating = 0; + + switch (arenaslot) + { + case 0: + arenatype = ARENA_TYPE_2v2; + break; + case 1: + arenatype = ARENA_TYPE_3v3; + break; + case 2: + arenatype = ARENA_TYPE_5v5; + break; + default: + sLog->outError("Unknown arena slot %u at HandleBattlemasterJoinArena()", arenaslot); + return; + } + + //check existance + Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(BATTLEGROUND_AA); + if (!bg) + { + sLog->outError("Battleground: template bg (all arenas) not found"); + return; + } + + if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, BATTLEGROUND_AA, NULL)) + { + ChatHandler(this).PSendSysMessage(LANG_ARENA_DISABLED); + return; + } + + BattlegroundTypeId bgTypeId = bg->GetTypeID(); + BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, arenatype); + PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); + if (!bracketEntry) + return; + + GroupJoinBattlegroundResult err = ERR_GROUP_JOIN_BATTLEGROUND_FAIL; + + if (!asGroup) + { + // check if already in queue + if (_player->GetBattlegroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES) + //player is already in this queue + return; + // check if has free queue slots + if (!_player->HasFreeBattlegroundQueueId()) + return; + } + else + { + grp = _player->GetGroup(); + // no group found, error + if (!grp) + return; + if (grp->GetLeaderGUID() != _player->GetGUID()) + return; + err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, arenatype, arenatype, (bool)isRated, arenaslot); + } + + uint32 ateamId = 0; + + if (isRated) + { + ateamId = _player->GetArenaTeamId(arenaslot); + // check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice) + ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(ateamId); + if (!at) + { + _player->GetSession()->SendNotInArenaTeamPacket(arenatype); + return; + } + // get the team rating for queueing + arenaRating = at->GetRating(); + matchmakerRating = at->GetAverageMMR(grp); + // the arenateam id must match for everyone in the group + + if (arenaRating <= 0) + arenaRating = 1; + } + + BattlegroundQueue &bgQueue = sBattlegroundMgr->m_BattlegroundQueues[bgQueueTypeId]; + if (asGroup) + { + uint32 avgTime = 0; + + if (err > 0) + { + sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: arena join as group start"); + if (isRated) + { + sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: arena team id %u, leader %s queued with matchmaker rating %u for type %u", _player->GetArenaTeamId(arenaslot), _player->GetName(), matchmakerRating, arenatype); + bg->SetRated(true); + } + else + bg->SetRated(false); + + GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, arenatype, isRated, false, arenaRating, matchmakerRating, ateamId); + avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); + } + + for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* member = itr->getSource(); + if (!member) + continue; + + WorldPacket data; + + if (err <= 0) + { + sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); + member->GetSession()->SendPacket(&data); + continue; + } + + // add to queue + uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId); + + // send status packet (in queue) + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype); + member->GetSession()->SendPacket(&data); + sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); + member->GetSession()->SendPacket(&data); + sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player joined queue for arena as group bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, member->GetGUIDLow(), member->GetName()); + } + } + else + { + GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, arenatype, isRated, false, arenaRating, matchmakerRating, ateamId); + uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); + uint32 queueSlot = _player->AddBattlegroundQueueId(bgQueueTypeId); + + WorldPacket data; + // send status packet (in queue) + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype); + SendPacket(&data); + sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player joined queue for arena, skirmish, bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, _player->GetGUIDLow(), _player->GetName()); + } + sBattlegroundMgr->ScheduleQueueUpdate(matchmakerRating, arenatype, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); +} + +void WorldSession::HandleReportPvPAFK(WorldPacket & recv_data) +{ + uint64 playerGuid; + recv_data >> playerGuid; + Player* reportedPlayer = ObjectAccessor::FindPlayer(playerGuid); + + if (!reportedPlayer) + { + sLog->outDebug(LOG_FILTER_BATTLEGROUND, "WorldSession::HandleReportPvPAFK: player not found"); + return; + } + + sLog->outDebug(LOG_FILTER_BATTLEGROUND, "WorldSession::HandleReportPvPAFK: %s reported %s", _player->GetName(), reportedPlayer->GetName()); + + reportedPlayer->ReportedAfkBy(_player); +} diff --git a/src/server/game/Handlers/CalendarHandler.cpp b/src/server/game/Handlers/CalendarHandler.cpp new file mode 100755 index 00000000000..be547c84b19 --- /dev/null +++ b/src/server/game/Handlers/CalendarHandler.cpp @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "WorldPacket.h" +#include "WorldSession.h" + +#include "InstanceSaveMgr.h" +#include "Log.h" +#include "Opcodes.h" +#include "Player.h" + +void WorldSession::HandleCalendarGetCalendar(WorldPacket& /*recv_data*/) +{ + uint64 guid = _player->GetGUID(); + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_CALENDAR_GET_CALENDAR [" UI64FMTD "]", guid); + + time_t cur_time = time_t(time(NULL)); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_CALENDAR_SEND_CALENDAR [" UI64FMTD "]", guid); + WorldPacket data(SMSG_CALENDAR_SEND_CALENDAR, 4+4*0+4+4*0+4+4); + + data << uint32(0); // invite count + /* + for (;;) + { + uint64 inviteId; + uint64 unkGuid0; + uint8 unk1, unk2, unk3; + uint64 creatorGuid; + } + */ + + data << uint32(0); // event count + /* + for (;;) + { + uint64 eventId; + std::string title; // 128 chars + uint32 type; + uint32 occurrenceTime; + uint32 flags; + uint32 unk4; -- possibly mapid for dungeon/raid + uint64 creatorGuid; + } + */ + + data << uint32(cur_time); // server time + data << uint32(secsToTimeBitFields(cur_time)); // server time + + uint32 counter = 0; + size_t p_counter = data.wpos(); + data << uint32(counter); // instance save count + + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) + for (Player::BoundInstancesMap::const_iterator itr = _player->m_boundInstances[i].begin(); itr != _player->m_boundInstances[i].end(); ++itr) + if (itr->second.perm) + { + InstanceSave const* save = itr->second.save; + data << uint32(save->GetMapId()); + data << uint32(save->GetDifficulty()); + data << uint32(save->GetResetTime() - cur_time); + data << uint64(save->GetInstanceId()); // instance save id as unique instance copy id + ++counter; + } + + data.put(p_counter, counter); + + data << uint32(1135753200); // unk (28.12.2005 07:00) + + counter = 0; + p_counter = data.wpos(); + data << uint32(counter); // raid reset count + + std::set sentMaps; + + ResetTimeByMapDifficultyMap const& resets = sInstanceSaveMgr->GetResetTimeMap(); + for (ResetTimeByMapDifficultyMap::const_iterator itr = resets.begin(); itr != resets.end(); ++itr) + { + uint32 mapId = PAIR32_LOPART(itr->first); + + if (sentMaps.find(mapId) != sentMaps.end()) + continue; + + MapEntry const* mapEntry = sMapStore.LookupEntry(mapId); + if (!mapEntry || !mapEntry->IsRaid()) + continue; + + sentMaps.insert(mapId); + + data << uint32(mapId); + data << uint32(itr->second - cur_time); + data << uint32(mapEntry->unk_time); + ++counter; + } + + data.put(p_counter, counter); + + data << uint32(0); // holiday count? + /* + for (;;) + { + uint32 unk5, unk6, unk7, unk8, unk9; + for (uint32 j = 0; j < 26; ++j) + { + uint32 unk10; + } + for (uint32 j = 0; j < 10; ++j) + { + uint32 unk11; + } + for (uint32 j = 0; j < 10; ++j) + { + uint32 unk12; + } + std::string holidayName; // 64 chars + } + */ + + SendPacket(&data); +} + +void WorldSession::HandleCalendarGetEvent(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_GET_EVENT"); + recv_data.read_skip(); // unk +} + +void WorldSession::HandleCalendarGuildFilter(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_GUILD_FILTER"); + recv_data.read_skip(); // unk1 + recv_data.read_skip(); // unk2 + recv_data.read_skip(); // unk3 +} + +void WorldSession::HandleCalendarArenaTeam(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_ARENA_TEAM"); + recv_data.read_skip(); // unk +} + +void WorldSession::HandleCalendarAddEvent(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_ADD_EVENT"); + recv_data.rfinish(); // set to end to avoid warnings spam + + //std::string unk1, unk2; + //recv_data >> (std::string)unk1; + //recv_data >> (std::string)unk2; + + //uint8 unk3, unk4; + //uint32 unk5, unk6, unk7, unk8, unk9, count = 0; + //recv_data >> (uint8)unk3; + //recv_data >> (uint8)unk4; + //recv_data >> (uint32)unk5; + //recv_data >> (uint32)unk6; + //recv_data >> (uint32)unk7; + //recv_data >> (uint32)unk8; + //recv_data >> (uint32)unk9; + //if (!((unk9 >> 6) & 1)) + //{ + // recv_data >> (uint32)count; + // if (count) + // { + // uint8 unk12, unk13; + // uint64 guid; + // for (int i=0; i> (uint8)unk12; + // recv_data >> (uint8)unk13; + // } + // } + //} +} + +void WorldSession::HandleCalendarUpdateEvent(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_UPDATE_EVENT"); + recv_data.rfinish(); // set to end to avoid warnings spam + + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> std::string + //recv_data >> std::string + //recv_data >> uint8 + //recv_data >> uint8 + //recv_data >> uint32 + //recv_data >> uint32 + //recv_data >> uint32 + //recv_data >> uint32 + //recv_data >> uint32 +} + +void WorldSession::HandleCalendarRemoveEvent(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_REMOVE_EVENT"); + recv_data.rfinish(); // set to end to avoid warnings spam + + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> uint32 + +} + +void WorldSession::HandleCalendarCopyEvent(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_COPY_EVENT"); + recv_data.rfinish(); // set to end to avoid warnings spam + + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> uint32 + +} + +void WorldSession::HandleCalendarEventInvite(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_EVENT_INVITE"); + recv_data.rfinish(); // set to end to avoid warnings spam + + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> std::string + //recv_data >> uint8 + //recv_data >> uint8 + +} + +void WorldSession::HandleCalendarEventRsvp(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_EVENT_RSVP"); + recv_data.rfinish(); // set to end to avoid warnings spam + + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> uint32 + +} + +void WorldSession::HandleCalendarEventRemoveInvite(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_EVENT_REMOVE_INVITE"); + recv_data.rfinish(); // set to end to avoid warnings spam + + //recv_data.readPackGUID(guid) + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> uint64 +} + +void WorldSession::HandleCalendarEventStatus(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_EVENT_STATUS"); + recv_data.rfinish(); // set to end to avoid warnings spam + + //recv_data.readPackGUID(guid) + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> uint32 +} + +void WorldSession::HandleCalendarEventModeratorStatus(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_EVENT_MODERATOR_STATUS"); + recv_data.rfinish(); // set to end to avoid warnings spam + + //recv_data.readPackGUID(guid) + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> uint32 +} + +void WorldSession::HandleCalendarComplain(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_COMPLAIN"); + recv_data.rfinish(); // set to end to avoid warnings spam + + //recv_data >> uint64 + //recv_data >> uint64 + //recv_data >> uint64 +} + +void WorldSession::HandleCalendarGetNumPending(WorldPacket& /*recv_data*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_GET_NUM_PENDING"); // empty + + WorldPacket data(SMSG_CALENDAR_SEND_NUM_PENDING, 4); + data << uint32(0); // 0 - no pending invites, 1 - some pending invites + SendPacket(&data); +} diff --git a/src/server/game/Handlers/ChannelHandler.cpp b/src/server/game/Handlers/ChannelHandler.cpp new file mode 100755 index 00000000000..9b749fa8005 --- /dev/null +++ b/src/server/game/Handlers/ChannelHandler.cpp @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "ObjectMgr.h" // for normalizePlayerName +#include "ChannelMgr.h" + +void WorldSession::HandleJoinChannel(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); + + uint32 channel_id; + uint8 unknown1, unknown2; + std::string channelname, pass; + + recvPacket >> channel_id; + recvPacket >> unknown1 >> unknown2; + recvPacket >> channelname; + recvPacket >> pass; + + if (channel_id) + { + ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(channel_id); + if (!channel) + return; + + AreaTableEntry const* current_zone = GetAreaEntryByAreaID(_player->GetZoneId()); + if (!current_zone) + return; + + if (!_player->CanJoinConstantChannelInZone(channel, current_zone)) + return; + } + + if (channelname.empty()) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + { + cMgr->team = _player->GetTeam(); + if (Channel* chn = cMgr->GetJoinChannel(channelname, channel_id)) + chn->Join(_player->GetGUID(), pass.c_str()); + } +} + +void WorldSession::HandleLeaveChannel(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); + + uint32 unk; + std::string channelname; + recvPacket >> unk; // channel id? + recvPacket >> channelname; + + if (channelname.empty()) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + { + if (Channel* chn = cMgr->GetChannel(channelname, _player)) + chn->Leave(_player->GetGUID(), true); + cMgr->LeftChannel(channelname); + } +} + +void WorldSession::HandleChannelList(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); + std::string channelname; + recvPacket >> channelname; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel* chn = cMgr->GetChannel(channelname, _player)) + chn->List(_player); +} + +void WorldSession::HandleChannelPassword(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); + std::string channelname, pass; + recvPacket >> channelname; + + recvPacket >> pass; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel* chn = cMgr->GetChannel(channelname, _player)) + chn->Password(_player->GetGUID(), pass.c_str()); +} + +void WorldSession::HandleChannelSetOwner(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); + std::string channelname, newp; + recvPacket >> channelname; + + recvPacket >> newp; + + if (!normalizePlayerName(newp)) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel* chn = cMgr->GetChannel(channelname, _player)) + chn->SetOwner(_player->GetGUID(), newp.c_str()); +} + +void WorldSession::HandleChannelOwner(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); + std::string channelname; + recvPacket >> channelname; + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel* chn = cMgr->GetChannel(channelname, _player)) + chn->SendWhoOwner(_player->GetGUID()); +} + +void WorldSession::HandleChannelModerator(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); + std::string channelname, otp; + recvPacket >> channelname; + + recvPacket >> otp; + + if (!normalizePlayerName(otp)) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel* chn = cMgr->GetChannel(channelname, _player)) + chn->SetModerator(_player->GetGUID(), otp.c_str()); +} + +void WorldSession::HandleChannelUnmoderator(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); + std::string channelname, otp; + recvPacket >> channelname; + + recvPacket >> otp; + + if (!normalizePlayerName(otp)) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel* chn = cMgr->GetChannel(channelname, _player)) + chn->UnsetModerator(_player->GetGUID(), otp.c_str()); +} + +void WorldSession::HandleChannelMute(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); + std::string channelname, otp; + recvPacket >> channelname; + + recvPacket >> otp; + + if (!normalizePlayerName(otp)) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel* chn = cMgr->GetChannel(channelname, _player)) + chn->SetMute(_player->GetGUID(), otp.c_str()); +} + +void WorldSession::HandleChannelUnmute(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); + + std::string channelname, otp; + recvPacket >> channelname; + + recvPacket >> otp; + + if (!normalizePlayerName(otp)) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel* chn = cMgr->GetChannel(channelname, _player)) + chn->UnsetMute(_player->GetGUID(), otp.c_str()); +} + +void WorldSession::HandleChannelInvite(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); + std::string channelname, otp; + recvPacket >> channelname; + + recvPacket >> otp; + + if (!normalizePlayerName(otp)) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel* chn = cMgr->GetChannel(channelname, _player)) + chn->Invite(_player->GetGUID(), otp.c_str()); +} + +void WorldSession::HandleChannelKick(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); + std::string channelname, otp; + recvPacket >> channelname; + + recvPacket >> otp; + if (!normalizePlayerName(otp)) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel* chn = cMgr->GetChannel(channelname, _player)) + chn->Kick(_player->GetGUID(), otp.c_str()); +} + +void WorldSession::HandleChannelBan(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); + std::string channelname, otp; + recvPacket >> channelname; + + recvPacket >> otp; + + if (!normalizePlayerName(otp)) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel* chn = cMgr->GetChannel(channelname, _player)) + chn->Ban(_player->GetGUID(), otp.c_str()); +} + +void WorldSession::HandleChannelUnban(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); + + std::string channelname, otp; + recvPacket >> channelname; + + recvPacket >> otp; + + if (!normalizePlayerName(otp)) + return; + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel* chn = cMgr->GetChannel(channelname, _player)) + chn->UnBan(_player->GetGUID(), otp.c_str()); +} + +void WorldSession::HandleChannelAnnouncements(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); + std::string channelname; + recvPacket >> channelname; + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel* chn = cMgr->GetChannel(channelname, _player)) + chn->Announce(_player->GetGUID()); +} + +void WorldSession::HandleChannelDisplayListQuery(WorldPacket &recvPacket) +{ + // this should be OK because the 2 function _were_ the same + HandleChannelList(recvPacket); +} + +void WorldSession::HandleGetChannelMemberCount(WorldPacket &recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); + std::string channelname; + recvPacket >> channelname; + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + { + if (Channel* chn = cMgr->GetChannel(channelname, _player)) + { + WorldPacket data(SMSG_CHANNEL_MEMBER_COUNT, chn->GetName().size()+1+1+4); + data << chn->GetName(); + data << uint8(chn->GetFlags()); + data << uint32(chn->GetNumPlayers()); + SendPacket(&data); + } + } +} + +void WorldSession::HandleSetChannelWatch(WorldPacket &recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); + std::string channelname; + recvPacket >> channelname; + /*if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + if (Channel* chn = cMgr->GetChannel(channelname, _player)) + chn->JoinNotify(_player->GetGUID());*/ +} + diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp new file mode 100644 index 00000000000..bd9668ce5b8 --- /dev/null +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -0,0 +1,1915 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "ObjectAccessor.h" +#include "ObjectMgr.h" +#include "ArenaTeamMgr.h" +#include "GuildMgr.h" +#include "SystemConfig.h" +#include "World.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "DatabaseEnv.h" + +#include "ArenaTeam.h" +#include "Chat.h" +#include "Group.h" +#include "Guild.h" +#include "Language.h" +#include "Log.h" +#include "Opcodes.h" +#include "Player.h" +#include "PlayerDump.h" +#include "SharedDefines.h" +#include "SocialMgr.h" +#include "UpdateMask.h" +#include "Util.h" +#include "ScriptMgr.h" +#include "Battleground.h" +#include "AccountMgr.h" +#include "LFGMgr.h" + +class LoginQueryHolder : public SQLQueryHolder +{ + private: + uint32 m_accountId; + uint64 m_guid; + public: + LoginQueryHolder(uint32 accountId, uint64 guid) + : m_accountId(accountId), m_guid(guid) { } + uint64 GetGuid() const { return m_guid; } + uint32 GetAccountId() const { return m_accountId; } + bool Initialize(); +}; + +bool LoginQueryHolder::Initialize() +{ + SetSize(MAX_PLAYER_LOGIN_QUERY); + + bool res = true; + uint32 lowGuid = GUID_LOPART(m_guid); + PreparedStatement* stmt = NULL; + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADFROM, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GROUP_MEMBER); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADGROUP, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_INSTANCE); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_AURAS); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADAURAS, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SPELL); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADSPELLS, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUS); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_DAILYQUESTSTATUS); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_WEEKLYQUESTSTATUS); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADWEEKLYQUESTSTATUS, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SEASONALQUESTSTATUS); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADSEASONALQUESTSTATUS, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_REPUTATION); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADREPUTATION, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_INVENTORY); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADINVENTORY, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACTIONS); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADACTIONS, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MAILCOUNT); + stmt->setUInt32(0, lowGuid); + stmt->setUInt64(1, uint64(time(NULL))); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADMAILCOUNT, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MAILDATE); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADMAILDATE, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SOCIALLIST); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADSOCIALLIST, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_HOMEBIND); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADHOMEBIND, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADSPELLCOOLDOWNS, stmt); + + if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED)) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_DECLINEDNAMES); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES, stmt); + } + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADGUILD, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ARENAINFO); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADARENAINFO, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACHIEVEMENTS); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADACHIEVEMENTS, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_CRITERIAPROGRESS); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADCRITERIAPROGRESS, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_EQUIPMENTSETS); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADEQUIPMENTSETS, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_BGDATA); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADBGDATA, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GLYPHS); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADGLYPHS, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_TALENTS); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADTALENTS, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PLAYER_ACCOUNT_DATA); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADACCOUNTDATA, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SKILLS); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADSKILLS, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_RANDOMBG); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADRANDOMBG, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_BANNED); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADBANNED, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUSREW); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADQUESTSTATUSREW, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES); + stmt->setUInt32(0, m_accountId); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADINSTANCELOCKTIMES, stmt); + + return res; +} + +void WorldSession::HandleCharEnum(PreparedQueryResult result) +{ + WorldPacket data(SMSG_CHAR_ENUM, 100); // we guess size + + uint8 num = 0; + + data << num; + + _allowedCharsToLogin.clear(); + if (result) + { + do + { + uint32 guidlow = (*result)[0].GetUInt32(); + sLog->outDetail("Loading char guid %u from account %u.", guidlow, GetAccountId()); + if (Player::BuildEnumData(result, &data)) + { + _allowedCharsToLogin.insert(guidlow); + ++num; + } + } + while (result->NextRow()); + } + + data.put(0, num); + + SendPacket(&data); +} + +void WorldSession::HandleCharEnumOpcode(WorldPacket & /*recv_data*/) +{ + // remove expired bans + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_EXPIRED_BANS); + CharacterDatabase.Execute(stmt); + + /// get all the data necessary for loading all characters (along with their pets) on the account + + if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED)) + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ENUM_DECLINED_NAME); + else + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ENUM); + + stmt->setUInt8(0, PET_SAVE_AS_CURRENT); + stmt->setUInt32(1, GetAccountId()); + + _charEnumCallback = CharacterDatabase.AsyncQuery(stmt); +} + +void WorldSession::HandleCharCreateOpcode(WorldPacket & recv_data) +{ + std::string name; + uint8 race_, class_; + + recv_data >> name; + + recv_data >> race_; + recv_data >> class_; + + // extract other data required for player creating + uint8 gender, skin, face, hairStyle, hairColor, facialHair, outfitId; + recv_data >> gender >> skin >> face; + recv_data >> hairStyle >> hairColor >> facialHair >> outfitId; + + WorldPacket data(SMSG_CHAR_CREATE, 1); // returned with diff.values in all cases + + if (AccountMgr::IsPlayerAccount(GetSecurity())) + { + if (uint32 mask = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED)) + { + bool disabled = false; + + uint32 team = Player::TeamForRace(race_); + switch (team) + { + case ALLIANCE: disabled = mask & (1 << 0); break; + case HORDE: disabled = mask & (1 << 1); break; + } + + if (disabled) + { + data << (uint8)CHAR_CREATE_DISABLED; + SendPacket(&data); + return; + } + } + } + + ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(class_); + if (!classEntry) + { + data << (uint8)CHAR_CREATE_FAILED; + SendPacket(&data); + sLog->outError("Class (%u) not found in DBC while creating new char for account (ID: %u): wrong DBC files or cheater?", class_, GetAccountId()); + return; + } + + ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(race_); + if (!raceEntry) + { + data << (uint8)CHAR_CREATE_FAILED; + SendPacket(&data); + sLog->outError("Race (%u) not found in DBC while creating new char for account (ID: %u): wrong DBC files or cheater?", race_, GetAccountId()); + return; + } + + // prevent character creating Expansion race without Expansion account + if (raceEntry->expansion > Expansion()) + { + data << (uint8)CHAR_CREATE_EXPANSION; + sLog->outError("Expansion %u account:[%d] tried to Create character with expansion %u race (%u)", Expansion(), GetAccountId(), raceEntry->expansion, race_); + SendPacket(&data); + return; + } + + // prevent character creating Expansion class without Expansion account + if (classEntry->expansion > Expansion()) + { + data << (uint8)CHAR_CREATE_EXPANSION_CLASS; + sLog->outError("Expansion %u account:[%d] tried to Create character with expansion %u class (%u)", Expansion(), GetAccountId(), classEntry->expansion, class_); + SendPacket(&data); + return; + } + + if (AccountMgr::IsPlayerAccount(GetSecurity())) + { + uint32 raceMaskDisabled = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK); + if ((1 << (race_ - 1)) & raceMaskDisabled) + { + data << uint8(CHAR_CREATE_DISABLED); + SendPacket(&data); + return; + } + + uint32 classMaskDisabled = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK); + if ((1 << (class_ - 1)) & classMaskDisabled) + { + data << uint8(CHAR_CREATE_DISABLED); + SendPacket(&data); + return; + } + } + + // prevent character creating with invalid name + if (!normalizePlayerName(name)) + { + data << (uint8)CHAR_NAME_NO_NAME; + SendPacket(&data); + sLog->outError("Account:[%d] but tried to Create character with empty [name] ", GetAccountId()); + return; + } + + // check name limitations + uint8 res = ObjectMgr::CheckPlayerName(name, true); + if (res != CHAR_NAME_SUCCESS) + { + data << uint8(res); + SendPacket(&data); + return; + } + + if (AccountMgr::IsPlayerAccount(GetSecurity()) && sObjectMgr->IsReservedName(name)) + { + data << (uint8)CHAR_NAME_RESERVED; + SendPacket(&data); + return; + } + + // speedup check for heroic class disabled case + uint32 heroic_free_slots = sWorld->getIntConfig(CONFIG_HEROIC_CHARACTERS_PER_REALM); + if (heroic_free_slots == 0 && AccountMgr::IsPlayerAccount(GetSecurity()) && class_ == CLASS_DEATH_KNIGHT) + { + data << (uint8)CHAR_CREATE_UNIQUE_CLASS_LIMIT; + SendPacket(&data); + return; + } + + // speedup check for heroic class disabled case + uint32 req_level_for_heroic = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER); + if (AccountMgr::IsPlayerAccount(GetSecurity()) && class_ == CLASS_DEATH_KNIGHT && req_level_for_heroic > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + data << (uint8)CHAR_CREATE_LEVEL_REQUIREMENT; + SendPacket(&data); + return; + } + + delete _charCreateCallback.GetParam(); // Delete existing if any, to make the callback chain reset to stage 0 + _charCreateCallback.SetParam(new CharacterCreateInfo(name, race_, class_, gender, skin, face, hairStyle, hairColor, facialHair, outfitId, recv_data)); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); + stmt->setString(0, name); + _charCreateCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); +} + +void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, CharacterCreateInfo* createInfo) +{ + /** This is a series of callbacks executed consecutively as a result from the database becomes available. + This is much more efficient than synchronous requests on packet handler, and much less DoS prone. + It also prevents data syncrhonisation errors. + */ + switch (_charCreateCallback.GetStage()) + { + case 0: + { + if (result) + { + WorldPacket data(SMSG_CHAR_CREATE, 1); + data << uint8(CHAR_CREATE_NAME_IN_USE); + SendPacket(&data); + delete createInfo; + _charCreateCallback.Reset(); + return; + } + + ASSERT(_charCreateCallback.GetParam() == createInfo); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SUM_REALM_CHARACTERS); + stmt->setUInt32(0, GetAccountId()); + + _charCreateCallback.FreeResult(); + _charCreateCallback.SetFutureResult(LoginDatabase.AsyncQuery(stmt)); + _charCreateCallback.NextStage(); + } + break; + case 1: + { + uint16 acctCharCount = 0; + if (result) + { + Field* fields = result->Fetch(); + // SELECT SUM(x) is MYSQL_TYPE_NEWDECIMAL - needs to be read as string + const char* ch = fields[0].GetCString(); + if (ch) + acctCharCount = atoi(ch); + } + + if (acctCharCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_ACCOUNT)) + { + WorldPacket data(SMSG_CHAR_CREATE, 1); + data << uint8(CHAR_CREATE_ACCOUNT_LIMIT); + SendPacket(&data); + delete createInfo; + _charCreateCallback.Reset(); + return; + } + + + ASSERT(_charCreateCallback.GetParam() == createInfo); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS); + stmt->setUInt32(0, GetAccountId()); + + _charCreateCallback.FreeResult(); + _charCreateCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); + _charCreateCallback.NextStage(); + } + break; + case 2: + { + if (result) + { + Field* fields = result->Fetch(); + createInfo->CharCount = fields[0].GetUInt8(); + + if (createInfo->CharCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM)) + { + WorldPacket data(SMSG_CHAR_CREATE, 1); + data << uint8(CHAR_CREATE_SERVER_LIMIT); + SendPacket(&data); + delete createInfo; + _charCreateCallback.Reset(); + return; + } + } + + bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS) || !AccountMgr::IsPlayerAccount(GetSecurity()); + uint32 skipCinematics = sWorld->getIntConfig(CONFIG_SKIP_CINEMATICS); + + _charCreateCallback.FreeResult(); + + if (!allowTwoSideAccounts || skipCinematics == 1 || createInfo->Class == CLASS_DEATH_KNIGHT) + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_CREATE_INFO); + stmt->setUInt32(0, GetAccountId()); + stmt->setUInt32(1, (skipCinematics == 1 || createInfo->Class == CLASS_DEATH_KNIGHT) ? 10 : 1); + _charCreateCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); + _charCreateCallback.NextStage(); + return; + } + + _charCreateCallback.NextStage(); + HandleCharCreateCallback(PreparedQueryResult(NULL), createInfo); // Will jump to case 3 + } + break; + case 3: + { + bool haveSameRace = false; + uint32 heroicReqLevel = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER); + bool hasHeroicReqLevel = (heroicReqLevel == 0); + bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS) || !AccountMgr::IsPlayerAccount(GetSecurity()); + uint32 skipCinematics = sWorld->getIntConfig(CONFIG_SKIP_CINEMATICS); + + if (result) + { + uint32 team = Player::TeamForRace(createInfo->Race); + uint32 freeHeroicSlots = sWorld->getIntConfig(CONFIG_HEROIC_CHARACTERS_PER_REALM); + + Field* field = result->Fetch(); + uint8 accRace = field[1].GetUInt8(); + + if (AccountMgr::IsPlayerAccount(GetSecurity()) && createInfo->Class == CLASS_DEATH_KNIGHT) + { + uint8 accClass = field[2].GetUInt8(); + if (accClass == CLASS_DEATH_KNIGHT) + { + if (freeHeroicSlots > 0) + --freeHeroicSlots; + + if (freeHeroicSlots == 0) + { + WorldPacket data(SMSG_CHAR_CREATE, 1); + data << uint8(CHAR_CREATE_UNIQUE_CLASS_LIMIT); + SendPacket(&data); + delete createInfo; + _charCreateCallback.Reset(); + return; + } + } + + if (!hasHeroicReqLevel) + { + uint8 accLevel = field[0].GetUInt8(); + if (accLevel >= heroicReqLevel) + hasHeroicReqLevel = true; + } + } + + // need to check team only for first character + // TODO: what to if account already has characters of both races? + if (!allowTwoSideAccounts) + { + uint32 accTeam = 0; + if (accRace > 0) + accTeam = Player::TeamForRace(accRace); + + if (accTeam != team) + { + WorldPacket data(SMSG_CHAR_CREATE, 1); + data << uint8(CHAR_CREATE_PVP_TEAMS_VIOLATION); + SendPacket(&data); + delete createInfo; + _charCreateCallback.Reset(); + return; + } + } + + // search same race for cinematic or same class if need + // TODO: check if cinematic already shown? (already logged in?; cinematic field) + while ((skipCinematics == 1 && !haveSameRace) || createInfo->Class == CLASS_DEATH_KNIGHT) + { + if (!result->NextRow()) + break; + + field = result->Fetch(); + accRace = field[1].GetUInt8(); + + if (!haveSameRace) + haveSameRace = createInfo->Race == accRace; + + if (AccountMgr::IsPlayerAccount(GetSecurity()) && createInfo->Class == CLASS_DEATH_KNIGHT) + { + uint8 acc_class = field[2].GetUInt8(); + if (acc_class == CLASS_DEATH_KNIGHT) + { + if (freeHeroicSlots > 0) + --freeHeroicSlots; + + if (freeHeroicSlots == 0) + { + WorldPacket data(SMSG_CHAR_CREATE, 1); + data << uint8(CHAR_CREATE_UNIQUE_CLASS_LIMIT); + SendPacket(&data); + delete createInfo; + _charCreateCallback.Reset(); + return; + } + } + + if (!hasHeroicReqLevel) + { + uint8 acc_level = field[0].GetUInt8(); + if (acc_level >= heroicReqLevel) + hasHeroicReqLevel = true; + } + } + } + } + + if (AccountMgr::IsPlayerAccount(GetSecurity()) && createInfo->Class == CLASS_DEATH_KNIGHT && !hasHeroicReqLevel) + { + WorldPacket data(SMSG_CHAR_CREATE, 1); + data << uint8(CHAR_CREATE_LEVEL_REQUIREMENT); + SendPacket(&data); + delete createInfo; + _charCreateCallback.Reset(); + return; + } + + if (createInfo->Data.rpos() < createInfo->Data.wpos()) + { + uint8 unk; + createInfo->Data >> unk; + sLog->outDebug(LOG_FILTER_NETWORKIO, "Character creation %s (account %u) has unhandled tail data: [%u]", createInfo->Name.c_str(), GetAccountId(), unk); + } + + Player newChar(this); + if (!newChar.Create(sObjectMgr->GenerateLowGuid(HIGHGUID_PLAYER), createInfo)) + { + // Player not create (race/class/etc problem?) + newChar.CleanupsBeforeDelete(); + + WorldPacket data(SMSG_CHAR_CREATE, 1); + data << uint8(CHAR_CREATE_ERROR); + SendPacket(&data); + delete createInfo; + _charCreateCallback.Reset(); + return; + } + + if ((haveSameRace && skipCinematics == 1) || skipCinematics == 2) + newChar.setCinematic(1); // not show intro + + newChar.SetAtLoginFlag(AT_LOGIN_FIRST); // First login + + // Player created, save it now + newChar.SaveToDB(true); + createInfo->CharCount += 1; + + SQLTransaction trans = LoginDatabase.BeginTransaction(); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS); + stmt->setUInt32(0, GetAccountId()); + stmt->setUInt32(1, realmID); + trans->Append(stmt); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS); + stmt->setUInt32(0, createInfo->CharCount); + stmt->setUInt32(1, GetAccountId()); + stmt->setUInt32(2, realmID); + trans->Append(stmt); + + LoginDatabase.CommitTransaction(trans); + + newChar.CleanupsBeforeDelete(); + + WorldPacket data(SMSG_CHAR_CREATE, 1); + data << uint8(CHAR_CREATE_SUCCESS); + SendPacket(&data); + + std::string IP_str = GetRemoteAddress(); + sLog->outDetail("Account: %d (IP: %s) Create Character:[%s] (GUID: %u)", GetAccountId(), IP_str.c_str(), createInfo->Name.c_str(), newChar.GetGUIDLow()); + sLog->outChar("Account: %d (IP: %s) Create Character:[%s] (GUID: %u)", GetAccountId(), IP_str.c_str(), createInfo->Name.c_str(), newChar.GetGUIDLow()); + sScriptMgr->OnPlayerCreate(&newChar); + sWorld->AddCharacterNameData(newChar.GetGUIDLow(), std::string(newChar.GetName()), newChar.getGender(), newChar.getRace(), newChar.getClass()); + + delete createInfo; + _charCreateCallback.Reset(); + } + break; + } +} + +void WorldSession::HandleCharDeleteOpcode(WorldPacket & recv_data) +{ + uint64 guid; + recv_data >> guid; + + // can't delete loaded character + if (ObjectAccessor::FindPlayer(guid)) + return; + + uint32 accountId = 0; + std::string name; + + // is guild leader + if (sGuildMgr->GetGuildByLeader(guid)) + { + WorldPacket data(SMSG_CHAR_DELETE, 1); + data << (uint8)CHAR_DELETE_FAILED_GUILD_LEADER; + SendPacket(&data); + return; + } + + // is arena team captain + if (sArenaTeamMgr->GetArenaTeamByCaptain(guid)) + { + WorldPacket data(SMSG_CHAR_DELETE, 1); + data << (uint8)CHAR_DELETE_FAILED_ARENA_CAPTAIN; + SendPacket(&data); + return; + } + + QueryResult result = CharacterDatabase.PQuery("SELECT account, name FROM characters WHERE guid='%u'", GUID_LOPART(guid)); + if (result) + { + Field* fields = result->Fetch(); + accountId = fields[0].GetUInt32(); + name = fields[1].GetString(); + } + + // prevent deleting other players' characters using cheating tools + if (accountId != GetAccountId()) + return; + + std::string IP_str = GetRemoteAddress(); + sLog->outDetail("Account: %d (IP: %s) Delete Character:[%s] (GUID: %u)", GetAccountId(), IP_str.c_str(), name.c_str(), GUID_LOPART(guid)); + sLog->outChar("Account: %d (IP: %s) Delete Character:[%s] (GUID: %u)", GetAccountId(), IP_str.c_str(), name.c_str(), GUID_LOPART(guid)); + sScriptMgr->OnPlayerDelete(guid); + sWorld->DeleteCharaceterNameData(GUID_LOPART(guid)); + + if (sLog->IsOutCharDump()) // optimize GetPlayerDump call + { + std::string dump; + if (PlayerDumpWriter().GetDump(GUID_LOPART(guid), dump)) + sLog->outCharDump(dump.c_str(), GetAccountId(), GUID_LOPART(guid), name.c_str()); + } + + Player::DeleteFromDB(guid, GetAccountId()); + + WorldPacket data(SMSG_CHAR_DELETE, 1); + data << (uint8)CHAR_DELETE_SUCCESS; + SendPacket(&data); +} + +void WorldSession::HandlePlayerLoginOpcode(WorldPacket & recv_data) +{ + if (PlayerLoading() || GetPlayer() != NULL) + { + sLog->outError("Player tryes to login again, AccountId = %d", GetAccountId()); + return; + } + + m_playerLoading = true; + uint64 playerGuid = 0; + + sLog->outStaticDebug("WORLD: Recvd Player Logon Message"); + + recv_data >> playerGuid; + + if (!CharCanLogin(GUID_LOPART(playerGuid))) + { + sLog->outError("Account (%u) can't login with that character (%u).", GetAccountId(), GUID_LOPART(playerGuid)); + KickPlayer(); + return; + } + + LoginQueryHolder *holder = new LoginQueryHolder(GetAccountId(), playerGuid); + if (!holder->Initialize()) + { + delete holder; // delete all unprocessed queries + m_playerLoading = false; + return; + } + + _charLoginCallback = CharacterDatabase.DelayQueryHolder((SQLQueryHolder*)holder); +} + +void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) +{ + uint64 playerGuid = holder->GetGuid(); + + Player* pCurrChar = new Player(this); + // for send server info and strings (config) + ChatHandler chH = ChatHandler(pCurrChar); + + // "GetAccountId() == db stored account id" checked in LoadFromDB (prevent login not own character using cheating tools) + if (!pCurrChar->LoadFromDB(GUID_LOPART(playerGuid), holder)) + { + SetPlayer(NULL); + KickPlayer(); // disconnect client, player no set to session and it will not deleted or saved at kick + delete pCurrChar; // delete it manually + delete holder; // delete all unprocessed queries + m_playerLoading = false; + return; + } + + pCurrChar->GetMotionMaster()->Initialize(); + pCurrChar->SendDungeonDifficulty(false); + + WorldPacket data(SMSG_LOGIN_VERIFY_WORLD, 20); + data << pCurrChar->GetMapId(); + data << pCurrChar->GetPositionX(); + data << pCurrChar->GetPositionY(); + data << pCurrChar->GetPositionZ(); + data << pCurrChar->GetOrientation(); + SendPacket(&data); + + // load player specific part before send times + LoadAccountData(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADACCOUNTDATA), PER_CHARACTER_CACHE_MASK); + SendAccountDataTimes(PER_CHARACTER_CACHE_MASK); + + data.Initialize(SMSG_FEATURE_SYSTEM_STATUS, 2); // added in 2.2.0 + data << uint8(2); // unknown value + data << uint8(0); // enable(1)/disable(0) voice chat interface in client + SendPacket(&data); + + // Send MOTD + { + data.Initialize(SMSG_MOTD, 50); // new in 2.0.1 + data << (uint32)0; + + uint32 linecount=0; + std::string str_motd = sWorld->GetMotd(); + std::string::size_type pos, nextpos; + + pos = 0; + while ((nextpos= str_motd.find('@', pos)) != std::string::npos) + { + if (nextpos != pos) + { + data << str_motd.substr(pos, nextpos-pos); + ++linecount; + } + pos = nextpos+1; + } + + if (posoutStaticDebug("WORLD: Sent motd (SMSG_MOTD)"); + + // send server info + if (sWorld->getIntConfig(CONFIG_ENABLE_SINFO_LOGIN) == 1) + chH.PSendSysMessage(_FULLVERSION); + + sLog->outStaticDebug("WORLD: Sent server info"); + } + + //QueryResult* result = CharacterDatabase.PQuery("SELECT guildid, rank FROM guild_member WHERE guid = '%u'", pCurrChar->GetGUIDLow()); + if (PreparedQueryResult resultGuild = holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADGUILD)) + { + Field* fields = resultGuild->Fetch(); + pCurrChar->SetInGuild(fields[0].GetUInt32()); + pCurrChar->SetRank(fields[1].GetUInt8()); + } + else if (pCurrChar->GetGuildId()) // clear guild related fields in case wrong data about non existed membership + { + pCurrChar->SetInGuild(0); + pCurrChar->SetRank(0); + } + + if (pCurrChar->GetGuildId() != 0) + { + if (Guild* guild = sGuildMgr->GetGuildById(pCurrChar->GetGuildId())) + guild->SendLoginInfo(this); + else + { + // remove wrong guild data + sLog->outError("Player %s (GUID: %u) marked as member of not existing guild (id: %u), removing guild membership for player.", pCurrChar->GetName(), pCurrChar->GetGUIDLow(), pCurrChar->GetGuildId()); + pCurrChar->SetInGuild(0); + } + } + + data.Initialize(SMSG_LEARNED_DANCE_MOVES, 4+4); + data << uint32(0); + data << uint32(0); + SendPacket(&data); + + pCurrChar->SendInitialPacketsBeforeAddToMap(); + + //Show cinematic at the first time that player login + if (!pCurrChar->getCinematic()) + { + pCurrChar->setCinematic(1); + + if (ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(pCurrChar->getClass())) + { + if (cEntry->CinematicSequence) + pCurrChar->SendCinematicStart(cEntry->CinematicSequence); + else if (ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(pCurrChar->getRace())) + pCurrChar->SendCinematicStart(rEntry->CinematicSequence); + + // send new char string if not empty + if (!sWorld->GetNewCharString().empty()) + chH.PSendSysMessage("%s", sWorld->GetNewCharString().c_str()); + } + } + + if (Group* group = pCurrChar->GetGroup()) + { + if (group->isLFGGroup()) + { + LfgDungeonSet Dungeons; + Dungeons.insert(sLFGMgr->GetDungeon(group->GetGUID())); + sLFGMgr->SetSelectedDungeons(pCurrChar->GetGUID(), Dungeons); + sLFGMgr->SetState(pCurrChar->GetGUID(), sLFGMgr->GetState(group->GetGUID())); + } + } + + if (!pCurrChar->GetMap()->AddPlayerToMap(pCurrChar) || !pCurrChar->CheckInstanceLoginValid()) + { + AreaTrigger const* at = sObjectMgr->GetGoBackTrigger(pCurrChar->GetMapId()); + if (at) + pCurrChar->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, pCurrChar->GetOrientation()); + else + pCurrChar->TeleportTo(pCurrChar->m_homebindMapId, pCurrChar->m_homebindX, pCurrChar->m_homebindY, pCurrChar->m_homebindZ, pCurrChar->GetOrientation()); + } + + sObjectAccessor->AddObject(pCurrChar); + //sLog->outDebug("Player %s added to Map.", pCurrChar->GetName()); + + pCurrChar->SendInitialPacketsAfterAddToMap(); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_ONLINE); + + stmt->setUInt32(0, pCurrChar->GetGUIDLow()); + + CharacterDatabase.Execute(stmt); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_ONLINE); + + stmt->setUInt32(0, GetAccountId()); + + LoginDatabase.Execute(stmt); + + pCurrChar->SetInGameTime(getMSTime()); + + // announce group about member online (must be after add to player list to receive announce to self) + if (Group* group = pCurrChar->GetGroup()) + { + //pCurrChar->groupInfo.group->SendInit(this); // useless + group->SendUpdate(); + group->ResetMaxEnchantingLevel(); + } + + // friend status + sSocialMgr->SendFriendStatus(pCurrChar, FRIEND_ONLINE, pCurrChar->GetGUIDLow(), true); + + // Place character in world (and load zone) before some object loading + pCurrChar->LoadCorpse(); + + // setting Ghost+speed if dead + if (pCurrChar->m_deathState != ALIVE) + { + // not blizz like, we must correctly save and load player instead... + if (pCurrChar->getRace() == RACE_NIGHTELF) + pCurrChar->CastSpell(pCurrChar, 20584, true, 0);// auras SPELL_AURA_INCREASE_SPEED(+speed in wisp form), SPELL_AURA_INCREASE_SWIM_SPEED(+swim speed in wisp form), SPELL_AURA_TRANSFORM (to wisp form) + pCurrChar->CastSpell(pCurrChar, 8326, true, 0); // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?) + + pCurrChar->SetMovement(MOVE_WATER_WALK); + } + + pCurrChar->ContinueTaxiFlight(); + + // reset for all pets before pet loading + if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS)) + Pet::resetTalentsForAllPetsOf(pCurrChar); + + // Load pet if any (if player not alive and in taxi flight or another then pet will remember as temporary unsummoned) + pCurrChar->LoadPet(); + + // Set FFA PvP for non GM in non-rest mode + if (sWorld->IsFFAPvPRealm() && !pCurrChar->isGameMaster() && !pCurrChar->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING)) + pCurrChar->SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); + + if (pCurrChar->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP)) + pCurrChar->SetContestedPvP(); + + // Apply at_login requests + if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_SPELLS)) + { + pCurrChar->resetSpells(); + SendNotification(LANG_RESET_SPELLS); + } + + if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_TALENTS)) + { + pCurrChar->resetTalents(true); + pCurrChar->SendTalentsInfoData(false); // original talents send already in to SendInitialPacketsBeforeAddToMap, resend reset state + SendNotification(LANG_RESET_TALENTS); + } + + if (pCurrChar->HasAtLoginFlag(AT_LOGIN_FIRST)) + pCurrChar->RemoveAtLoginFlag(AT_LOGIN_FIRST); + + // show time before shutdown if shutdown planned. + if (sWorld->IsShuttingDown()) + sWorld->ShutdownMsg(true, pCurrChar); + + if (sWorld->getBoolConfig(CONFIG_ALL_TAXI_PATHS)) + pCurrChar->SetTaxiCheater(true); + + if (pCurrChar->isGameMaster()) + SendNotification(LANG_GM_ON); + + std::string IP_str = GetRemoteAddress(); + sLog->outChar("Account: %d (IP: %s) Login Character:[%s] (GUID: %u)", + GetAccountId(), IP_str.c_str(), pCurrChar->GetName(), pCurrChar->GetGUIDLow()); + + if (!pCurrChar->IsStandState() && !pCurrChar->HasUnitState(UNIT_STAT_STUNNED)) + pCurrChar->SetStandState(UNIT_STAND_STATE_STAND); + + m_playerLoading = false; + + sScriptMgr->OnPlayerLogin(pCurrChar); + delete holder; +} + +void WorldSession::HandleSetFactionAtWar(WorldPacket & recv_data) +{ + sLog->outStaticDebug("WORLD: Received CMSG_SET_FACTION_ATWAR"); + + uint32 repListID; + uint8 flag; + + recv_data >> repListID; + recv_data >> flag; + + GetPlayer()->GetReputationMgr().SetAtWar(repListID, flag); +} + +//I think this function is never used :/ I dunno, but i guess this opcode not exists +void WorldSession::HandleSetFactionCheat(WorldPacket & /*recv_data*/) +{ + sLog->outError("WORLD SESSION: HandleSetFactionCheat, not expected call, please report."); + GetPlayer()->GetReputationMgr().SendStates(); +} + +void WorldSession::HandleTutorialFlag(WorldPacket & recv_data) +{ + uint32 data; + recv_data >> data; + + uint8 index = uint8(data / 32); + if (index >= MAX_ACCOUNT_TUTORIAL_VALUES) + return; + + uint32 value = (data % 32); + + uint32 flag = GetTutorialInt(index); + flag |= (1 << value); + SetTutorialInt(index, flag); +} + +void WorldSession::HandleTutorialClear(WorldPacket & /*recv_data*/) +{ + for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i) + SetTutorialInt(i, 0xFFFFFFFF); +} + +void WorldSession::HandleTutorialReset(WorldPacket & /*recv_data*/) +{ + for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i) + SetTutorialInt(i, 0x00000000); +} + +void WorldSession::HandleSetWatchedFactionOpcode(WorldPacket & recv_data) +{ + sLog->outStaticDebug("WORLD: Received CMSG_SET_WATCHED_FACTION"); + uint32 fact; + recv_data >> fact; + GetPlayer()->SetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, fact); +} + +void WorldSession::HandleSetFactionInactiveOpcode(WorldPacket & recv_data) +{ + sLog->outStaticDebug("WORLD: Received CMSG_SET_FACTION_INACTIVE"); + uint32 replistid; + uint8 inactive; + recv_data >> replistid >> inactive; + + _player->GetReputationMgr().SetInactive(replistid, inactive); +} + +void WorldSession::HandleShowingHelmOpcode(WorldPacket& recv_data) +{ + sLog->outStaticDebug("CMSG_SHOWING_HELM for %s", _player->GetName()); + recv_data.read_skip(); // unknown, bool? + _player->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM); +} + +void WorldSession::HandleShowingCloakOpcode(WorldPacket& recv_data) +{ + sLog->outStaticDebug("CMSG_SHOWING_CLOAK for %s", _player->GetName()); + recv_data.read_skip(); // unknown, bool? + _player->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK); +} + +void WorldSession::HandleCharRenameOpcode(WorldPacket& recv_data) +{ + uint64 guid; + std::string newName; + + recv_data >> guid; + recv_data >> newName; + + // prevent character rename to invalid name + if (!normalizePlayerName(newName)) + { + WorldPacket data(SMSG_CHAR_RENAME, 1); + data << uint8(CHAR_NAME_NO_NAME); + SendPacket(&data); + return; + } + + uint8 res = ObjectMgr::CheckPlayerName(newName, true); + if (res != CHAR_NAME_SUCCESS) + { + WorldPacket data(SMSG_CHAR_RENAME, 1); + data << uint8(res); + SendPacket(&data); + return; + } + + // check name limitations + if (AccountMgr::IsPlayerAccount(GetSecurity()) && sObjectMgr->IsReservedName(newName)) + { + WorldPacket data(SMSG_CHAR_RENAME, 1); + data << uint8(CHAR_NAME_RESERVED); + SendPacket(&data); + return; + } + + // Ensure that the character belongs to the current account, that rename at login is enabled + // and that there is no character with the desired new name + _charRenameCallback.SetParam(newName); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_FREE_NAME); + + stmt->setUInt32(0, GUID_LOPART(guid)); + stmt->setUInt32(1, GetAccountId()); + stmt->setUInt16(2, AT_LOGIN_RENAME); + stmt->setUInt16(3, AT_LOGIN_RENAME); + stmt->setString(4, newName); + + _charRenameCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); +} + +void WorldSession::HandleChangePlayerNameOpcodeCallBack(PreparedQueryResult result, std::string newName) +{ + if (!result) + { + WorldPacket data(SMSG_CHAR_RENAME, 1); + data << uint8(CHAR_CREATE_ERROR); + SendPacket(&data); + return; + } + + Field* fields = result->Fetch(); + + uint32 guidLow = fields[0].GetUInt32(); + std::string oldName = fields[1].GetString(); + + uint64 guid = MAKE_NEW_GUID(guidLow, 0, HIGHGUID_PLAYER); + + // Update name and at_login flag in the db + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_NAME); + + stmt->setString(0, newName); + stmt->setUInt16(1, AT_LOGIN_RENAME); + stmt->setUInt32(2, guidLow); + + CharacterDatabase.Execute(stmt); + + // Removed declined name from db + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_DECLINED_NAME); + + stmt->setUInt32(0, guidLow); + + CharacterDatabase.Execute(stmt); + + sLog->outChar("Account: %d (IP: %s) Character:[%s] (guid:%u) Changed name to: %s", GetAccountId(), GetRemoteAddress().c_str(), oldName.c_str(), guidLow, newName.c_str()); + + WorldPacket data(SMSG_CHAR_RENAME, 1+8+(newName.size()+1)); + data << uint8(RESPONSE_SUCCESS); + data << uint64(guid); + data << newName; + SendPacket(&data); + + sWorld->UpdateCharacterNameData(guidLow, newName); +} + +void WorldSession::HandleSetPlayerDeclinedNames(WorldPacket& recv_data) +{ + uint64 guid; + + recv_data >> guid; + + // not accept declined names for unsupported languages + std::string name; + if (!sObjectMgr->GetPlayerNameByGUID(guid, name)) + { + WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); + data << uint32(1); + data << uint64(guid); + SendPacket(&data); + return; + } + + std::wstring wname; + if (!Utf8toWStr(name, wname)) + { + WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); + data << uint32(1); + data << uint64(guid); + SendPacket(&data); + return; + } + + if (!isCyrillicCharacter(wname[0])) // name already stored as only single alphabet using + { + WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); + data << uint32(1); + data << uint64(guid); + SendPacket(&data); + return; + } + + std::string name2; + DeclinedName declinedname; + + recv_data >> name2; + + if (name2 != name) // character have different name + { + WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); + data << uint32(1); + data << uint64(guid); + SendPacket(&data); + return; + } + + for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i) + { + recv_data >> declinedname.name[i]; + if (!normalizePlayerName(declinedname.name[i])) + { + WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); + data << uint32(1); + data << uint64(guid); + SendPacket(&data); + return; + } + } + + if (!ObjectMgr::CheckDeclinedNames(wname, declinedname)) + { + WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); + data << uint32(1); + data << uint64(guid); + SendPacket(&data); + return; + } + + for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i) + CharacterDatabase.EscapeString(declinedname.name[i]); + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + trans->PAppend("DELETE FROM character_declinedname WHERE guid = '%u'", GUID_LOPART(guid)); + trans->PAppend("INSERT INTO character_declinedname (guid, genitive, dative, accusative, instrumental, prepositional) VALUES ('%u', '%s', '%s', '%s', '%s', '%s')", + GUID_LOPART(guid), declinedname.name[0].c_str(), declinedname.name[1].c_str(), declinedname.name[2].c_str(), declinedname.name[3].c_str(), declinedname.name[4].c_str()); + CharacterDatabase.CommitTransaction(trans); + + WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); + data << uint32(0); // OK + data << uint64(guid); + SendPacket(&data); +} + +void WorldSession::HandleAlterAppearance(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_ALTER_APPEARANCE"); + + uint32 Hair, Color, FacialHair, SkinColor; + recv_data >> Hair >> Color >> FacialHair >> SkinColor; + + BarberShopStyleEntry const* bs_hair = sBarberShopStyleStore.LookupEntry(Hair); + + if (!bs_hair || bs_hair->type != 0 || bs_hair->race != _player->getRace() || bs_hair->gender != _player->getGender()) + return; + + BarberShopStyleEntry const* bs_facialHair = sBarberShopStyleStore.LookupEntry(FacialHair); + + if (!bs_facialHair || bs_facialHair->type != 2 || bs_facialHair->race != _player->getRace() || bs_facialHair->gender != _player->getGender()) + return; + + BarberShopStyleEntry const* bs_skinColor = sBarberShopStyleStore.LookupEntry(SkinColor); + + if (bs_skinColor && (bs_skinColor->type != 3 || bs_skinColor->race != _player->getRace() || bs_skinColor->gender != _player->getGender())) + return; + + uint32 Cost = _player->GetBarberShopCost(bs_hair->hair_id, Color, bs_facialHair->hair_id, bs_skinColor); + + // 0 - ok + // 1, 3 - not enough money + // 2 - you have to seat on barber chair + if (!_player->HasEnoughMoney(Cost)) + { + WorldPacket data(SMSG_BARBER_SHOP_RESULT, 4); + data << uint32(1); // no money + SendPacket(&data); + return; + } + else + { + WorldPacket data(SMSG_BARBER_SHOP_RESULT, 4); + data << uint32(0); // ok + SendPacket(&data); + } + + _player->ModifyMoney(-int32(Cost)); // it isn't free + _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER, Cost); + + _player->SetByteValue(PLAYER_BYTES, 2, uint8(bs_hair->hair_id)); + _player->SetByteValue(PLAYER_BYTES, 3, uint8(Color)); + _player->SetByteValue(PLAYER_BYTES_2, 0, uint8(bs_facialHair->hair_id)); + if (bs_skinColor) + _player->SetByteValue(PLAYER_BYTES, 0, uint8(bs_skinColor->hair_id)); + + _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP, 1); + + _player->SetStandState(0); // stand up +} + +void WorldSession::HandleRemoveGlyph(WorldPacket & recv_data) +{ + uint32 slot; + recv_data >> slot; + + if (slot >= MAX_GLYPH_SLOT_INDEX) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "Client sent wrong glyph slot number in opcode CMSG_REMOVE_GLYPH %u", slot); + return; + } + + if (uint32 glyph = _player->GetGlyph(slot)) + { + if (GlyphPropertiesEntry const* gp = sGlyphPropertiesStore.LookupEntry(glyph)) + { + _player->RemoveAurasDueToSpell(gp->SpellId); + _player->SetGlyph(slot, 0); + _player->SendTalentsInfoData(false); + } + } +} + +void WorldSession::HandleCharCustomize(WorldPacket& recv_data) +{ + uint64 guid; + std::string newName; + + recv_data >> guid; + recv_data >> newName; + + uint8 gender, skin, face, hairStyle, hairColor, facialHair; + recv_data >> gender >> skin >> hairColor >> hairStyle >> facialHair >> face; + + QueryResult result = CharacterDatabase.PQuery("SELECT at_login FROM characters WHERE guid ='%u'", GUID_LOPART(guid)); + if (!result) + { + WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); + data << uint8(CHAR_CREATE_ERROR); + SendPacket(&data); + return; + } + + Field* fields = result->Fetch(); + uint32 at_loginFlags = fields[0].GetUInt16(); + + if (!(at_loginFlags & AT_LOGIN_CUSTOMIZE)) + { + WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); + data << uint8(CHAR_CREATE_ERROR); + SendPacket(&data); + return; + } + + // prevent character rename to invalid name + if (!normalizePlayerName(newName)) + { + WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); + data << uint8(CHAR_NAME_NO_NAME); + SendPacket(&data); + return; + } + + uint8 res = ObjectMgr::CheckPlayerName(newName, true); + if (res != CHAR_NAME_SUCCESS) + { + WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); + data << uint8(res); + SendPacket(&data); + return; + } + + // check name limitations + if (AccountMgr::IsPlayerAccount(GetSecurity()) && sObjectMgr->IsReservedName(newName)) + { + WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); + data << uint8(CHAR_NAME_RESERVED); + SendPacket(&data); + return; + } + + // character with this name already exist + if (uint64 newguid = sObjectMgr->GetPlayerGUIDByName(newName)) + { + if (newguid != guid) + { + WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); + data << uint8(CHAR_CREATE_NAME_IN_USE); + SendPacket(&data); + return; + } + } + + if (QueryResult oldNameResult = CharacterDatabase.PQuery("SELECT name FROM characters WHERE guid ='%u'", GUID_LOPART(guid))) + { + std::string oldname = oldNameResult->Fetch()[0].GetString(); + std::string IP_str = GetRemoteAddress(); + sLog->outChar("Account: %d (IP: %s), Character[%s] (guid:%u) Customized to: %s", GetAccountId(), IP_str.c_str(), oldname.c_str(), GUID_LOPART(guid), newName.c_str()); + } + Player::Customize(guid, gender, skin, face, hairStyle, hairColor, facialHair); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_NAME_AT_LOGIN); + + stmt->setString(0, newName); + stmt->setUInt16(1, uint16(AT_LOGIN_CUSTOMIZE)); + stmt->setUInt32(2, GUID_LOPART(guid)); + + CharacterDatabase.Execute(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_DECLINED_NAME); + + stmt->setUInt32(0, GUID_LOPART(guid)); + + CharacterDatabase.Execute(stmt); + + sWorld->UpdateCharacterNameData(GUID_LOPART(guid), newName, gender); + + WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1+8+(newName.size()+1)+6); + data << uint8(RESPONSE_SUCCESS); + data << uint64(guid); + data << newName; + data << uint8(gender); + data << uint8(skin); + data << uint8(face); + data << uint8(hairStyle); + data << uint8(hairColor); + data << uint8(facialHair); + SendPacket(&data); +} + +void WorldSession::HandleEquipmentSetSave(WorldPacket &recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_EQUIPMENT_SET_SAVE"); + + uint64 setGuid; + recv_data.readPackGUID(setGuid); + + uint32 index; + recv_data >> index; + if (index >= MAX_EQUIPMENT_SET_INDEX) // client set slots amount + return; + + std::string name; + recv_data >> name; + + std::string iconName; + recv_data >> iconName; + + EquipmentSet eqSet; + + eqSet.Guid = setGuid; + eqSet.Name = name; + eqSet.IconName = iconName; + eqSet.state = EQUIPMENT_SET_NEW; + + for (uint32 i = 0; i < EQUIPMENT_SLOT_END; ++i) + { + uint64 itemGuid; + recv_data.readPackGUID(itemGuid); + + Item* item = _player->GetItemByPos(INVENTORY_SLOT_BAG_0, i); + + if (!item && itemGuid) // cheating check 1 + return; + + if (item && item->GetGUID() != itemGuid) // cheating check 2 + return; + + eqSet.Items[i] = GUID_LOPART(itemGuid); + } + + _player->SetEquipmentSet(index, eqSet); +} + +void WorldSession::HandleEquipmentSetDelete(WorldPacket &recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_EQUIPMENT_SET_DELETE"); + + uint64 setGuid; + recv_data.readPackGUID(setGuid); + + _player->DeleteEquipmentSet(setGuid); +} + +void WorldSession::HandleEquipmentSetUse(WorldPacket &recv_data) +{ + if (_player->isInCombat()) + return; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_EQUIPMENT_SET_USE"); + + for (uint32 i = 0; i < EQUIPMENT_SLOT_END; ++i) + { + uint64 itemGuid; + recv_data.readPackGUID(itemGuid); + + uint8 srcbag, srcslot; + recv_data >> srcbag >> srcslot; + + sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "Item " UI64FMTD ": srcbag %u, srcslot %u", itemGuid, srcbag, srcslot); + + Item* item = _player->GetItemByGuid(itemGuid); + + uint16 dstpos = i | (INVENTORY_SLOT_BAG_0 << 8); + + if (!item) + { + Item* uItem = _player->GetItemByPos(INVENTORY_SLOT_BAG_0, i); + if (!uItem) + continue; + + ItemPosCountVec sDest; + InventoryResult msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, sDest, uItem, false); + if (msg == EQUIP_ERR_OK) + { + _player->RemoveItem(INVENTORY_SLOT_BAG_0, i, true); + _player->StoreItem(sDest, uItem, true); + } + else + _player->SendEquipError(msg, uItem, NULL); + + continue; + } + + if (item->GetPos() == dstpos) + continue; + + _player->SwapItem(item->GetPos(), dstpos); + } + + WorldPacket data(SMSG_EQUIPMENT_SET_USE_RESULT, 1); + data << uint8(0); // 4 - equipment swap failed - inventory is full + SendPacket(&data); +} + +void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recv_data) +{ + // TODO: Move queries to prepared statements + uint64 guid; + std::string newname; + uint8 gender, skin, face, hairStyle, hairColor, facialHair, race; + recv_data >> guid; + recv_data >> newname; + recv_data >> gender >> skin >> hairColor >> hairStyle >> facialHair >> face >> race; + + uint32 lowGuid = GUID_LOPART(guid); + QueryResult result = CharacterDatabase.PQuery("SELECT class, level, at_login FROM characters WHERE guid ='%u'", lowGuid); + if (!result) + { + WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1); + data << uint8(CHAR_CREATE_ERROR); + SendPacket(&data); + return; + } + + Field* fields = result->Fetch(); + uint32 playerClass = fields[0].GetUInt32(); + uint32 level = fields[1].GetUInt32(); + uint32 at_loginFlags = fields[2].GetUInt16(); + uint32 used_loginFlag = ((recv_data.GetOpcode() == CMSG_CHAR_RACE_CHANGE) ? AT_LOGIN_CHANGE_RACE : AT_LOGIN_CHANGE_FACTION); + + if (!sObjectMgr->GetPlayerInfo(race, playerClass)) + { + WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1); + data << uint8(CHAR_CREATE_ERROR); + SendPacket(&data); + return; + } + + if (!(at_loginFlags & used_loginFlag)) + { + WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1); + data << uint8(CHAR_CREATE_ERROR); + SendPacket(&data); + return; + } + + if (AccountMgr::IsPlayerAccount(GetSecurity())) + { + uint32 raceMaskDisabled = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK); + if ((1 << (race - 1)) & raceMaskDisabled) + { + WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1); + data << uint8(CHAR_CREATE_ERROR); + SendPacket(&data); + return; + } + } + + // prevent character rename to invalid name + if (!normalizePlayerName(newname)) + { + WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1); + data << uint8(CHAR_NAME_NO_NAME); + SendPacket(&data); + return; + } + + uint8 res = ObjectMgr::CheckPlayerName(newname, true); + if (res != CHAR_NAME_SUCCESS) + { + WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1); + data << uint8(res); + SendPacket(&data); + return; + } + + // check name limitations + if (AccountMgr::IsPlayerAccount(GetSecurity()) && sObjectMgr->IsReservedName(newname)) + { + WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1); + data << uint8(CHAR_NAME_RESERVED); + SendPacket (&data); + return; + } + + // character with this name already exist + if (uint64 newguid = sObjectMgr->GetPlayerGUIDByName(newname)) + { + if (newguid != guid) + { + WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1); + data << uint8(CHAR_CREATE_NAME_IN_USE); + SendPacket(&data); + return; + } + } + + CharacterDatabase.EscapeString(newname); + Player::Customize(guid, gender, skin, face, hairStyle, hairColor, facialHair); + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + trans->PAppend("UPDATE `characters` SET name='%s', race='%u', at_login=at_login & ~ %u WHERE guid='%u'", newname.c_str(), race, used_loginFlag, lowGuid); + trans->PAppend("DELETE FROM character_declinedname WHERE guid ='%u'", lowGuid); + sWorld->UpdateCharacterNameData(GUID_LOPART(guid), newname, gender, race); + + BattlegroundTeamId team = BG_TEAM_ALLIANCE; + + // Search each faction is targeted + switch (race) + { + case RACE_ORC: + case RACE_TAUREN: + case RACE_UNDEAD_PLAYER: + case RACE_TROLL: + case RACE_BLOODELF: + team = BG_TEAM_HORDE; + break; + default: + break; + } + + // Switch Languages + // delete all languages first + trans->PAppend("DELETE FROM `character_skills` WHERE `skill` IN (98, 113, 759, 111, 313, 109, 115, 315, 673, 137) AND `guid`='%u'", lowGuid); + + // now add them back + if (team == BG_TEAM_ALLIANCE) + { + trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 98, 300, 300)", lowGuid); + switch (race) + { + case RACE_DWARF: + trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 111, 300, 300)", lowGuid); + break; + case RACE_DRAENEI: + trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 759, 300, 300)", lowGuid); + break; + case RACE_GNOME: + trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 313, 300, 300)", lowGuid); + break; + case RACE_NIGHTELF: + trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 113, 300, 300)", lowGuid); + break; + } + } + else if (team == BG_TEAM_HORDE) + { + trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 109, 300, 300)", lowGuid); + switch (race) + { + case RACE_UNDEAD_PLAYER: + trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 673, 300, 300)", lowGuid); + break; + case RACE_TAUREN: + trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 115, 300, 300)", lowGuid); + break; + case RACE_TROLL: + trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 315, 300, 300)", lowGuid); + break; + case RACE_BLOODELF: + trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 137, 300, 300)", lowGuid); + break; + } + } + + if (recv_data.GetOpcode() == CMSG_CHAR_FACTION_CHANGE) + { + // Delete all Flypaths + trans->PAppend("UPDATE `characters` SET taxi_path = '' WHERE guid ='%u'", lowGuid); + + if (level > 7) + { + // Update Taxi path + // this doesn't seem to be 100% blizzlike... but it can't really be helped. + std::ostringstream taximaskstream; + uint32 numFullTaximasks = level / 7; + if (numFullTaximasks > 11) + numFullTaximasks = 11; + if (team == BG_TEAM_ALLIANCE) + { + if (playerClass != CLASS_DEATH_KNIGHT) + { + for (uint8 i = 0; i < numFullTaximasks; ++i) + taximaskstream << uint32(sAllianceTaxiNodesMask[i]) << ' '; + } + else + { + for (uint8 i = 0; i < numFullTaximasks; ++i) + taximaskstream << uint32(sAllianceTaxiNodesMask[i] | sDeathKnightTaxiNodesMask[i]) << ' '; + } + } + else + { + if (playerClass != CLASS_DEATH_KNIGHT) + { + for (uint8 i = 0; i < numFullTaximasks; ++i) + taximaskstream << uint32(sHordeTaxiNodesMask[i]) << ' '; + } + else + { + for (uint8 i = 0; i < numFullTaximasks; ++i) + taximaskstream << uint32(sHordeTaxiNodesMask[i] | sDeathKnightTaxiNodesMask[i]) << ' '; + } + } + + uint32 numEmptyTaximasks = 11 - numFullTaximasks; + for (uint8 i = 0; i < numEmptyTaximasks; ++i) + taximaskstream << "0 "; + taximaskstream << '0'; + std::string taximask = taximaskstream.str(); + trans->PAppend("UPDATE `characters` SET `taximask`= '%s' WHERE `guid` = '%u'", taximask.c_str(), lowGuid); + } + + // Delete all current quests + trans->PAppend("DELETE FROM `character_queststatus` WHERE guid ='%u'", GUID_LOPART(guid)); + + // Delete record of the faction old completed quests + { + std::ostringstream quests; + ObjectMgr::QuestMap const& qTemplates = sObjectMgr->GetQuestTemplates(); + for (ObjectMgr::QuestMap::const_iterator iter = qTemplates.begin(); iter != qTemplates.end(); ++iter) + { + Quest *qinfo = iter->second; + uint32 requiredRaces = qinfo->GetRequiredRaces(); + if (team == BG_TEAM_ALLIANCE) + { + if (requiredRaces & RACEMASK_ALLIANCE) + { + quests << uint32(qinfo->GetQuestId()); + quests << ','; + } + } + else // if (team == BG_TEAM_HORDE) + { + if (requiredRaces & RACEMASK_HORDE) + { + quests << uint32(qinfo->GetQuestId()); + quests << ','; + } + } + } + + std::string questsStr = quests.str(); + questsStr = questsStr.substr(0, questsStr.length() - 1); + + if (!questsStr.empty()) + trans->PAppend("DELETE FROM `character_queststatus_rewarded` WHERE guid='%u' AND quest IN (%s)", lowGuid, questsStr.c_str()); + } + + if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD)) + { + // Reset guild + if (QueryResult result = CharacterDatabase.PQuery("SELECT guildid FROM `guild_member` WHERE guid ='%u'", lowGuid)) + if (Guild* guild = sGuildMgr->GetGuildById((result->Fetch()[0]).GetUInt32())) + guild->DeleteMember(MAKE_NEW_GUID(lowGuid, 0, HIGHGUID_PLAYER)); + } + + if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND)) + { + // Delete Friend List + trans->PAppend("DELETE FROM `character_social` WHERE `guid`= '%u'", lowGuid); + trans->PAppend("DELETE FROM `character_social` WHERE `friend`= '%u'", lowGuid); + } + + // Leave Arena Teams + Player::LeaveAllArenaTeams(guid); + + // Reset homebind and position + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_HOMEBIND); + stmt->setUInt32(0, lowGuid); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PLAYER_HOMEBIND); + stmt->setUInt32(0, lowGuid); + if (team == BG_TEAM_ALLIANCE) + { + stmt->setUInt16(1, 0); + stmt->setUInt16(2, 1519); + stmt->setFloat (3, -8867.68f); + stmt->setFloat (4, 673.373f); + stmt->setFloat (5, 97.9034f); + Player::SavePositionInDB(0, -8867.68f, 673.373f, 97.9034f, 0.0f, 1519, lowGuid); + } + else + { + stmt->setUInt16(1, 1); + stmt->setUInt16(2, 1637); + stmt->setFloat (3, 1633.33f); + stmt->setFloat (4, -4439.11f); + stmt->setFloat (5, 15.7588f); + Player::SavePositionInDB(1, 1633.33f, -4439.11f, 15.7588f, 0.0f, 1637, lowGuid); + } + trans->Append(stmt); + + // Achievement conversion + for (std::map::const_iterator it = sObjectMgr->factionchange_achievements.begin(); it != sObjectMgr->factionchange_achievements.end(); ++it) + { + uint32 achiev_alliance = it->first; + uint32 achiev_horde = it->second; + trans->PAppend("DELETE FROM `character_achievement` WHERE `achievement`=%u AND `guid`=%u", + team == BG_TEAM_ALLIANCE ? achiev_alliance : achiev_horde, lowGuid); + trans->PAppend("UPDATE `character_achievement` SET achievement = '%u' where achievement = '%u' AND guid = '%u'", + team == BG_TEAM_ALLIANCE ? achiev_alliance : achiev_horde, team == BG_TEAM_ALLIANCE ? achiev_horde : achiev_alliance, lowGuid); + } + + // Item conversion + for (std::map::const_iterator it = sObjectMgr->factionchange_items.begin(); it != sObjectMgr->factionchange_items.end(); ++it) + { + uint32 item_alliance = it->first; + uint32 item_horde = it->second; + trans->PAppend("UPDATE `item_instance` ii, `character_inventory` ci SET ii.itemEntry = '%u' WHERE ii.itemEntry = '%u' AND ci.guid = '%u' AND ci.item = ii.guid", + team == BG_TEAM_ALLIANCE ? item_alliance : item_horde, team == BG_TEAM_ALLIANCE ? item_horde : item_alliance, guid); + } + + // Spell conversion + for (std::map::const_iterator it = sObjectMgr->factionchange_spells.begin(); it != sObjectMgr->factionchange_spells.end(); ++it) + { + uint32 spell_alliance = it->first; + uint32 spell_horde = it->second; + trans->PAppend("DELETE FROM `character_spell` WHERE `spell`=%u AND `guid`=%u", + team == BG_TEAM_ALLIANCE ? spell_alliance : spell_horde, lowGuid); + trans->PAppend("UPDATE `character_spell` SET spell = '%u' where spell = '%u' AND guid = '%u'", + team == BG_TEAM_ALLIANCE ? spell_alliance : spell_horde, team == BG_TEAM_ALLIANCE ? spell_horde : spell_alliance, lowGuid); + } + + // Reputation conversion + for (std::map::const_iterator it = sObjectMgr->factionchange_reputations.begin(); it != sObjectMgr->factionchange_reputations.end(); ++it) + { + uint32 reputation_alliance = it->first; + uint32 reputation_horde = it->second; + trans->PAppend("DELETE FROM character_reputation WHERE faction = '%u' AND guid = '%u'", + team == BG_TEAM_ALLIANCE ? reputation_alliance : reputation_horde, lowGuid); + trans->PAppend("UPDATE `character_reputation` SET faction = '%u' where faction = '%u' AND guid = '%u'", + team == BG_TEAM_ALLIANCE ? reputation_alliance : reputation_horde, team == BG_TEAM_ALLIANCE ? reputation_horde : reputation_alliance, lowGuid); + } + } + + CharacterDatabase.CommitTransaction(trans); + + std::string IP_str = GetRemoteAddress(); + sLog->outDebug(LOG_FILTER_UNITS, "Account: %d (IP: %s), Character guid: %u Change Race/Faction to: %s", GetAccountId(), IP_str.c_str(), lowGuid, newname.c_str()); + + WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1 + 8 + (newname.size() + 1) + 1 + 1 + 1 + 1 + 1 + 1 + 1); + data << uint8(RESPONSE_SUCCESS); + data << uint64(guid); + data << newname; + data << uint8(gender); + data << uint8(skin); + data << uint8(face); + data << uint8(hairStyle); + data << uint8(hairColor); + data << uint8(facialHair); + data << uint8(race); + SendPacket(&data); +} diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp new file mode 100755 index 00000000000..3d689196256 --- /dev/null +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -0,0 +1,635 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "ObjectAccessor.h" +#include "ObjectMgr.h" +#include "GuildMgr.h" +#include "World.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "DatabaseEnv.h" + +#include "CellImpl.h" +#include "Chat.h" +#include "ChannelMgr.h" +#include "GridNotifiersImpl.h" +#include "Group.h" +#include "Guild.h" +#include "Language.h" +#include "Log.h" +#include "Opcodes.h" +#include "Player.h" +#include "SpellAuras.h" +#include "SpellAuraEffects.h" +#include "Util.h" +#include "ScriptMgr.h" +#include "AccountMgr.h" + +bool WorldSession::processChatmessageFurtherAfterSecurityChecks(std::string& msg, uint32 lang) +{ + if (lang != LANG_ADDON) + { + // strip invisible characters for non-addon messages + if (sWorld->getBoolConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING)) + stripLineInvisibleChars(msg); + + if (sWorld->getIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY) && AccountMgr::IsPlayerAccount(GetSecurity()) + && !ChatHandler(this).isValidChatMessage(msg.c_str())) + { + sLog->outError("Player %s (GUID: %u) sent a chatmessage with an invalid link: %s", GetPlayer()->GetName(), + GetPlayer()->GetGUIDLow(), msg.c_str()); + if (sWorld->getIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_KICK)) + KickPlayer(); + return false; + } + } + + return true; +} + +void WorldSession::HandleMessagechatOpcode(WorldPacket & recv_data) +{ + uint32 type; + uint32 lang; + + recv_data >> type; + recv_data >> lang; + + if (type >= MAX_CHAT_MSG_TYPE) + { + sLog->outError("CHAT: Wrong message type received: %u", type); + recv_data.rfinish(); + return; + } + + Player* sender = GetPlayer(); + + //sLog->outDebug("CHAT: packet received. type %u, lang %u", type, lang); + + // prevent talking at unknown language (cheating) + LanguageDesc const* langDesc = GetLanguageDescByID(lang); + if (!langDesc) + { + SendNotification(LANG_UNKNOWN_LANGUAGE); + recv_data.rfinish(); + return; + } + if (langDesc->skill_id != 0 && !sender->HasSkill(langDesc->skill_id)) + { + // also check SPELL_AURA_COMPREHEND_LANGUAGE (client offers option to speak in that language) + Unit::AuraEffectList const& langAuras = sender->GetAuraEffectsByType(SPELL_AURA_COMPREHEND_LANGUAGE); + bool foundAura = false; + for (Unit::AuraEffectList::const_iterator i = langAuras.begin(); i != langAuras.end(); ++i) + { + if ((*i)->GetMiscValue() == int32(lang)) + { + foundAura = true; + break; + } + } + if (!foundAura) + { + SendNotification(LANG_NOT_LEARNED_LANGUAGE); + recv_data.rfinish(); + return; + } + } + + if (lang == LANG_ADDON) + { + if (sWorld->getBoolConfig(CONFIG_CHATLOG_ADDON)) + { + std::string msg = ""; + recv_data >> msg; + + if (msg.empty()) + return; + + sScriptMgr->OnPlayerChat(sender, uint32(CHAT_MSG_ADDON), lang, msg); + } + + // Disabled addon channel? + if (!sWorld->getBoolConfig(CONFIG_ADDON_CHANNEL)) + return; + } + // LANG_ADDON should not be changed nor be affected by flood control + else + { + // send in universal language if player in .gmon mode (ignore spell effects) + if (sender->isGameMaster()) + lang = LANG_UNIVERSAL; + else + { + // send in universal language in two side iteration allowed mode + if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT)) + lang = LANG_UNIVERSAL; + else + { + switch (type) + { + case CHAT_MSG_PARTY: + case CHAT_MSG_PARTY_LEADER: + case CHAT_MSG_RAID: + case CHAT_MSG_RAID_LEADER: + case CHAT_MSG_RAID_WARNING: + // allow two side chat at group channel if two side group allowed + if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP)) + lang = LANG_UNIVERSAL; + break; + case CHAT_MSG_GUILD: + case CHAT_MSG_OFFICER: + // allow two side chat at guild channel if two side guild allowed + if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD)) + lang = LANG_UNIVERSAL; + break; + } + } + + // but overwrite it by SPELL_AURA_MOD_LANGUAGE auras (only single case used) + Unit::AuraEffectList const& ModLangAuras = sender->GetAuraEffectsByType(SPELL_AURA_MOD_LANGUAGE); + if (!ModLangAuras.empty()) + lang = ModLangAuras.front()->GetMiscValue(); + } + + if (!sender->CanSpeak()) + { + std::string timeStr = secsToTimeString(m_muteTime - time(NULL)); + SendNotification(GetTrinityString(LANG_WAIT_BEFORE_SPEAKING), timeStr.c_str()); + recv_data.rfinish(); // Prevent warnings + return; + } + + if (type != CHAT_MSG_AFK && type != CHAT_MSG_DND) + sender->UpdateSpeakTime(); + } + + if (sender->HasAura(1852) && type != CHAT_MSG_WHISPER) + { + std::string msg=""; + recv_data >> msg; + + SendNotification(GetTrinityString(LANG_GM_SILENCE), sender->GetName()); + return; + } + + std::string to, channel, msg; + bool ignoreChecks = false; + switch (type) + { + case CHAT_MSG_SAY: + case CHAT_MSG_EMOTE: + case CHAT_MSG_YELL: + case CHAT_MSG_PARTY: + case CHAT_MSG_PARTY_LEADER: + case CHAT_MSG_GUILD: + case CHAT_MSG_OFFICER: + case CHAT_MSG_RAID: + case CHAT_MSG_RAID_LEADER: + case CHAT_MSG_RAID_WARNING: + case CHAT_MSG_BATTLEGROUND: + case CHAT_MSG_BATTLEGROUND_LEADER: + recv_data >> msg; + break; + case CHAT_MSG_WHISPER: + recv_data >> to; + recv_data >> msg; + break; + case CHAT_MSG_CHANNEL: + recv_data >> channel; + recv_data >> msg; + break; + case CHAT_MSG_AFK: + case CHAT_MSG_DND: + recv_data >> msg; + ignoreChecks = true; + break; + } + + if (!ignoreChecks) + { + if (msg.empty()) + return; + + if (ChatHandler(this).ParseCommands(msg.c_str()) > 0) + return; + + if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) + return; + + if (msg.empty()) + return; + } + + switch (type) + { + case CHAT_MSG_SAY: + case CHAT_MSG_EMOTE: + case CHAT_MSG_YELL: + { + if (sender->getLevel() < sWorld->getIntConfig(CONFIG_CHAT_SAY_LEVEL_REQ)) + { + SendNotification(GetTrinityString(LANG_SAY_REQ), sWorld->getIntConfig(CONFIG_CHAT_SAY_LEVEL_REQ)); + return; + } + + if (type == CHAT_MSG_SAY) + sender->Say(msg, lang); + else if (type == CHAT_MSG_EMOTE) + sender->TextEmote(msg); + else if (type == CHAT_MSG_YELL) + sender->Yell(msg, lang); + } break; + case CHAT_MSG_WHISPER: + { + if (sender->getLevel() < sWorld->getIntConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ)) + { + SendNotification(GetTrinityString(LANG_WHISPER_REQ), sWorld->getIntConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ)); + return; + } + + if (!normalizePlayerName(to)) + { + SendPlayerNotFoundNotice(to); + break; + } + + Player* receiver = sObjectAccessor->FindPlayerByName(to.c_str()); + bool senderIsPlayer = AccountMgr::IsPlayerAccount(GetSecurity()); + bool receiverIsPlayer = AccountMgr::IsPlayerAccount(receiver ? receiver->GetSession()->GetSecurity() : SEC_PLAYER); + if (!receiver || (senderIsPlayer && !receiverIsPlayer && !receiver->isAcceptWhispers() && !receiver->IsInWhisperWhiteList(sender->GetGUID()))) + { + SendPlayerNotFoundNotice(to); + return; + } + + if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT) && senderIsPlayer && receiverIsPlayer) + if (GetPlayer()->GetTeam() != receiver->GetTeam()) + { + SendWrongFactionNotice(); + return; + } + + if (GetPlayer()->HasAura(1852) && !receiver->isGameMaster()) + { + SendNotification(GetTrinityString(LANG_GM_SILENCE), GetPlayer()->GetName()); + return; + } + + // If player is a Gamemaster and doesn't accept whisper, we auto-whitelist every player that the Gamemaster is talking to + if (!senderIsPlayer && !sender->isAcceptWhispers() && !sender->IsInWhisperWhiteList(receiver->GetGUID())) + sender->AddWhisperWhiteList(receiver->GetGUID()); + + GetPlayer()->Whisper(msg, lang, receiver->GetGUID()); + } break; + case CHAT_MSG_PARTY: + case CHAT_MSG_PARTY_LEADER: + { + // if player is in battleground, he cannot say to battleground members by /p + Group* group = GetPlayer()->GetOriginalGroup(); + if (!group) + { + group = _player->GetGroup(); + if (!group || group->isBGGroup()) + return; + } + + if (type == CHAT_MSG_PARTY_LEADER && !group->IsLeader(_player->GetGUID())) + return; + + sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); + + WorldPacket data; + ChatHandler::FillMessageData(&data, this, uint8(type), lang, NULL, 0, msg.c_str(), NULL); + group->BroadcastPacket(&data, false, group->GetMemberGroup(GetPlayer()->GetGUID())); + } break; + case CHAT_MSG_GUILD: + { + if (GetPlayer()->GetGuildId()) + { + if (Guild* guild = sGuildMgr->GetGuildById(GetPlayer()->GetGuildId())) + { + sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, guild); + + guild->BroadcastToGuild(this, false, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL); + } + } + } break; + case CHAT_MSG_OFFICER: + { + if (GetPlayer()->GetGuildId()) + { + if (Guild* guild = sGuildMgr->GetGuildById(GetPlayer()->GetGuildId())) + { + sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, guild); + + guild->BroadcastToGuild(this, true, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL); + } + } + } break; + case CHAT_MSG_RAID: + { + // if player is in battleground, he cannot say to battleground members by /ra + Group* group = GetPlayer()->GetOriginalGroup(); + if (!group) + { + group = GetPlayer()->GetGroup(); + if (!group || group->isBGGroup() || !group->isRaidGroup()) + return; + } + + sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); + + WorldPacket data; + ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID, lang, "", 0, msg.c_str(), NULL); + group->BroadcastPacket(&data, false); + } break; + case CHAT_MSG_RAID_LEADER: + { + // if player is in battleground, he cannot say to battleground members by /ra + Group* group = GetPlayer()->GetOriginalGroup(); + if (!group) + { + group = GetPlayer()->GetGroup(); + if (!group || group->isBGGroup() || !group->isRaidGroup() || !group->IsLeader(_player->GetGUID())) + return; + } + + sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); + + WorldPacket data; + ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_LEADER, lang, "", 0, msg.c_str(), NULL); + group->BroadcastPacket(&data, false); + } break; + case CHAT_MSG_RAID_WARNING: + { + Group* group = GetPlayer()->GetGroup(); + if (!group || !group->isRaidGroup() || !(group->IsLeader(GetPlayer()->GetGUID()) || group->IsAssistant(GetPlayer()->GetGUID())) || group->isBGGroup()) + return; + + sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); + + WorldPacket data; + //in battleground, raid warning is sent only to players in battleground - code is ok + ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_WARNING, lang, "", 0, msg.c_str(), NULL); + group->BroadcastPacket(&data, false); + } break; + case CHAT_MSG_BATTLEGROUND: + { + //battleground raid is always in Player->GetGroup(), never in GetOriginalGroup() + Group* group = GetPlayer()->GetGroup(); + if (!group || !group->isBGGroup()) + return; + + sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); + + WorldPacket data; + ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND, lang, "", 0, msg.c_str(), NULL); + group->BroadcastPacket(&data, false); + } break; + case CHAT_MSG_BATTLEGROUND_LEADER: + { + // battleground raid is always in Player->GetGroup(), never in GetOriginalGroup() + Group* group = GetPlayer()->GetGroup(); + if (!group || !group->isBGGroup() || !group->IsLeader(GetPlayer()->GetGUID())) + return; + + sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); + + WorldPacket data; + ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND_LEADER, lang, "", 0, msg.c_str(), NULL); + group->BroadcastPacket(&data, false); + } break; + case CHAT_MSG_CHANNEL: + { + if (AccountMgr::IsPlayerAccount(GetSecurity())) + { + if (_player->getLevel() < sWorld->getIntConfig(CONFIG_CHAT_CHANNEL_LEVEL_REQ)) + { + SendNotification(GetTrinityString(LANG_CHANNEL_REQ), sWorld->getIntConfig(CONFIG_CHAT_CHANNEL_LEVEL_REQ)); + return; + } + } + + if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + { + + if (Channel* chn = cMgr->GetChannel(channel, _player)) + { + sScriptMgr->OnPlayerChat(_player, type, lang, msg, chn); + + chn->Say(_player->GetGUID(), msg.c_str(), lang); + } + } + } break; + case CHAT_MSG_AFK: + { + if ((msg.empty() || !_player->isAFK()) && !_player->isInCombat()) + { + if (!_player->isAFK()) + { + if (msg.empty()) + msg = GetTrinityString(LANG_PLAYER_AFK_DEFAULT); + _player->afkMsg = msg; + } + + sScriptMgr->OnPlayerChat(_player, type, lang, msg); + + _player->ToggleAFK(); + if (_player->isAFK() && _player->isDND()) + _player->ToggleDND(); + } + } break; + case CHAT_MSG_DND: + { + if (msg.empty() || !_player->isDND()) + { + if (!_player->isDND()) + { + if (msg.empty()) + msg = GetTrinityString(LANG_PLAYER_DND_DEFAULT); + _player->dndMsg = msg; + } + + sScriptMgr->OnPlayerChat(_player, type, lang, msg); + + _player->ToggleDND(); + if (_player->isDND() && _player->isAFK()) + _player->ToggleAFK(); + } + } break; + default: + sLog->outError("CHAT: unknown message type %u, lang: %u", type, lang); + break; + } +} + +void WorldSession::HandleEmoteOpcode(WorldPacket & recv_data) +{ + if (!GetPlayer()->isAlive() || GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + return; + + uint32 emote; + recv_data >> emote; + sScriptMgr->OnPlayerEmote(GetPlayer(), emote); + GetPlayer()->HandleEmoteCommand(emote); +} + +namespace Trinity +{ + class EmoteChatBuilder + { + public: + EmoteChatBuilder(Player const& player, uint32 text_emote, uint32 emote_num, Unit const* target) + : i_player(player), i_text_emote(text_emote), i_emote_num(emote_num), i_target(target) {} + + void operator()(WorldPacket& data, LocaleConstant loc_idx) + { + char const* nam = i_target ? i_target->GetNameForLocaleIdx(loc_idx) : NULL; + uint32 namlen = (nam ? strlen(nam) : 0) + 1; + + data.Initialize(SMSG_TEXT_EMOTE, (20+namlen)); + data << i_player.GetGUID(); + data << (uint32)i_text_emote; + data << i_emote_num; + data << (uint32)namlen; + if (namlen > 1) + data.append(nam, namlen); + else + data << (uint8)0x00; + } + + private: + Player const& i_player; + uint32 i_text_emote; + uint32 i_emote_num; + Unit const* i_target; + }; +} // namespace Trinity + +void WorldSession::HandleTextEmoteOpcode(WorldPacket & recv_data) +{ + if (!GetPlayer()->isAlive()) + return; + + if (!GetPlayer()->CanSpeak()) + { + std::string timeStr = secsToTimeString(m_muteTime - time(NULL)); + SendNotification(GetTrinityString(LANG_WAIT_BEFORE_SPEAKING), timeStr.c_str()); + return; + } + + uint32 text_emote, emoteNum; + uint64 guid; + + recv_data >> text_emote; + recv_data >> emoteNum; + recv_data >> guid; + + sScriptMgr->OnPlayerTextEmote(GetPlayer(), text_emote, emoteNum, guid); + + EmotesTextEntry const* em = sEmotesTextStore.LookupEntry(text_emote); + if (!em) + return; + + uint32 emote_anim = em->textid; + + switch (emote_anim) + { + case EMOTE_STATE_SLEEP: + case EMOTE_STATE_SIT: + case EMOTE_STATE_KNEEL: + case EMOTE_ONESHOT_NONE: + break; + default: + // Only allow text-emotes for "dead" entities (feign death included) + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + break; + GetPlayer()->HandleEmoteCommand(emote_anim); + break; + } + + Unit* unit = ObjectAccessor::GetUnit(*_player, guid); + + CellCoord p = Trinity::ComputeCellCoord(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY()); + + Cell cell(p); + cell.SetNoCreate(); + + Trinity::EmoteChatBuilder emote_builder(*GetPlayer(), text_emote, emoteNum, unit); + Trinity::LocalizedPacketDo emote_do(emote_builder); + Trinity::PlayerDistWorker > emote_worker(GetPlayer(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), emote_do); + TypeContainerVisitor >, WorldTypeMapContainer> message(emote_worker); + cell.Visit(p, message, *GetPlayer()->GetMap(), *GetPlayer(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE)); + + GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, text_emote, 0, unit); + + //Send scripted event call + if (unit && unit->GetTypeId() == TYPEID_UNIT && ((Creature*)unit)->AI()) + ((Creature*)unit)->AI()->ReceiveEmote(GetPlayer(), text_emote); +} + +void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recv_data) +{ + uint64 iguid; + uint8 unk; + //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: Received CMSG_CHAT_IGNORED"); + + recv_data >> iguid; + recv_data >> unk; // probably related to spam reporting + + Player* player = ObjectAccessor::FindPlayer(iguid); + if (!player || !player->GetSession()) + return; + + WorldPacket data; + ChatHandler::FillMessageData(&data, this, CHAT_MSG_IGNORED, LANG_UNIVERSAL, NULL, GetPlayer()->GetGUID(), GetPlayer()->GetName(), NULL); + player->GetSession()->SendPacket(&data); +} + +void WorldSession::HandleChannelDeclineInvite(WorldPacket &recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); +} + +void WorldSession::SendPlayerNotFoundNotice(std::string name) +{ + WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, name.size()+1); + data << name; + SendPacket(&data); +} + +void WorldSession::SendPlayerAmbiguousNotice(std::string name) +{ + WorldPacket data(SMSG_CHAT_PLAYER_AMBIGUOUS, name.size()+1); + data << name; + SendPacket(&data); +} + +void WorldSession::SendWrongFactionNotice() +{ + WorldPacket data(SMSG_CHAT_WRONG_FACTION, 0); + SendPacket(&data); +} + +void WorldSession::SendChatRestrictedNotice(ChatRestrictionType restriction) +{ + WorldPacket data(SMSG_CHAT_RESTRICTED, 1); + data << uint8(restriction); + SendPacket(&data); +} diff --git a/src/server/game/Handlers/CombatHandler.cpp b/src/server/game/Handlers/CombatHandler.cpp new file mode 100755 index 00000000000..6693cdfca27 --- /dev/null +++ b/src/server/game/Handlers/CombatHandler.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "Log.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "ObjectAccessor.h" +#include "CreatureAI.h" +#include "ObjectDefines.h" +#include "Vehicle.h" +#include "VehicleDefines.h" + +void WorldSession::HandleAttackSwingOpcode(WorldPacket& recv_data) +{ + uint64 guid; + recv_data >> guid; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_ATTACKSWING Message guidlow:%u guidhigh:%u", GUID_LOPART(guid), GUID_HIPART(guid)); + + Unit* pEnemy = ObjectAccessor::GetUnit(*_player, guid); + + if (!pEnemy) + { + // stop attack state at client + SendAttackStop(NULL); + return; + } + + if (!_player->IsValidAttackTarget(pEnemy)) + { + // stop attack state at client + SendAttackStop(pEnemy); + return; + } + + //! Client explicitly checks the following before sending CMSG_ATTACKSWING packet, + //! so we'll place the same check here. Note that it might be possible to reuse this snippet + //! in other places as well. + if (Vehicle* vehicle = _player->GetVehicle()) + { + VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(_player); + ASSERT(seat); + if (!(seat->m_flags & VEHICLE_SEAT_FLAG_CAN_ATTACK)) + { + SendAttackStop(pEnemy); + return; + } + } + + _player->Attack(pEnemy, true); +} + +void WorldSession::HandleAttackStopOpcode(WorldPacket & /*recv_data*/) +{ + GetPlayer()->AttackStop(); +} + +void WorldSession::HandleSetSheathedOpcode(WorldPacket& recv_data) +{ + uint32 sheathed; + recv_data >> sheathed; + + //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: Recvd CMSG_SETSHEATHED Message guidlow:%u value1:%u", GetPlayer()->GetGUIDLow(), sheathed); + + if (sheathed >= MAX_SHEATH_STATE) + { + sLog->outError("Unknown sheath state %u ??", sheathed); + return; + } + + GetPlayer()->SetSheath(SheathState(sheathed)); +} + +void WorldSession::SendAttackStop(Unit const* enemy) +{ + WorldPacket data(SMSG_ATTACKSTOP, (8+8+4)); // we guess size + data.append(GetPlayer()->GetPackGUID()); + data.append(enemy ? enemy->GetPackGUID() : 0); // must be packed guid + data << uint32(0); // unk, can be 1 also + SendPacket(&data); +} diff --git a/src/server/game/Handlers/DuelHandler.cpp b/src/server/game/Handlers/DuelHandler.cpp new file mode 100755 index 00000000000..8afd9f3b978 --- /dev/null +++ b/src/server/game/Handlers/DuelHandler.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Log.h" +#include "Opcodes.h" +#include "UpdateData.h" +#include "Player.h" + +void WorldSession::HandleDuelAcceptedOpcode(WorldPacket& recvPacket) +{ + uint64 guid; + Player* player; + Player* plTarget; + + recvPacket >> guid; + + if (!GetPlayer()->duel) // ignore accept from duel-sender + return; + + player = GetPlayer(); + plTarget = player->duel->opponent; + + if (player == player->duel->initiator || !plTarget || player == plTarget || player->duel->startTime != 0 || plTarget->duel->startTime != 0) + return; + + //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: Received CMSG_DUEL_ACCEPTED"); + sLog->outStaticDebug("Player 1 is: %u (%s)", player->GetGUIDLow(), player->GetName()); + sLog->outStaticDebug("Player 2 is: %u (%s)", plTarget->GetGUIDLow(), plTarget->GetName()); + + time_t now = time(NULL); + player->duel->startTimer = now; + plTarget->duel->startTimer = now; + + player->SendDuelCountdown(3000); + plTarget->SendDuelCountdown(3000); +} + +void WorldSession::HandleDuelCancelledOpcode(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_DUEL_CANCELLED"); + uint64 guid; + recvPacket >> guid; + + // no duel requested + if (!GetPlayer()->duel) + return; + + // player surrendered in a duel using /forfeit + if (GetPlayer()->duel->startTime != 0) + { + GetPlayer()->CombatStopWithPets(true); + if (GetPlayer()->duel->opponent) + GetPlayer()->duel->opponent->CombatStopWithPets(true); + + GetPlayer()->CastSpell(GetPlayer(), 7267, true); // beg + GetPlayer()->DuelComplete(DUEL_WON); + return; + } + + GetPlayer()->DuelComplete(DUEL_INTERRUPTED); +} diff --git a/src/server/game/Handlers/GroupHandler.cpp b/src/server/game/Handlers/GroupHandler.cpp new file mode 100755 index 00000000000..9343a5356b6 --- /dev/null +++ b/src/server/game/Handlers/GroupHandler.cpp @@ -0,0 +1,996 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "DatabaseEnv.h" +#include "Opcodes.h" +#include "Log.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "World.h" +#include "ObjectMgr.h" +#include "GroupMgr.h" +#include "Player.h" +#include "Group.h" +#include "SocialMgr.h" +#include "Util.h" +#include "SpellAuras.h" +#include "Vehicle.h" + +class Aura; + +/* differeces from off: + -you can uninvite yourself - is is useful + -you can accept invitation even if leader went offline +*/ +/* todo: + -group_destroyed msg is sent but not shown + -reduce xp gaining when in raid group + -quest sharing has to be corrected + -FIX sending PartyMemberStats +*/ + +void WorldSession::SendPartyResult(PartyOperation operation, const std::string& member, PartyResult res, uint32 val /* = 0 */) +{ + WorldPacket data(SMSG_PARTY_COMMAND_RESULT, 4 + member.size() + 1 + 4 + 4); + data << uint32(operation); + data << member; + data << uint32(res); + data << uint32(val); // LFD cooldown related (used with ERR_PARTY_LFG_BOOT_COOLDOWN_S and ERR_PARTY_LFG_BOOT_NOT_ELIGIBLE_S) + + SendPacket(&data); +} + +void WorldSession::HandleGroupInviteOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GROUP_INVITE"); + + std::string membername; + recv_data >> membername; + recv_data.read_skip(); + + // attempt add selected player + + // cheating + if (!normalizePlayerName(membername)) + { + SendPartyResult(PARTY_OP_INVITE, membername, ERR_BAD_PLAYER_NAME_S); + return; + } + + Player* player = sObjectAccessor->FindPlayerByName(membername.c_str()); + + // no player + if (!player) + { + SendPartyResult(PARTY_OP_INVITE, membername, ERR_BAD_PLAYER_NAME_S); + return; + } + + // restrict invite to GMs + if (!sWorld->getBoolConfig(CONFIG_ALLOW_GM_GROUP) && !GetPlayer()->isGameMaster() && player->isGameMaster()) + return; + + // can't group with + if (!GetPlayer()->isGameMaster() && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && GetPlayer()->GetTeam() != player->GetTeam()) + { + SendPartyResult(PARTY_OP_INVITE, membername, ERR_PLAYER_WRONG_FACTION); + return; + } + if (GetPlayer()->GetInstanceId() != 0 && player->GetInstanceId() != 0 && GetPlayer()->GetInstanceId() != player->GetInstanceId() && GetPlayer()->GetMapId() == player->GetMapId()) + { + SendPartyResult(PARTY_OP_INVITE, membername, ERR_TARGET_NOT_IN_INSTANCE_S); + return; + } + // just ignore us + if (player->GetInstanceId() != 0 && player->GetDungeonDifficulty() != GetPlayer()->GetDungeonDifficulty()) + { + SendPartyResult(PARTY_OP_INVITE, membername, ERR_IGNORING_YOU_S); + return; + } + + if (player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) + { + SendPartyResult(PARTY_OP_INVITE, membername, ERR_IGNORING_YOU_S); + return; + } + + Group* group = GetPlayer()->GetGroup(); + if (group && group->isBGGroup()) + group = GetPlayer()->GetOriginalGroup(); + + Group* group2 = player->GetGroup(); + if (group2 && group2->isBGGroup()) + group2 = player->GetOriginalGroup(); + // player already in another group or invited + if (group2 || player->GetGroupInvite()) + { + SendPartyResult(PARTY_OP_INVITE, membername, ERR_ALREADY_IN_GROUP_S); + + if (group2) + { + // tell the player that they were invited but it failed as they were already in a group + WorldPacket data(SMSG_GROUP_INVITE, 10); // guess size + data << uint8(0); // invited/already in group flag + data << GetPlayer()->GetName(); // max len 48 + data << uint32(0); // unk + data << uint8(0); // count + data << uint32(0); // unk + player->GetSession()->SendPacket(&data); + } + + return; + } + + if (group) + { + // not have permissions for invite + if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) + { + SendPartyResult(PARTY_OP_INVITE, "", ERR_NOT_LEADER); + return; + } + // not have place + if (group->IsFull()) + { + SendPartyResult(PARTY_OP_INVITE, "", ERR_GROUP_FULL); + return; + } + } + + // ok, but group not exist, start a new group + // but don't create and save the group to the DB until + // at least one person joins + if (!group) + { + group = new Group; + // new group: if can't add then delete + if (!group->AddLeaderInvite(GetPlayer())) + { + delete group; + return; + } + if (!group->AddInvite(player)) + { + delete group; + return; + } + } + else + { + // already existed group: if can't add then just leave + if (!group->AddInvite(player)) + { + return; + } + } + + // ok, we do it + WorldPacket data(SMSG_GROUP_INVITE, 10); // guess size + data << uint8(1); // invited/already in group flag + data << GetPlayer()->GetName(); // max len 48 + data << uint32(0); // unk + data << uint8(0); // count + data << uint32(0); // unk + player->GetSession()->SendPacket(&data); + + SendPartyResult(PARTY_OP_INVITE, membername, ERR_PARTY_RESULT_OK); +} + +void WorldSession::HandleGroupAcceptOpcode(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GROUP_ACCEPT"); + + recv_data.read_skip(); + Group* group = GetPlayer()->GetGroupInvite(); + + if (!group) + return; + + // Remove player from invitees in any case + group->RemoveInvite(GetPlayer()); + + if (group->GetLeaderGUID() == GetPlayer()->GetGUID()) + { + sLog->outError("HandleGroupAcceptOpcode: player %s(%d) tried to accept an invite to his own group", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow()); + return; + } + + // Group is full + if (group->IsFull()) + { + SendPartyResult(PARTY_OP_INVITE, "", ERR_GROUP_FULL); + return; + } + + Player* leader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()); + + // Forming a new group, create it + if (!group->IsCreated()) + { + // This can happen if the leader is zoning. To be removed once delayed actions for zoning are implemented + if (!leader) + { + group->RemoveAllInvites(); + return; + } + + // If we're about to create a group there really should be a leader present + ASSERT(leader); + group->RemoveInvite(leader); + group->Create(leader); + sGroupMgr->AddGroup(group); + } + + // Everything is fine, do it, PLAYER'S GROUP IS SET IN ADDMEMBER!!! + if (!group->AddMember(GetPlayer())) + return; + + group->BroadcastGroupUpdate(); +} + +void WorldSession::HandleGroupDeclineOpcode(WorldPacket & /*recv_data*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GROUP_DECLINE"); + + Group *group = GetPlayer()->GetGroupInvite(); + if (!group) return; + + // Remember leader if online (group pointer will be invalid if group gets disbanded) + Player* leader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()); + + // uninvite, group can be deleted + GetPlayer()->UninviteFromGroup(); + + if (!leader || !leader->GetSession()) + return; + + // report + std::string name = std::string(GetPlayer()->GetName()); + WorldPacket data(SMSG_GROUP_DECLINE, name.length()); + data << name.c_str(); + leader->GetSession()->SendPacket(&data); +} + +void WorldSession::HandleGroupUninviteGuidOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GROUP_UNINVITE_GUID"); + + uint64 guid; + std::string reason; + recv_data >> guid; + recv_data >> reason; + + //can't uninvite yourself + if (guid == GetPlayer()->GetGUID()) + { + sLog->outError("WorldSession::HandleGroupUninviteGuidOpcode: leader %s(%d) tried to uninvite himself from the group.", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow()); + return; + } + + PartyResult res = GetPlayer()->CanUninviteFromGroup(); + if (res != ERR_PARTY_RESULT_OK) + { + SendPartyResult(PARTY_OP_UNINVITE, "", res); + return; + } + + Group* grp = GetPlayer()->GetGroup(); + if (!grp) + return; + + if (grp->IsLeader(guid)) + { + SendPartyResult(PARTY_OP_UNINVITE, "", ERR_NOT_LEADER); + return; + } + + if (grp->IsMember(guid)) + { + Player::RemoveFromGroup(grp, guid, GROUP_REMOVEMETHOD_KICK, GetPlayer()->GetGUID(), reason.c_str()); + return; + } + + if (Player* player = grp->GetInvited(guid)) + { + player->UninviteFromGroup(); + return; + } + + SendPartyResult(PARTY_OP_UNINVITE, "", ERR_TARGET_NOT_IN_GROUP_S); +} + +void WorldSession::HandleGroupUninviteOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GROUP_UNINVITE"); + + std::string membername; + recv_data >> membername; + + // player not found + if (!normalizePlayerName(membername)) + return; + + // can't uninvite yourself + if (GetPlayer()->GetName() == membername) + { + sLog->outError("WorldSession::HandleGroupUninviteOpcode: leader %s(%d) tried to uninvite himself from the group.", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow()); + return; + } + + PartyResult res = GetPlayer()->CanUninviteFromGroup(); + if (res != ERR_PARTY_RESULT_OK) + { + SendPartyResult(PARTY_OP_UNINVITE, "", res); + return; + } + + Group* grp = GetPlayer()->GetGroup(); + if (!grp) + return; + + if (uint64 guid = grp->GetMemberGUID(membername)) + { + Player::RemoveFromGroup(grp, guid, GROUP_REMOVEMETHOD_KICK, GetPlayer()->GetGUID()); + return; + } + + if (Player* player = grp->GetInvited(membername)) + { + player->UninviteFromGroup(); + return; + } + + SendPartyResult(PARTY_OP_UNINVITE, membername, ERR_TARGET_NOT_IN_GROUP_S); +} + +void WorldSession::HandleGroupSetLeaderOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GROUP_SET_LEADER"); + + uint64 guid; + recv_data >> guid; + + Player* player = ObjectAccessor::FindPlayer(guid); + Group* group = GetPlayer()->GetGroup(); + + if (!group || !player) + return; + + if (!group->IsLeader(GetPlayer()->GetGUID()) || player->GetGroup() != group) + return; + + // Everything's fine, accepted. + group->ChangeLeader(guid); + group->SendUpdate(); +} + +void WorldSession::HandleGroupDisbandOpcode(WorldPacket & /*recv_data*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GROUP_DISBAND"); + + Group* grp = GetPlayer()->GetGroup(); + if (!grp) + return; + + if (_player->InBattleground()) + { + SendPartyResult(PARTY_OP_INVITE, "", ERR_INVITE_RESTRICTED); + return; + } + + /** error handling **/ + /********************/ + + // everything's fine, do it + SendPartyResult(PARTY_OP_LEAVE, GetPlayer()->GetName(), ERR_PARTY_RESULT_OK); + + GetPlayer()->RemoveFromGroup(GROUP_REMOVEMETHOD_LEAVE); +} + +void WorldSession::HandleLootMethodOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_LOOT_METHOD"); + + uint32 lootMethod; + uint64 lootMaster; + uint32 lootThreshold; + recv_data >> lootMethod >> lootMaster >> lootThreshold; + + Group* group = GetPlayer()->GetGroup(); + if (!group) + return; + + /** error handling **/ + if (!group->IsLeader(GetPlayer()->GetGUID())) + return; + /********************/ + + // everything's fine, do it + group->SetLootMethod((LootMethod)lootMethod); + group->SetLooterGuid(lootMaster); + group->SetLootThreshold((ItemQualities)lootThreshold); + group->SendUpdate(); +} + +void WorldSession::HandleLootRoll(WorldPacket &recv_data) +{ + if (!GetPlayer()->GetGroup()) + { + recv_data.rfinish(); + return; + } + + uint64 Guid; + uint32 NumberOfPlayers; + uint8 rollType; + recv_data >> Guid; //guid of the item rolled + recv_data >> NumberOfPlayers; + recv_data >> rollType; //0: pass, 1: need, 2: greed + + //sLog->outDebug("WORLD RECIEVE CMSG_LOOT_ROLL, From:%u, Numberofplayers:%u, Choise:%u", (uint32)Guid, NumberOfPlayers, Choise); + + Group* group = GetPlayer()->GetGroup(); + if (!group) + return; + + // everything's fine, do it + group->CountRollVote(GetPlayer()->GetGUID(), Guid, NumberOfPlayers, rollType); + + switch (rollType) + { + case ROLL_NEED: + GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED, 1); + break; + case ROLL_GREED: + GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED, 1); + break; + } +} + +void WorldSession::HandleMinimapPingOpcode(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received MSG_MINIMAP_PING"); + + if (!GetPlayer()->GetGroup()) + return; + + float x, y; + recv_data >> x; + recv_data >> y; + + //sLog->outDebug("Received opcode MSG_MINIMAP_PING X: %f, Y: %f", x, y); + + /** error handling **/ + /********************/ + + // everything's fine, do it + WorldPacket data(MSG_MINIMAP_PING, (8+4+4)); + data << uint64(GetPlayer()->GetGUID()); + data << float(x); + data << float(y); + GetPlayer()->GetGroup()->BroadcastPacket(&data, true, -1, GetPlayer()->GetGUID()); +} + +void WorldSession::HandleRandomRollOpcode(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received MSG_RANDOM_ROLL"); + + uint32 minimum, maximum, roll; + recv_data >> minimum; + recv_data >> maximum; + + /** error handling **/ + if (minimum > maximum || maximum > 10000) // < 32768 for urand call + return; + /********************/ + + // everything's fine, do it + roll = urand(minimum, maximum); + + //sLog->outDebug("ROLL: MIN: %u, MAX: %u, ROLL: %u", minimum, maximum, roll); + + WorldPacket data(MSG_RANDOM_ROLL, 4+4+4+8); + data << uint32(minimum); + data << uint32(maximum); + data << uint32(roll); + data << uint64(GetPlayer()->GetGUID()); + if (GetPlayer()->GetGroup()) + GetPlayer()->GetGroup()->BroadcastPacket(&data, false); + else + SendPacket(&data); +} + +void WorldSession::HandleRaidTargetUpdateOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received MSG_RAID_TARGET_UPDATE"); + + Group* group = GetPlayer()->GetGroup(); + if (!group) + return; + + uint8 x; + recv_data >> x; + + /** error handling **/ + /********************/ + + // everything's fine, do it + if (x == 0xFF) // target icon request + { + group->SendTargetIconList(this); + } + else // target icon update + { + if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) + return; + + uint64 guid; + recv_data >> guid; + group->SetTargetIcon(x, _player->GetGUID(), guid); + } +} + +void WorldSession::HandleGroupRaidConvertOpcode(WorldPacket & /*recv_data*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GROUP_RAID_CONVERT"); + + Group* group = GetPlayer()->GetGroup(); + if (!group) + return; + + if (_player->InBattleground()) + return; + + /** error handling **/ + if (!group->IsLeader(GetPlayer()->GetGUID()) || group->GetMembersCount() < 2) + return; + /********************/ + + // everything's fine, do it (is it 0 (PARTY_OP_INVITE) correct code) + SendPartyResult(PARTY_OP_INVITE, "", ERR_PARTY_RESULT_OK); + group->ConvertToRaid(); +} + +void WorldSession::HandleGroupChangeSubGroupOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GROUP_CHANGE_SUB_GROUP"); + + // we will get correct pointer for group here, so we don't have to check if group is BG raid + Group* group = GetPlayer()->GetGroup(); + if (!group) + return; + + std::string name; + uint8 groupNr; + recv_data >> name; + recv_data >> groupNr; + + if (groupNr >= MAX_RAID_SUBGROUPS) + return; + + uint64 senderGuid = GetPlayer()->GetGUID(); + if (!group->IsLeader(senderGuid) && !group->IsAssistant(senderGuid)) + return; + + if (!group->HasFreeSlotSubGroup(groupNr)) + return; + + Player* movedPlayer = sObjectAccessor->FindPlayerByName(name.c_str()); + uint64 guid; + if (movedPlayer) + { + guid = movedPlayer->GetGUID(); + } + else + { + CharacterDatabase.EscapeString(name); + guid = sObjectMgr->GetPlayerGUIDByName(name.c_str()); + } + + group->ChangeMembersGroup(guid, groupNr); +} + +void WorldSession::HandleGroupAssistantLeaderOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GROUP_ASSISTANT_LEADER"); + + Group* group = GetPlayer()->GetGroup(); + if (!group) + return; + + if (!group->IsLeader(GetPlayer()->GetGUID())) + return; + + uint64 guid; + bool apply; + recv_data >> guid; + recv_data >> apply; + + group->SetGroupMemberFlag(guid, apply, MEMBER_FLAG_ASSISTANT); + + group->SendUpdate(); +} + +void WorldSession::HandlePartyAssignmentOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received MSG_PARTY_ASSIGNMENT"); + + Group* group = GetPlayer()->GetGroup(); + if (!group) + return; + + uint64 senderGuid = GetPlayer()->GetGUID(); + if (!group->IsLeader(senderGuid) && !group->IsAssistant(senderGuid)) + return; + + uint8 assignment; + bool apply; + uint64 guid; + recv_data >> assignment >> apply; + recv_data >> guid; + + switch (assignment) + { + case GROUP_ASSIGN_MAINASSIST: + group->RemoveUniqueGroupMemberFlag(MEMBER_FLAG_MAINASSIST); + group->SetGroupMemberFlag(guid, apply, MEMBER_FLAG_MAINASSIST); + break; + case GROUP_ASSIGN_MAINTANK: + group->RemoveUniqueGroupMemberFlag(MEMBER_FLAG_MAINTANK); // Remove main assist flag from current if any. + group->SetGroupMemberFlag(guid, apply, MEMBER_FLAG_MAINTANK); + default: + break; + } + + group->SendUpdate(); +} + +void WorldSession::HandleRaidReadyCheckOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received MSG_RAID_READY_CHECK"); + + Group* group = GetPlayer()->GetGroup(); + if (!group) + return; + + if (recv_data.empty()) // request + { + /** error handling **/ + if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) + return; + /********************/ + + // everything's fine, do it + WorldPacket data(MSG_RAID_READY_CHECK, 8); + data << GetPlayer()->GetGUID(); + group->BroadcastPacket(&data, false, -1); + + group->OfflineReadyCheck(); + } + else // answer + { + uint8 state; + recv_data >> state; + + // everything's fine, do it + WorldPacket data(MSG_RAID_READY_CHECK_CONFIRM, 9); + data << uint64(GetPlayer()->GetGUID()); + data << uint8(state); + group->BroadcastReadyCheck(&data); + } +} + +void WorldSession::HandleRaidReadyCheckFinishedOpcode(WorldPacket & /*recv_data*/) +{ + //Group* group = GetPlayer()->GetGroup(); + //if (!group) + // return; + + //if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) + // return; + + // Is any reaction need? +} + +void WorldSession::BuildPartyMemberStatsChangedPacket(Player* player, WorldPacket* data) +{ + uint32 mask = player->GetGroupUpdateFlag(); + + if (mask == GROUP_UPDATE_FLAG_NONE) + return; + + if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) // if update power type, update current/max power also + mask |= (GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER); + + if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) // same for pets + mask |= (GROUP_UPDATE_FLAG_PET_CUR_POWER | GROUP_UPDATE_FLAG_PET_MAX_POWER); + + uint32 byteCount = 0; + for (int i = 1; i < GROUP_UPDATE_FLAGS_COUNT; ++i) + if (mask & (1 << i)) + byteCount += GroupUpdateLength[i]; + + data->Initialize(SMSG_PARTY_MEMBER_STATS, 8 + 4 + byteCount); + data->append(player->GetPackGUID()); + *data << (uint32) mask; + + if (mask & GROUP_UPDATE_FLAG_STATUS) + { + if (player) + { + if (player->IsPvP()) + *data << (uint16) (MEMBER_STATUS_ONLINE | MEMBER_STATUS_PVP); + else + *data << (uint16) MEMBER_STATUS_ONLINE; + } + else + *data << (uint16) MEMBER_STATUS_OFFLINE; + } + + if (mask & GROUP_UPDATE_FLAG_CUR_HP) + *data << (uint32) player->GetHealth(); + + if (mask & GROUP_UPDATE_FLAG_MAX_HP) + *data << (uint32) player->GetMaxHealth(); + + Powers powerType = player->getPowerType(); + if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) + *data << (uint8) powerType; + + if (mask & GROUP_UPDATE_FLAG_CUR_POWER) + *data << (uint16) player->GetPower(powerType); + + if (mask & GROUP_UPDATE_FLAG_MAX_POWER) + *data << (uint16) player->GetMaxPower(powerType); + + if (mask & GROUP_UPDATE_FLAG_LEVEL) + *data << (uint16) player->getLevel(); + + if (mask & GROUP_UPDATE_FLAG_ZONE) + *data << (uint16) player->GetZoneId(); + + if (mask & GROUP_UPDATE_FLAG_POSITION) + *data << (uint16) player->GetPositionX() << (uint16) player->GetPositionY(); + + if (mask & GROUP_UPDATE_FLAG_AURAS) + { + uint64 auramask = player->GetAuraUpdateMaskForRaid(); + *data << uint64(auramask); + for (uint32 i = 0; i < MAX_AURAS; ++i) + { + if (auramask & (uint64(1) << i)) + { + AuraApplication const* aurApp = player->GetVisibleAura(i); + *data << uint32(aurApp ? aurApp->GetBase()->GetId() : 0); + *data << uint8(1); + } + } + } + + Pet* pet = player->GetPet(); + if (mask & GROUP_UPDATE_FLAG_PET_GUID) + { + if (pet) + *data << (uint64) pet->GetGUID(); + else + *data << (uint64) 0; + } + + if (mask & GROUP_UPDATE_FLAG_PET_NAME) + { + if (pet) + *data << pet->GetName(); + else + *data << (uint8) 0; + } + + if (mask & GROUP_UPDATE_FLAG_PET_MODEL_ID) + { + if (pet) + *data << (uint16) pet->GetDisplayId(); + else + *data << (uint16) 0; + } + + if (mask & GROUP_UPDATE_FLAG_PET_CUR_HP) + { + if (pet) + *data << (uint32) pet->GetHealth(); + else + *data << (uint32) 0; + } + + if (mask & GROUP_UPDATE_FLAG_PET_MAX_HP) + { + if (pet) + *data << (uint32) pet->GetMaxHealth(); + else + *data << (uint32) 0; + } + + if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) + { + if (pet) + *data << (uint8) pet->getPowerType(); + else + *data << (uint8) 0; + } + + if (mask & GROUP_UPDATE_FLAG_PET_CUR_POWER) + { + if (pet) + *data << (uint16) pet->GetPower(pet->getPowerType()); + else + *data << (uint16) 0; + } + + if (mask & GROUP_UPDATE_FLAG_PET_MAX_POWER) + { + if (pet) + *data << (uint16) pet->GetMaxPower(pet->getPowerType()); + else + *data << (uint16) 0; + } + + if (mask & GROUP_UPDATE_FLAG_VEHICLE_SEAT) + { + if (Vehicle* veh = player->GetVehicle()) + *data << (uint32) veh->GetVehicleInfo()->m_seatID[player->m_movementInfo.t_seat]; + } + + if (mask & GROUP_UPDATE_FLAG_PET_AURAS) + { + if (pet) + { + uint64 auramask = pet->GetAuraUpdateMaskForRaid(); + *data << uint64(auramask); + for (uint32 i = 0; i < MAX_AURAS; ++i) + { + if (auramask & (uint64(1) << i)) + { + AuraApplication const* aurApp = player->GetVisibleAura(i); + *data << uint32(aurApp ? aurApp->GetBase()->GetId() : 0); + *data << uint8(1); + } + } + } + else + *data << (uint64) 0; + } +} + +/*this procedure handles clients CMSG_REQUEST_PARTY_MEMBER_STATS request*/ +void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket &recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_REQUEST_PARTY_MEMBER_STATS"); + uint64 Guid; + recv_data >> Guid; + + Player* player = HashMapHolder::Find(Guid); + if (!player) + { + WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 3+4+2); + data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related + data.appendPackGUID(Guid); + data << (uint32) GROUP_UPDATE_FLAG_STATUS; + data << (uint16) MEMBER_STATUS_OFFLINE; + SendPacket(&data); + return; + } + + Pet* pet = player->GetPet(); + + WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 4+2+2+2+1+2*6+8+1+8); + data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related + data.append(player->GetPackGUID()); + + uint32 mask1 = 0x00040BFF; // common mask, real flags used 0x000040BFF + if (pet) + mask1 = 0x7FFFFFFF; // for hunters and other classes with pets + + Powers powerType = player->getPowerType(); + data << (uint32) mask1; // group update mask + data << (uint16) MEMBER_STATUS_ONLINE; // member's online status + data << (uint32) player->GetHealth(); // GROUP_UPDATE_FLAG_CUR_HP + data << (uint32) player->GetMaxHealth(); // GROUP_UPDATE_FLAG_MAX_HP + data << (uint8) powerType; // GROUP_UPDATE_FLAG_POWER_TYPE + data << (uint16) player->GetPower(powerType); // GROUP_UPDATE_FLAG_CUR_POWER + data << (uint16) player->GetMaxPower(powerType); // GROUP_UPDATE_FLAG_MAX_POWER + data << (uint16) player->getLevel(); // GROUP_UPDATE_FLAG_LEVEL + data << (uint16) player->GetZoneId(); // GROUP_UPDATE_FLAG_ZONE + data << (uint16) player->GetPositionX(); // GROUP_UPDATE_FLAG_POSITION + data << (uint16) player->GetPositionY(); // GROUP_UPDATE_FLAG_POSITION + + uint64 auramask = 0; + size_t maskPos = data.wpos(); + data << (uint64) auramask; // placeholder + for (uint8 i = 0; i < MAX_AURAS; ++i) + { + if (AuraApplication * aurApp = player->GetVisibleAura(i)) + { + auramask |= (uint64(1) << i); + data << (uint32) aurApp->GetBase()->GetId(); + data << (uint8) 1; + } + } + data.put(maskPos, auramask); // GROUP_UPDATE_FLAG_AURAS + + if (pet) + { + Powers petpowertype = pet->getPowerType(); + data << (uint64) pet->GetGUID(); // GROUP_UPDATE_FLAG_PET_GUID + data << pet->GetName(); // GROUP_UPDATE_FLAG_PET_NAME + data << (uint16) pet->GetDisplayId(); // GROUP_UPDATE_FLAG_PET_MODEL_ID + data << (uint32) pet->GetHealth(); // GROUP_UPDATE_FLAG_PET_CUR_HP + data << (uint32) pet->GetMaxHealth(); // GROUP_UPDATE_FLAG_PET_MAX_HP + data << (uint8) petpowertype; // GROUP_UPDATE_FLAG_PET_POWER_TYPE + data << (uint16) pet->GetPower(petpowertype); // GROUP_UPDATE_FLAG_PET_CUR_POWER + data << (uint16) pet->GetMaxPower(petpowertype); // GROUP_UPDATE_FLAG_PET_MAX_POWER + + uint64 petauramask = 0; + size_t petMaskPos = data.wpos(); + data << (uint64) petauramask; // placeholder + for (uint8 i = 0; i < MAX_AURAS; ++i) + { + if (AuraApplication * auraApp = pet->GetVisibleAura(i)) + { + petauramask |= (uint64(1) << i); + data << (uint32) auraApp->GetBase()->GetId(); + data << (uint8) 1; + } + } + data.put(petMaskPos, petauramask); // GROUP_UPDATE_FLAG_PET_AURAS + } + else + { + data << (uint8) 0; // GROUP_UPDATE_FLAG_PET_NAME + data << (uint64) 0; // GROUP_UPDATE_FLAG_PET_AURAS + } + + SendPacket(&data); +} + +/*!*/void WorldSession::HandleRequestRaidInfoOpcode(WorldPacket & /*recv_data*/) +{ + // every time the player checks the character screen + _player->SendRaidInfo(); +} + +/*void WorldSession::HandleGroupCancelOpcode(WorldPacket & recv_data) +{ + sLog->outDebug("WORLD: got CMSG_GROUP_CANCEL."); +}*/ + +void WorldSession::HandleOptOutOfLootOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_OPT_OUT_OF_LOOT"); + + uint32 passOnLoot; + recv_data >> passOnLoot; // 1 always pass, 0 do not pass + + // ignore if player not loaded + if (!GetPlayer()) // needed because STATUS_AUTHED + { + if (passOnLoot != 0) + sLog->outError("CMSG_OPT_OUT_OF_LOOT value<>0 for not-loaded character!"); + return; + } + + GetPlayer()->SetPassOnGroupLoot(passOnLoot); +} diff --git a/src/server/game/Handlers/GuildHandler.cpp b/src/server/game/Handlers/GuildHandler.cpp new file mode 100755 index 00000000000..d2a5f8014b8 --- /dev/null +++ b/src/server/game/Handlers/GuildHandler.cpp @@ -0,0 +1,570 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "World.h" +#include "ObjectMgr.h" +#include "GuildMgr.h" +#include "Log.h" +#include "Opcodes.h" +#include "Guild.h" +#include "GossipDef.h" +#include "SocialMgr.h" + +// Helper for getting guild object of session's player. +// If guild does not exist, sends error (if necessary). +inline Guild* _GetPlayerGuild(WorldSession* session, bool sendError = false) +{ + if (uint32 guildId = session->GetPlayer()->GetGuildId()) // If guild id = 0, player is not in guild + if (Guild* guild = sGuildMgr->GetGuildById(guildId)) // Find guild by id + return guild; + if (sendError) + Guild::SendCommandResult(session, GUILD_CREATE_S, ERR_GUILD_PLAYER_NOT_IN_GUILD); + return NULL; +} + +void WorldSession::HandleGuildQueryOpcode(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_QUERY"); + + uint32 guildId; + recvPacket >> guildId; + // Use received guild id to access guild method (not player's guild id) + if (Guild* guild = sGuildMgr->GetGuildById(guildId)) + guild->HandleQuery(this); + else + Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_PLAYER_NOT_IN_GUILD); +} + +void WorldSession::HandleGuildCreateOpcode(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_CREATE"); + + std::string name; + recvPacket >> name; + + if (!GetPlayer()->GetGuildId()) // Player cannot be in guild + { + Guild* guild = new Guild(); + if (guild->Create(GetPlayer(), name)) + sGuildMgr->AddGuild(guild); + else + delete guild; + } +} + +void WorldSession::HandleGuildInviteOpcode(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_INVITE"); + + std::string invitedName; + recvPacket >> invitedName; + + if (normalizePlayerName(invitedName)) + if (Guild* guild = _GetPlayerGuild(this, true)) + guild->HandleInviteMember(this, invitedName); +} + +void WorldSession::HandleGuildRemoveOpcode(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_REMOVE"); + + std::string playerName; + recvPacket >> playerName; + + if (normalizePlayerName(playerName)) + if (Guild* guild = _GetPlayerGuild(this, true)) + guild->HandleRemoveMember(this, playerName); +} + +void WorldSession::HandleGuildAcceptOpcode(WorldPacket& /*recvPacket*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_ACCEPT"); + // Player cannot be in guild + if (!GetPlayer()->GetGuildId()) + // Guild where player was invited must exist + if (Guild* guild = sGuildMgr->GetGuildById(GetPlayer()->GetGuildIdInvited())) + guild->HandleAcceptMember(this); +} + +void WorldSession::HandleGuildDeclineOpcode(WorldPacket& /*recvPacket*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_DECLINE"); + + GetPlayer()->SetGuildIdInvited(0); + GetPlayer()->SetInGuild(0); +} + +void WorldSession::HandleGuildInfoOpcode(WorldPacket& /*recvPacket*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_INFO"); + + if (Guild* guild = _GetPlayerGuild(this, true)) + guild->SendInfo(this); +} + +void WorldSession::HandleGuildRosterOpcode(WorldPacket& /*recvPacket*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_ROSTER"); + + if (Guild* guild = _GetPlayerGuild(this)) + guild->HandleRoster(this); +} + +void WorldSession::HandleGuildPromoteOpcode(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_PROMOTE"); + + std::string playerName; + recvPacket >> playerName; + + if (normalizePlayerName(playerName)) + if (Guild* guild = _GetPlayerGuild(this, true)) + guild->HandleUpdateMemberRank(this, playerName, false); +} + +void WorldSession::HandleGuildDemoteOpcode(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_DEMOTE"); + + std::string playerName; + recvPacket >> playerName; + + if (normalizePlayerName(playerName)) + if (Guild* guild = _GetPlayerGuild(this, true)) + guild->HandleUpdateMemberRank(this, playerName, true); +} + +void WorldSession::HandleGuildLeaveOpcode(WorldPacket& /*recvPacket*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_LEAVE"); + + if (Guild* guild = _GetPlayerGuild(this, true)) + guild->HandleLeaveMember(this); +} + +void WorldSession::HandleGuildDisbandOpcode(WorldPacket& /*recvPacket*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_DISBAND"); + + if (Guild* guild = _GetPlayerGuild(this, true)) + guild->HandleDisband(this); +} + +void WorldSession::HandleGuildLeaderOpcode(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_LEADER"); + + std::string name; + recvPacket >> name; + + if (normalizePlayerName(name)) + if (Guild* guild = _GetPlayerGuild(this, true)) + guild->HandleSetLeader(this, name); +} + +void WorldSession::HandleGuildMOTDOpcode(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_MOTD"); + + std::string motd; // Empty by default + if (!recvPacket.empty()) + recvPacket >> motd; + + if (Guild* guild = _GetPlayerGuild(this, true)) + guild->HandleSetMOTD(this, motd); +} + +void WorldSession::HandleGuildSetPublicNoteOpcode(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_SET_PUBLIC_NOTE"); + + std::string playerName; + recvPacket >> playerName; + + std::string publicNote; + recvPacket >> publicNote; + + if (normalizePlayerName(playerName)) + if (Guild* guild = _GetPlayerGuild(this, true)) + guild->HandleSetMemberNote(this, playerName, publicNote, false); +} + +void WorldSession::HandleGuildSetOfficerNoteOpcode(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_SET_OFFICER_NOTE"); + + std::string playerName; + recvPacket >> playerName; + + std::string officerNote; + recvPacket >> officerNote; + + if (normalizePlayerName(playerName)) + if (Guild* guild = _GetPlayerGuild(this, true)) + guild->HandleSetMemberNote(this, playerName, officerNote, true); +} + +void WorldSession::HandleGuildRankOpcode(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_RANK"); + + Guild* guild = _GetPlayerGuild(this, true); + if (!guild) + { + recvPacket.rpos(recvPacket.wpos()); + return; + } + + uint32 rankId; + recvPacket >> rankId; + + uint32 rights; + recvPacket >> rights; + + std::string rankName; + recvPacket >> rankName; + + uint32 money; + recvPacket >> money; + + GuildBankRightsAndSlotsVec rightsAndSlots(GUILD_BANK_MAX_TABS); + for (uint8 tabId = 0; tabId < GUILD_BANK_MAX_TABS; ++tabId) + { + uint32 bankRights; + uint32 slots; + + recvPacket >> bankRights; + recvPacket >> slots; + + rightsAndSlots[tabId] = GuildBankRightsAndSlots(uint8(bankRights), slots); + } + + guild->HandleSetRankInfo(this, rankId, rankName, rights, money, rightsAndSlots); +} + +void WorldSession::HandleGuildAddRankOpcode(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_ADD_RANK"); + + std::string rankName; + recvPacket >> rankName; + + if (Guild* guild = _GetPlayerGuild(this, true)) + guild->HandleAddNewRank(this, rankName); +} + +void WorldSession::HandleGuildDelRankOpcode(WorldPacket& /*recvPacket*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_DEL_RANK"); + + if (Guild* guild = _GetPlayerGuild(this, true)) + guild->HandleRemoveLowestRank(this); +} + +void WorldSession::HandleGuildChangeInfoTextOpcode(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_INFO_TEXT"); + + std::string info; + recvPacket >> info; + + if (Guild* guild = _GetPlayerGuild(this, true)) + guild->HandleSetInfo(this, info); +} + +void WorldSession::HandleSaveGuildEmblemOpcode(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received MSG_SAVE_GUILD_EMBLEM"); + + uint64 vendorGuid; + recvPacket >> vendorGuid; + + EmblemInfo emblemInfo; + emblemInfo.ReadPacket(recvPacket); + + if (GetPlayer()->GetNPCIfCanInteractWith(vendorGuid, UNIT_NPC_FLAG_TABARDDESIGNER)) + { + // Remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + if (Guild* guild = _GetPlayerGuild(this)) + guild->HandleSetEmblem(this, emblemInfo); + else + // "You are not part of a guild!"; + Guild::SendSaveEmblemResult(this, ERR_GUILDEMBLEM_NOGUILD); + } + else + { + // "That's not an emblem vendor!" + Guild::SendSaveEmblemResult(this, ERR_GUILDEMBLEM_INVALIDVENDOR); + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleSaveGuildEmblemOpcode - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(vendorGuid)); + } +} + +void WorldSession::HandleGuildEventLogQueryOpcode(WorldPacket& /* recvPacket */) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (MSG_GUILD_EVENT_LOG_QUERY)"); + + if (Guild* guild = _GetPlayerGuild(this)) + guild->SendEventLog(this); +} + +void WorldSession::HandleGuildBankMoneyWithdrawn(WorldPacket & /* recv_data */) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (MSG_GUILD_BANK_MONEY_WITHDRAWN)"); + + if (Guild* guild = _GetPlayerGuild(this)) + guild->SendMoneyInfo(this); +} + +void WorldSession::HandleGuildPermissions(WorldPacket& /* recv_data */) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (MSG_GUILD_PERMISSIONS)"); + + if (Guild* guild = _GetPlayerGuild(this)) + guild->SendPermissions(this); +} + +// Called when clicking on Guild bank gameobject +void WorldSession::HandleGuildBankerActivate(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (CMSG_GUILD_BANKER_ACTIVATE)"); + + uint64 GoGuid; + recv_data >> GoGuid; + + uint8 unk; + recv_data >> unk; + + if (GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) + { + if (Guild* guild = _GetPlayerGuild(this)) + guild->SendBankTabsInfo(this); + else + Guild::SendCommandResult(this, GUILD_UNK1, ERR_GUILD_PLAYER_NOT_IN_GUILD); + } +} + +// Called when opening guild bank tab only (first one) +void WorldSession::HandleGuildBankQueryTab(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (CMSG_GUILD_BANK_QUERY_TAB)"); + + uint64 GoGuid; + recv_data >> GoGuid; + + uint8 tabId; + recv_data >> tabId; + + uint8 unk1; + recv_data >> unk1; + + if (GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) + if (Guild* guild = _GetPlayerGuild(this)) + guild->SendBankTabData(this, tabId); +} + +void WorldSession::HandleGuildBankDepositMoney(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (CMSG_GUILD_BANK_DEPOSIT_MONEY)"); + + uint64 GoGuid; + recv_data >> GoGuid; + + uint32 money; + recv_data >> money; + + if (GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) + if (money && GetPlayer()->HasEnoughMoney(money)) + if (Guild* guild = _GetPlayerGuild(this)) + guild->HandleMemberDepositMoney(this, money); +} + +void WorldSession::HandleGuildBankWithdrawMoney(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (CMSG_GUILD_BANK_WITHDRAW_MONEY)"); + + uint64 GoGuid; + recv_data >> GoGuid; + + uint32 money; + recv_data >> money; + + if (money) + if (GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) + if (Guild* guild = _GetPlayerGuild(this)) + guild->HandleMemberWithdrawMoney(this, money); +} + +void WorldSession::HandleGuildBankSwapItems(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (CMSG_GUILD_BANK_SWAP_ITEMS)"); + + uint64 GoGuid; + recv_data >> GoGuid; + + if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) + { + recv_data.rfinish(); // Prevent additional spam at rejected packet + return; + } + + Guild* guild = _GetPlayerGuild(this); + if (!guild) + { + recv_data.rfinish(); // Prevent additional spam at rejected packet + return; + } + + uint8 bankToBank; + recv_data >> bankToBank; + + uint8 tabId; + uint8 slotId; + uint32 itemEntry; + uint32 splitedAmount = 0; + + if (bankToBank) + { + uint8 destTabId; + recv_data >> destTabId; + + uint8 destSlotId; + recv_data >> destSlotId; + recv_data.read_skip(); // Always 0 + + recv_data >> tabId; + recv_data >> slotId; + recv_data >> itemEntry; + recv_data.read_skip(); // Always 0 + + recv_data >> splitedAmount; + + guild->SwapItems(GetPlayer(), tabId, slotId, destTabId, destSlotId, splitedAmount); + } + else + { + uint8 playerBag = NULL_BAG; + uint8 playerSlotId = NULL_SLOT; + uint8 toChar = 1; + + recv_data >> tabId; + recv_data >> slotId; + recv_data >> itemEntry; + + uint8 autoStore; + recv_data >> autoStore; + if (autoStore) + { + recv_data.read_skip(); // autoStoreCount + recv_data.read_skip(); // ToChar (?), always and expected to be 1 (autostore only triggered in Bank -> Char) + recv_data.read_skip(); // Always 0 + } + else + { + recv_data >> playerBag; + recv_data >> playerSlotId; + recv_data >> toChar; + recv_data >> splitedAmount; + } + + // Player <-> Bank + // Allow to work with inventory only + if (!Player::IsInventoryPos(playerBag, playerSlotId) && !(playerBag == NULL_BAG && playerSlotId == NULL_SLOT)) + GetPlayer()->SendEquipError(EQUIP_ERR_NONE, NULL); + else + guild->SwapItemsWithInventory(GetPlayer(), toChar, tabId, slotId, playerBag, playerSlotId, splitedAmount); + } +} + +void WorldSession::HandleGuildBankBuyTab(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (CMSG_GUILD_BANK_BUY_TAB)"); + + uint64 GoGuid; + recv_data >> GoGuid; + + uint8 tabId; + recv_data >> tabId; + + if (GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) + if (Guild* guild = _GetPlayerGuild(this)) + guild->HandleBuyBankTab(this, tabId); +} + +void WorldSession::HandleGuildBankUpdateTab(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (CMSG_GUILD_BANK_UPDATE_TAB)"); + + uint64 GoGuid; + recv_data >> GoGuid; + + uint8 tabId; + recv_data >> tabId; + + std::string name; + recv_data >> name; + + std::string icon; + recv_data >> icon; + + if (!name.empty() && !icon.empty()) + if (GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) + if (Guild* guild = _GetPlayerGuild(this)) + guild->HandleSetBankTabInfo(this, tabId, name, icon); +} + +void WorldSession::HandleGuildBankLogQuery(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (MSG_GUILD_BANK_LOG_QUERY)"); + + uint8 tabId; + recv_data >> tabId; + + if (Guild* guild = _GetPlayerGuild(this)) + guild->SendBankLog(this, tabId); +} + +void WorldSession::HandleQueryGuildBankTabText(WorldPacket &recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received MSG_QUERY_GUILD_BANK_TEXT"); + + uint8 tabId; + recv_data >> tabId; + + if (Guild* guild = _GetPlayerGuild(this)) + guild->SendBankTabText(this, tabId); +} + +void WorldSession::HandleSetGuildBankTabText(WorldPacket &recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_SET_GUILD_BANK_TEXT"); + + uint8 tabId; + recv_data >> tabId; + + std::string text; + recv_data >> text; + + if (Guild* guild = _GetPlayerGuild(this)) + guild->SetBankTabText(tabId, text); +} diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp new file mode 100755 index 00000000000..47700fd088a --- /dev/null +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -0,0 +1,1432 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Opcodes.h" +#include "Log.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "Item.h" +#include "UpdateData.h" +#include "ObjectAccessor.h" +#include "SpellInfo.h" + +void WorldSession::HandleSplitItemOpcode(WorldPacket & recv_data) +{ + //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_SPLIT_ITEM"); + uint8 srcbag, srcslot, dstbag, dstslot; + uint32 count; + + recv_data >> srcbag >> srcslot >> dstbag >> dstslot >> count; + //sLog->outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u, dstslot = %u, count = %u", srcbag, srcslot, dstbag, dstslot, count); + + uint16 src = ((srcbag << 8) | srcslot); + uint16 dst = ((dstbag << 8) | dstslot); + + if (src == dst) + return; + + if (count == 0) + return; //check count - if zero it's fake packet + + if (!_player->IsValidPos(srcbag, srcslot, true)) + { + _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; + } + + if (!_player->IsValidPos(dstbag, dstslot, false)) // can be autostore pos + { + _player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); + return; + } + + _player->SplitItem(src, dst, count); +} + +void WorldSession::HandleSwapInvItemOpcode(WorldPacket & recv_data) +{ + //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_SWAP_INV_ITEM"); + uint8 srcslot, dstslot; + + recv_data >> dstslot >> srcslot; + //sLog->outDebug("STORAGE: receive srcslot = %u, dstslot = %u", srcslot, dstslot); + + // prevent attempt swap same item to current position generated by client at special checting sequence + if (srcslot == dstslot) + return; + + if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0, srcslot, true)) + { + _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; + } + + if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0, dstslot, true)) + { + _player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); + return; + } + + uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | srcslot); + uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | dstslot); + + _player->SwapItem(src, dst); +} + +void WorldSession::HandleAutoEquipItemSlotOpcode(WorldPacket & recv_data) +{ + uint64 itemguid; + uint8 dstslot; + recv_data >> itemguid >> dstslot; + + // cheating attempt, client should never send opcode in that case + if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, dstslot)) + return; + + Item* item = _player->GetItemByGuid(itemguid); + uint16 dstpos = dstslot | (INVENTORY_SLOT_BAG_0 << 8); + + if (!item || item->GetPos() == dstpos) + return; + + _player->SwapItem(item->GetPos(), dstpos); +} + +void WorldSession::HandleSwapItem(WorldPacket & recv_data) +{ + //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_SWAP_ITEM"); + uint8 dstbag, dstslot, srcbag, srcslot; + + recv_data >> dstbag >> dstslot >> srcbag >> srcslot ; + //sLog->outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u, dstslot = %u", srcbag, srcslot, dstbag, dstslot); + + uint16 src = ((srcbag << 8) | srcslot); + uint16 dst = ((dstbag << 8) | dstslot); + + // prevent attempt swap same item to current position generated by client at special checting sequence + if (src == dst) + return; + + if (!_player->IsValidPos(srcbag, srcslot, true)) + { + _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; + } + + if (!_player->IsValidPos(dstbag, dstslot, true)) + { + _player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); + return; + } + + _player->SwapItem(src, dst); +} + +void WorldSession::HandleAutoEquipItemOpcode(WorldPacket & recv_data) +{ + //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_AUTOEQUIP_ITEM"); + uint8 srcbag, srcslot; + + recv_data >> srcbag >> srcslot; + //sLog->outDebug("STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot); + + Item* pSrcItem = _player->GetItemByPos(srcbag, srcslot); + if (!pSrcItem) + return; // only at cheat + + uint16 dest; + InventoryResult msg = _player->CanEquipItem(NULL_SLOT, dest, pSrcItem, !pSrcItem->IsBag()); + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, pSrcItem, NULL); + return; + } + + uint16 src = pSrcItem->GetPos(); + if (dest == src) // prevent equip in same slot, only at cheat + return; + + Item* pDstItem = _player->GetItemByPos(dest); + if (!pDstItem) // empty slot, simple case + { + _player->RemoveItem(srcbag, srcslot, true); + _player->EquipItem(dest, pSrcItem, true); + _player->AutoUnequipOffhandIfNeed(); + } + else // have currently equipped item, not simple case + { + uint8 dstbag = pDstItem->GetBagSlot(); + uint8 dstslot = pDstItem->GetSlot(); + + msg = _player->CanUnequipItem(dest, !pSrcItem->IsBag()); + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, pDstItem, NULL); + return; + } + + // check dest->src move possibility + ItemPosCountVec sSrc; + uint16 eSrc = 0; + if (_player->IsInventoryPos(src)) + { + msg = _player->CanStoreItem(srcbag, srcslot, sSrc, pDstItem, true); + if (msg != EQUIP_ERR_OK) + msg = _player->CanStoreItem(srcbag, NULL_SLOT, sSrc, pDstItem, true); + if (msg != EQUIP_ERR_OK) + msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, sSrc, pDstItem, true); + } + else if (_player->IsBankPos(src)) + { + msg = _player->CanBankItem(srcbag, srcslot, sSrc, pDstItem, true); + if (msg != EQUIP_ERR_OK) + msg = _player->CanBankItem(srcbag, NULL_SLOT, sSrc, pDstItem, true); + if (msg != EQUIP_ERR_OK) + msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, sSrc, pDstItem, true); + } + else if (_player->IsEquipmentPos(src)) + { + msg = _player->CanEquipItem(srcslot, eSrc, pDstItem, true); + if (msg == EQUIP_ERR_OK) + msg = _player->CanUnequipItem(eSrc, true); + } + + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, pDstItem, pSrcItem); + return; + } + + // now do moves, remove... + _player->RemoveItem(dstbag, dstslot, false); + _player->RemoveItem(srcbag, srcslot, false); + + // add to dest + _player->EquipItem(dest, pSrcItem, true); + + // add to src + if (_player->IsInventoryPos(src)) + _player->StoreItem(sSrc, pDstItem, true); + else if (_player->IsBankPos(src)) + _player->BankItem(sSrc, pDstItem, true); + else if (_player->IsEquipmentPos(src)) + _player->EquipItem(eSrc, pDstItem, true); + + _player->AutoUnequipOffhandIfNeed(); + } +} + +void WorldSession::HandleDestroyItemOpcode(WorldPacket & recv_data) +{ + //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_DESTROYITEM"); + uint8 bag, slot, count, data1, data2, data3; + + recv_data >> bag >> slot >> count >> data1 >> data2 >> data3; + //sLog->outDebug("STORAGE: receive bag = %u, slot = %u, count = %u", bag, slot, count); + + uint16 pos = (bag << 8) | slot; + + // prevent drop unequipable items (in combat, for example) and non-empty bags + if (_player->IsEquipmentPos(pos) || _player->IsBagPos(pos)) + { + InventoryResult msg = _player->CanUnequipItem(pos, false); + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, _player->GetItemByPos(pos), NULL); + return; + } + } + + Item* pItem = _player->GetItemByPos(bag, slot); + if (!pItem) + { + _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; + } + + if (pItem->GetTemplate()->Flags & ITEM_PROTO_FLAG_INDESTRUCTIBLE) + { + _player->SendEquipError(EQUIP_ERR_CANT_DROP_SOULBOUND, NULL, NULL); + return; + } + + if (count) + { + uint32 i_count = count; + _player->DestroyItemCount(pItem, i_count, true); + } + else + _player->DestroyItem(bag, slot, true); +} + +// Only _static_ data send in this packet !!! +void WorldSession::HandleItemQuerySingleOpcode(WorldPacket & recv_data) +{ + //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_ITEM_QUERY_SINGLE"); + uint32 item; + recv_data >> item; + + sLog->outDetail("STORAGE: Item Query = %u", item); + + ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item); + if (pProto) + { + std::string Name = pProto->Name1; + std::string Description = pProto->Description; + + int loc_idx = GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + if (ItemLocale const* il = sObjectMgr->GetItemLocale(pProto->ItemId)) + { + ObjectMgr::GetLocaleString(il->Name, loc_idx, Name); + ObjectMgr::GetLocaleString(il->Description, loc_idx, Description); + } + } + // guess size + WorldPacket data(SMSG_ITEM_QUERY_SINGLE_RESPONSE, 600); + data << pProto->ItemId; + data << pProto->Class; + data << pProto->SubClass; + data << int32(pProto->Unk0); // new 2.0.3, not exist in wdb cache? + data << Name; + data << uint8(0x00); //pProto->Name2; // blizz not send name there, just uint8(0x00); <-- \0 = empty string = empty name... + data << uint8(0x00); //pProto->Name3; // blizz not send name there, just uint8(0x00); + data << uint8(0x00); //pProto->Name4; // blizz not send name there, just uint8(0x00); + data << pProto->DisplayInfoID; + data << pProto->Quality; + data << pProto->Flags; + data << pProto->Flags2; + data << pProto->BuyPrice; + data << pProto->SellPrice; + data << pProto->InventoryType; + data << pProto->AllowableClass; + data << pProto->AllowableRace; + data << pProto->ItemLevel; + data << pProto->RequiredLevel; + data << pProto->RequiredSkill; + data << pProto->RequiredSkillRank; + data << pProto->RequiredSpell; + data << pProto->RequiredHonorRank; + data << pProto->RequiredCityRank; + data << pProto->RequiredReputationFaction; + data << pProto->RequiredReputationRank; + data << int32(pProto->MaxCount); + data << int32(pProto->Stackable); + data << pProto->ContainerSlots; + data << pProto->StatsCount; // item stats count + for (uint32 i = 0; i < pProto->StatsCount; ++i) + { + data << pProto->ItemStat[i].ItemStatType; + data << pProto->ItemStat[i].ItemStatValue; + } + data << pProto->ScalingStatDistribution; // scaling stats distribution + data << pProto->ScalingStatValue; // some kind of flags used to determine stat values column + for (int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i) + { + data << pProto->Damage[i].DamageMin; + data << pProto->Damage[i].DamageMax; + data << pProto->Damage[i].DamageType; + } + + // resistances (7) + data << pProto->Armor; + data << pProto->HolyRes; + data << pProto->FireRes; + data << pProto->NatureRes; + data << pProto->FrostRes; + data << pProto->ShadowRes; + data << pProto->ArcaneRes; + + data << pProto->Delay; + data << pProto->AmmoType; + data << pProto->RangedModRange; + + for (int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s) + { + // send DBC data for cooldowns in same way as it used in Spell::SendSpellCooldown + // use `item_template` or if not set then only use spell cooldowns + SpellInfo const* spell = sSpellMgr->GetSpellInfo(pProto->Spells[s].SpellId); + if (spell) + { + bool db_data = pProto->Spells[s].SpellCooldown >= 0 || pProto->Spells[s].SpellCategoryCooldown >= 0; + + data << pProto->Spells[s].SpellId; + data << pProto->Spells[s].SpellTrigger; + data << uint32(-abs(pProto->Spells[s].SpellCharges)); + + if (db_data) + { + data << uint32(pProto->Spells[s].SpellCooldown); + data << uint32(pProto->Spells[s].SpellCategory); + data << uint32(pProto->Spells[s].SpellCategoryCooldown); + } + else + { + data << uint32(spell->RecoveryTime); + data << uint32(spell->Category); + data << uint32(spell->CategoryRecoveryTime); + } + } + else + { + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(-1); + data << uint32(0); + data << uint32(-1); + } + } + data << pProto->Bonding; + data << Description; + data << pProto->PageText; + data << pProto->LanguageID; + data << pProto->PageMaterial; + data << pProto->StartQuest; + data << pProto->LockID; + data << int32(pProto->Material); + data << pProto->Sheath; + data << pProto->RandomProperty; + data << pProto->RandomSuffix; + data << pProto->Block; + data << pProto->ItemSet; + data << pProto->MaxDurability; + data << pProto->Area; + data << pProto->Map; // Added in 1.12.x & 2.0.1 client branch + data << pProto->BagFamily; + data << pProto->TotemCategory; + for (int s = 0; s < MAX_ITEM_PROTO_SOCKETS; ++s) + { + data << pProto->Socket[s].Color; + data << pProto->Socket[s].Content; + } + data << pProto->socketBonus; + data << pProto->GemProperties; + data << pProto->RequiredDisenchantSkill; + data << pProto->ArmorDamageModifier; + data << uint32(abs(pProto->Duration)); // added in 2.4.2.8209, duration (seconds) + data << pProto->ItemLimitCategory; // WotLK, ItemLimitCategory + data << pProto->HolidayId; // Holiday.dbc? + SendPacket(&data); + } + else + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_ITEM_QUERY_SINGLE - NO item INFO! (ENTRY: %u)", item); + WorldPacket data(SMSG_ITEM_QUERY_SINGLE_RESPONSE, 4); + data << uint32(item | 0x80000000); + SendPacket(&data); + } +} + +void WorldSession::HandleReadItem(WorldPacket & recv_data) +{ + //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_READ_ITEM"); + + uint8 bag, slot; + recv_data >> bag >> slot; + + //sLog->outDetail("STORAGE: Read bag = %u, slot = %u", bag, slot); + Item* pItem = _player->GetItemByPos(bag, slot); + + if (pItem && pItem->GetTemplate()->PageText) + { + WorldPacket data; + + InventoryResult msg = _player->CanUseItem(pItem); + if (msg == EQUIP_ERR_OK) + { + data.Initialize (SMSG_READ_ITEM_OK, 8); + sLog->outDetail("STORAGE: Item page sent"); + } + else + { + data.Initialize(SMSG_READ_ITEM_FAILED, 8); + sLog->outDetail("STORAGE: Unable to read item"); + _player->SendEquipError(msg, pItem, NULL); + } + data << pItem->GetGUID(); + SendPacket(&data); + } + else + _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); +} + +void WorldSession::HandlePageQuerySkippedOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_PAGE_TEXT_QUERY"); + + uint32 itemid; + uint64 guid; + + recv_data >> itemid >> guid; + + sLog->outDetail("Packet Info: itemid: %u guidlow: %u guidentry: %u guidhigh: %u", + itemid, GUID_LOPART(guid), GUID_ENPART(guid), GUID_HIPART(guid)); +} + +void WorldSession::HandleSellItemOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_SELL_ITEM"); + uint64 vendorguid, itemguid; + uint32 count; + + recv_data >> vendorguid >> itemguid >> count; + + if (!itemguid) + return; + + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR); + if (!creature) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleSellItemOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorguid))); + _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, itemguid, 0); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + Item* pItem = _player->GetItemByGuid(itemguid); + if (pItem) + { + // prevent sell not owner item + if (_player->GetGUID() != pItem->GetOwnerGUID()) + { + _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0); + return; + } + + // prevent sell non empty bag by drag-and-drop at vendor's item list + if (pItem->IsNotEmptyBag()) + { + _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0); + return; + } + + // prevent sell currently looted item + if (_player->GetLootGUID() == pItem->GetGUID()) + { + _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0); + return; + } + + // prevent selling item for sellprice when the item is still refundable + // this probably happens when right clicking a refundable item, the client sends both + // CMSG_SELL_ITEM and CMSG_REFUND_ITEM (unverified) + if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE)) + return; // Therefore, no feedback to client + + // special case at auto sell (sell all) + if (count == 0) + { + count = pItem->GetCount(); + } + else + { + // prevent sell more items that exist in stack (possible only not from client) + if (count > pItem->GetCount()) + { + _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0); + return; + } + } + + ItemTemplate const* pProto = pItem->GetTemplate(); + if (pProto) + { + if (pProto->SellPrice > 0) + { + if (count < pItem->GetCount()) // need split items + { + Item* pNewItem = pItem->CloneItem(count, _player); + if (!pNewItem) + { + sLog->outError("WORLD: HandleSellItemOpcode - could not create clone of item %u; count = %u", pItem->GetEntry(), count); + _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0); + return; + } + + pItem->SetCount(pItem->GetCount() - count); + _player->ItemRemovedQuestCheck(pItem->GetEntry(), count); + if (_player->IsInWorld()) + pItem->SendUpdateToPlayer(_player); + pItem->SetState(ITEM_CHANGED, _player); + + _player->AddItemToBuyBackSlot(pNewItem); + if (_player->IsInWorld()) + pNewItem->SendUpdateToPlayer(_player); + } + else + { + _player->ItemRemovedQuestCheck(pItem->GetEntry(), pItem->GetCount()); + _player->RemoveItem(pItem->GetBagSlot(), pItem->GetSlot(), true); + pItem->RemoveFromUpdateQueueOf(_player); + _player->AddItemToBuyBackSlot(pItem); + } + + uint32 money = pProto->SellPrice * count; + _player->ModifyMoney(money); + _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS, money); + } + else + _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0); + return; + } + } + _player->SendSellError(SELL_ERR_CANT_FIND_ITEM, creature, itemguid, 0); + return; +} + +void WorldSession::HandleBuybackItem(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_BUYBACK_ITEM"); + uint64 vendorguid; + uint32 slot; + + recv_data >> vendorguid >> slot; + + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR); + if (!creature) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleBuybackItem - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorguid))); + _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + Item* pItem = _player->GetItemFromBuyBackSlot(slot); + if (pItem) + { + uint32 price = _player->GetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + slot - BUYBACK_SLOT_START); + if (!_player->HasEnoughMoney(price)) + { + _player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, creature, pItem->GetEntry(), 0); + return; + } + + ItemPosCountVec dest; + InventoryResult msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, pItem, false); + if (msg == EQUIP_ERR_OK) + { + _player->ModifyMoney(-(int32)price); + _player->RemoveItemFromBuyBackSlot(slot, false); + _player->ItemAddedQuestCheck(pItem->GetEntry(), pItem->GetCount()); + _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM, pItem->GetEntry(), pItem->GetCount()); + _player->StoreItem(dest, pItem, true); + } + else + _player->SendEquipError(msg, pItem, NULL); + return; + } + else + _player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, 0, 0); +} + +void WorldSession::HandleBuyItemInSlotOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_BUY_ITEM_IN_SLOT"); + uint64 vendorguid, bagguid; + uint32 item, slot, count; + uint8 bagslot; + + recv_data >> vendorguid >> item >> slot >> bagguid >> bagslot >> count; + + // client expects count starting at 1, and we send vendorslot+1 to client already + if (slot > 0) + --slot; + else + return; // cheating + + uint8 bag = NULL_BAG; // init for case invalid bagGUID + + // find bag slot by bag guid + if (bagguid == _player->GetGUID()) + bag = INVENTORY_SLOT_BAG_0; + else + { + for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) + { + if (Bag* pBag = _player->GetBagByPos(i)) + { + if (bagguid == pBag->GetGUID()) + { + bag = i; + break; + } + } + } + } + + // bag not found, cheating? + if (bag == NULL_BAG) + return; + + GetPlayer()->BuyItemFromVendorSlot(vendorguid, slot, item, count, bag, bagslot); +} + +void WorldSession::HandleBuyItemOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_BUY_ITEM"); + uint64 vendorguid; + uint32 item, slot, count; + uint8 unk1; + + recv_data >> vendorguid >> item >> slot >> count >> unk1; + + // client expects count starting at 1, and we send vendorslot+1 to client already + if (slot > 0) + --slot; + else + return; // cheating + + GetPlayer()->BuyItemFromVendorSlot(vendorguid, slot, item, count, NULL_BAG, NULL_SLOT); +} + +void WorldSession::HandleListInventoryOpcode(WorldPacket & recv_data) +{ + uint64 guid; + + recv_data >> guid; + + if (!GetPlayer()->isAlive()) + return; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_LIST_INVENTORY"); + + SendListInventory(guid); +} + +void WorldSession::SendListInventory(uint64 vendorGuid) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_LIST_INVENTORY"); + + Creature* vendor = GetPlayer()->GetNPCIfCanInteractWith(vendorGuid, UNIT_NPC_FLAG_VENDOR); + if (!vendor) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: SendListInventory - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorGuid))); + _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + // Stop the npc if moving + if (vendor->HasUnitState(UNIT_STAT_MOVING)) + vendor->StopMoving(); + + VendorItemData const* items = vendor->GetVendorItems(); + if (!items) + { + WorldPacket data(SMSG_LIST_INVENTORY, 8 + 1 + 1); + data << uint64(vendorGuid); + data << uint8(0); // count == 0, next will be error code + data << uint8(0); // "Vendor has no inventory" + SendPacket(&data); + return; + } + + uint8 itemCount = items->GetItemCount(); + uint8 count = 0; + + WorldPacket data(SMSG_LIST_INVENTORY, 8 + 1 + itemCount * 8 * 4); + data << uint64(vendorGuid); + + size_t countPos = data.wpos(); + data << uint8(count); + + float discountMod = _player->GetReputationPriceDiscount(vendor); + + for (uint8 slot = 0; slot < itemCount; ++slot) + { + if (VendorItem const* item = items->GetItem(slot)) + { + if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(item->item)) + { + if (!(itemTemplate->AllowableClass & _player->getClassMask()) && itemTemplate->Bonding == BIND_WHEN_PICKED_UP && !_player->isGameMaster()) + continue; + // Only display items in vendor lists for the team the + // player is on. If GM on, display all items. + if (!_player->isGameMaster() && ((itemTemplate->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY && _player->GetTeam() == ALLIANCE) || (itemTemplate->Flags2 == ITEM_FLAGS_EXTRA_ALLIANCE_ONLY && _player->GetTeam() == HORDE))) + continue; + + // Items sold out are not displayed in list + uint32 leftInStock = !item->maxcount ? 0xFFFFFFFF : vendor->GetVendorItemCurrentCount(item); + if (!_player->isGameMaster() && !leftInStock) + continue; + + ++count; + + // reputation discount + int32 price = item->IsGoldRequired(itemTemplate) ? uint32(floor(itemTemplate->BuyPrice * discountMod)) : 0; + + data << uint32(slot + 1); // client expects counting to start at 1 + data << uint32(item->item); + data << uint32(itemTemplate->DisplayInfoID); + data << int32(leftInStock); + data << uint32(price); + data << uint32(itemTemplate->MaxDurability); + data << uint32(itemTemplate->BuyCount); + data << uint32(item->ExtendedCost); + } + } + } + + if (count == 0) + { + data << uint8(0); + SendPacket(&data); + return; + } + + data.put(countPos, count); + SendPacket(&data); +} + +void WorldSession::HandleAutoStoreBagItemOpcode(WorldPacket & recv_data) +{ + //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_AUTOSTORE_BAG_ITEM"); + uint8 srcbag, srcslot, dstbag; + + recv_data >> srcbag >> srcslot >> dstbag; + //sLog->outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u", srcbag, srcslot, dstbag); + + Item* pItem = _player->GetItemByPos(srcbag, srcslot); + if (!pItem) + return; + + if (!_player->IsValidPos(dstbag, NULL_SLOT, false)) // can be autostore pos + { + _player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); + return; + } + + uint16 src = pItem->GetPos(); + + // check unequip potability for equipped items and bank bags + if (_player->IsEquipmentPos (src) || _player->IsBagPos (src)) + { + InventoryResult msg = _player->CanUnequipItem(src, !_player->IsBagPos (src)); + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, pItem, NULL); + return; + } + } + + ItemPosCountVec dest; + InventoryResult msg = _player->CanStoreItem(dstbag, NULL_SLOT, dest, pItem, false); + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, pItem, NULL); + return; + } + + // no-op: placed in same slot + if (dest.size() == 1 && dest[0].pos == src) + { + // just remove grey item state + _player->SendEquipError(EQUIP_ERR_NONE, pItem, NULL); + return; + } + + _player->RemoveItem(srcbag, srcslot, true); + _player->StoreItem(dest, pItem, true); +} + +void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_BUY_BANK_SLOT"); + + uint64 guid; + recvPacket >> guid; + + // cheating protection + /* not critical if "cheated", and check skip allow by slots in bank windows open by .bank command. + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_BANKER); + if (!creature) + { + sLog->outDebug("WORLD: HandleBuyBankSlotOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + return; + } + */ + + uint32 slot = _player->GetBankBagSlotCount(); + + // next slot + ++slot; + + sLog->outDetail("PLAYER: Buy bank bag slot, slot number = %u", slot); + + BankBagSlotPricesEntry const* slotEntry = sBankBagSlotPricesStore.LookupEntry(slot); + + WorldPacket data(SMSG_BUY_BANK_SLOT_RESULT, 4); + + if (!slotEntry) + { + data << uint32(ERR_BANKSLOT_FAILED_TOO_MANY); + SendPacket(&data); + return; + } + + uint32 price = slotEntry->price; + + if (!_player->HasEnoughMoney(price)) + { + data << uint32(ERR_BANKSLOT_INSUFFICIENT_FUNDS); + SendPacket(&data); + return; + } + + _player->SetBankBagSlotCount(slot); + _player->ModifyMoney(-int32(price)); + + data << uint32(ERR_BANKSLOT_OK); + SendPacket(&data); + + _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT); +} + +void WorldSession::HandleAutoBankItemOpcode(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AUTOBANK_ITEM"); + uint8 srcbag, srcslot; + + recvPacket >> srcbag >> srcslot; + sLog->outDebug(LOG_FILTER_NETWORKIO, "STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot); + + Item* pItem = _player->GetItemByPos(srcbag, srcslot); + if (!pItem) + return; + + ItemPosCountVec dest; + InventoryResult msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, dest, pItem, false); + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, pItem, NULL); + return; + } + + if (dest.size() == 1 && dest[0].pos == pItem->GetPos()) + { + _player->SendEquipError(EQUIP_ERR_NONE, pItem, NULL); + return; + } + + _player->RemoveItem(srcbag, srcslot, true); + _player->ItemRemovedQuestCheck(pItem->GetEntry(), pItem->GetCount()); + _player->BankItem(dest, pItem, true); +} + +void WorldSession::HandleAutoStoreBankItemOpcode(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AUTOSTORE_BANK_ITEM"); + uint8 srcbag, srcslot; + + recvPacket >> srcbag >> srcslot; + sLog->outDebug(LOG_FILTER_NETWORKIO, "STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot); + + Item* pItem = _player->GetItemByPos(srcbag, srcslot); + if (!pItem) + return; + + if (_player->IsBankPos(srcbag, srcslot)) // moving from bank to inventory + { + ItemPosCountVec dest; + InventoryResult msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, pItem, false); + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, pItem, NULL); + return; + } + + _player->RemoveItem(srcbag, srcslot, true); + _player->StoreItem(dest, pItem, true); + _player->ItemAddedQuestCheck(pItem->GetEntry(), pItem->GetCount()); + } + else // moving from inventory to bank + { + ItemPosCountVec dest; + InventoryResult msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, dest, pItem, false); + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, pItem, NULL); + return; + } + + _player->RemoveItem(srcbag, srcslot, true); + _player->BankItem(dest, pItem, true); + } +} + +void WorldSession::HandleSetAmmoOpcode(WorldPacket & recv_data) +{ + if (!GetPlayer()->isAlive()) + { + GetPlayer()->SendEquipError(EQUIP_ERR_YOU_ARE_DEAD, NULL, NULL); + return; + } + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_SET_AMMO"); + uint32 item; + + recv_data >> item; + + if (!item) + GetPlayer()->RemoveAmmo(); + else + GetPlayer()->SetAmmo(item); +} + +void WorldSession::SendEnchantmentLog(uint64 Target, uint64 Caster, uint32 ItemID, uint32 SpellID) +{ + WorldPacket data(SMSG_ENCHANTMENTLOG, (8+8+4+4+1)); // last check 2.0.10 + data << uint64(Target); + data << uint64(Caster); + data << uint32(ItemID); + data << uint32(SpellID); + data << uint8(0); + SendPacket(&data); +} + +void WorldSession::SendItemEnchantTimeUpdate(uint64 Playerguid, uint64 Itemguid, uint32 slot, uint32 Duration) +{ + // last check 2.0.10 + WorldPacket data(SMSG_ITEM_ENCHANT_TIME_UPDATE, (8+4+4+8)); + data << uint64(Itemguid); + data << uint32(slot); + data << uint32(Duration); + data << uint64(Playerguid); + SendPacket(&data); +} + +void WorldSession::HandleItemNameQueryOpcode(WorldPacket & recv_data) +{ + uint32 itemid; + recv_data >> itemid; + recv_data.read_skip(); // guid + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_ITEM_NAME_QUERY %u", itemid); + ItemSetNameEntry const* pName = sObjectMgr->GetItemSetNameEntry(itemid); + if (pName) + { + std::string Name = pName->name; + int loc_idx = GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + if (ItemSetNameLocale const* isnl = sObjectMgr->GetItemSetNameLocale(itemid)) + ObjectMgr::GetLocaleString(isnl->Name, loc_idx, Name); + + WorldPacket data(SMSG_ITEM_NAME_QUERY_RESPONSE, (4+Name.size()+1+4)); + data << uint32(itemid); + data << Name; + data << uint32(pName->InventoryType); + SendPacket(&data); + } +} + +void WorldSession::HandleWrapItemOpcode(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode CMSG_WRAP_ITEM"); + + uint8 gift_bag, gift_slot, item_bag, item_slot; + + recv_data >> gift_bag >> gift_slot; // paper + recv_data >> item_bag >> item_slot; // item + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WRAP: receive gift_bag = %u, gift_slot = %u, item_bag = %u, item_slot = %u", gift_bag, gift_slot, item_bag, item_slot); + + Item* gift = _player->GetItemByPos(gift_bag, gift_slot); + if (!gift) + { + _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL); + return; + } + + if (!(gift->GetTemplate()->Flags & ITEM_PROTO_FLAG_WRAPPER)) // cheating: non-wrapper wrapper + { + _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL); + return; + } + + Item* item = _player->GetItemByPos(item_bag, item_slot); + + if (!item) + { + _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, item, NULL); + return; + } + + if (item == gift) // not possable with pacjket from real client + { + _player->SendEquipError(EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL); + return; + } + + if (item->IsEquipped()) + { + _player->SendEquipError(EQUIP_ERR_EQUIPPED_CANT_BE_WRAPPED, item, NULL); + return; + } + + if (item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR)) // HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED); + { + _player->SendEquipError(EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL); + return; + } + + if (item->IsBag()) + { + _player->SendEquipError(EQUIP_ERR_BAGS_CANT_BE_WRAPPED, item, NULL); + return; + } + + if (item->IsSoulBound()) + { + _player->SendEquipError(EQUIP_ERR_BOUND_CANT_BE_WRAPPED, item, NULL); + return; + } + + if (item->GetMaxStackCount() != 1) + { + _player->SendEquipError(EQUIP_ERR_STACKABLE_CANT_BE_WRAPPED, item, NULL); + return; + } + + // maybe not correct check (it is better than nothing) + if (item->GetTemplate()->MaxCount>0) + { + _player->SendEquipError(EQUIP_ERR_UNIQUE_CANT_BE_WRAPPED, item, NULL); + return; + } + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + trans->PAppend("INSERT INTO character_gifts VALUES ('%u', '%u', '%u', '%u')", GUID_LOPART(item->GetOwnerGUID()), item->GetGUIDLow(), item->GetEntry(), item->GetUInt32Value(ITEM_FIELD_FLAGS)); + item->SetEntry(gift->GetEntry()); + + switch (item->GetEntry()) + { + case 5042: item->SetEntry(5043); break; + case 5048: item->SetEntry(5044); break; + case 17303: item->SetEntry(17302); break; + case 17304: item->SetEntry(17305); break; + case 17307: item->SetEntry(17308); break; + case 21830: item->SetEntry(21831); break; + } + item->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, _player->GetGUID()); + item->SetUInt32Value(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED); + item->SetState(ITEM_CHANGED, _player); + + if (item->GetState() == ITEM_NEW) // save new item, to have alway for `character_gifts` record in `item_instance` + { + // after save it will be impossible to remove the item from the queue + item->RemoveFromUpdateQueueOf(_player); + item->SaveToDB(trans); // item gave inventory record unchanged and can be save standalone + } + CharacterDatabase.CommitTransaction(trans); + + uint32 count = 1; + _player->DestroyItemCount(gift, count, true); +} + +void WorldSession::HandleSocketOpcode(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_SOCKET_GEMS"); + + uint64 item_guid; + uint64 gem_guids[MAX_GEM_SOCKETS]; + + recv_data >> item_guid; + if (!item_guid) + return; + + for (int i = 0; i < MAX_GEM_SOCKETS; ++i) + recv_data >> gem_guids[i]; + + //cheat -> tried to socket same gem multiple times + if ((gem_guids[0] && (gem_guids[0] == gem_guids[1] || gem_guids[0] == gem_guids[2])) || + (gem_guids[1] && (gem_guids[1] == gem_guids[2]))) + return; + + Item* itemTarget = _player->GetItemByGuid(item_guid); + if (!itemTarget) //missing item to socket + return; + + ItemTemplate const* itemProto = itemTarget->GetTemplate(); + if (!itemProto) + return; + + //this slot is excepted when applying / removing meta gem bonus + uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : uint8(NULL_SLOT); + + Item* Gems[MAX_GEM_SOCKETS]; + for (int i = 0; i < MAX_GEM_SOCKETS; ++i) + Gems[i] = gem_guids[i] ? _player->GetItemByGuid(gem_guids[i]) : NULL; + + GemPropertiesEntry const* GemProps[MAX_GEM_SOCKETS]; + for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //get geminfo from dbc storage + GemProps[i] = (Gems[i]) ? sGemPropertiesStore.LookupEntry(Gems[i]->GetTemplate()->GemProperties) : NULL; + + for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //check for hack maybe + { + if (!GemProps[i]) + continue; + + // tried to put gem in socket where no socket exists (take care about prismatic sockets) + if (!itemProto->Socket[i].Color) + { + // no prismatic socket + if (!itemTarget->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT)) + return; + + // not first not-colored (not normaly used) socket + if (i != 0 && !itemProto->Socket[i-1].Color && (i+1 >= MAX_GEM_SOCKETS || itemProto->Socket[i+1].Color)) + return; + + // ok, this is first not colored socket for item with prismatic socket + } + + // tried to put normal gem in meta socket + if (itemProto->Socket[i].Color == SOCKET_COLOR_META && GemProps[i]->color != SOCKET_COLOR_META) + return; + + // tried to put meta gem in normal socket + if (itemProto->Socket[i].Color != SOCKET_COLOR_META && GemProps[i]->color == SOCKET_COLOR_META) + return; + } + + uint32 GemEnchants[MAX_GEM_SOCKETS]; + uint32 OldEnchants[MAX_GEM_SOCKETS]; + for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //get new and old enchantments + { + GemEnchants[i] = (GemProps[i]) ? GemProps[i]->spellitemenchantement : 0; + OldEnchants[i] = itemTarget->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i)); + } + + // check unique-equipped conditions + for (int i = 0; i < MAX_GEM_SOCKETS; ++i) + { + if (!Gems[i]) + continue; + + // continue check for case when attempt add 2 similar unique equipped gems in one item. + ItemTemplate const* iGemProto = Gems[i]->GetTemplate(); + + // unique item (for new and already placed bit removed enchantments + if (iGemProto->Flags & ITEM_PROTO_FLAG_UNIQUE_EQUIPPED) + { + for (int j = 0; j < MAX_GEM_SOCKETS; ++j) + { + if (i == j) // skip self + continue; + + if (Gems[j]) + { + if (iGemProto->ItemId == Gems[j]->GetEntry()) + { + _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); + return; + } + } + else if (OldEnchants[j]) + { + if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j])) + { + if (iGemProto->ItemId == enchantEntry->GemID) + { + _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); + return; + } + } + } + + } + } + + // unique limit type item + int32 limit_newcount = 0; + if (iGemProto->ItemLimitCategory) + { + if (ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(iGemProto->ItemLimitCategory)) + { + // NOTE: limitEntry->mode is not checked because if item has limit then it is applied in equip case + for (int j = 0; j < MAX_GEM_SOCKETS; ++j) + { + if (Gems[j]) + { + // new gem + if (iGemProto->ItemLimitCategory == Gems[j]->GetTemplate()->ItemLimitCategory) + ++limit_newcount; + } + else if (OldEnchants[j]) + { + // existing gem + if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j])) + if (ItemTemplate const* jProto = sObjectMgr->GetItemTemplate(enchantEntry->GemID)) + if (iGemProto->ItemLimitCategory == jProto->ItemLimitCategory) + ++limit_newcount; + } + } + + if (limit_newcount > 0 && uint32(limit_newcount) > limitEntry->maxCount) + { + _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); + return; + } + } + } + + // for equipped item check all equipment for duplicate equipped gems + if (itemTarget->IsEquipped()) + { + if (InventoryResult res = _player->CanEquipUniqueItem(Gems[i], slot, std::max(limit_newcount, 0))) + { + _player->SendEquipError(res, itemTarget, NULL); + return; + } + } + } + + bool SocketBonusActivated = itemTarget->GemsFitSockets(); //save state of socketbonus + _player->ToggleMetaGemsActive(slot, false); //turn off all metagems (except for the target item) + + //if a meta gem is being equipped, all information has to be written to the item before testing if the conditions for the gem are met + + //remove ALL enchants + for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + MAX_GEM_SOCKETS; ++enchant_slot) + _player->ApplyEnchantment(itemTarget, EnchantmentSlot(enchant_slot), false); + + for (int i = 0; i < MAX_GEM_SOCKETS; ++i) + { + if (GemEnchants[i]) + { + itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i), GemEnchants[i], 0, 0); + if (Item* guidItem = _player->GetItemByGuid(gem_guids[i])) + _player->DestroyItem(guidItem->GetBagSlot(), guidItem->GetSlot(), true); + } + } + + for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot) + _player->ApplyEnchantment(itemTarget, EnchantmentSlot(enchant_slot), true); + + bool SocketBonusToBeActivated = itemTarget->GemsFitSockets();//current socketbonus state + if (SocketBonusActivated ^ SocketBonusToBeActivated) //if there was a change... + { + _player->ApplyEnchantment(itemTarget, BONUS_ENCHANTMENT_SLOT, false); + itemTarget->SetEnchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetTemplate()->socketBonus : 0), 0, 0); + _player->ApplyEnchantment(itemTarget, BONUS_ENCHANTMENT_SLOT, true); + //it is not displayed, client has an inbuilt system to determine if the bonus is activated + } + + _player->ToggleMetaGemsActive(slot, true); //turn on all metagems (except for target item) + + itemTarget->ClearSoulboundTradeable(_player); // clear tradeable flag +} + +void WorldSession::HandleCancelTempEnchantmentOpcode(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CANCEL_TEMP_ENCHANTMENT"); + + uint32 eslot; + + recv_data >> eslot; + + // apply only to equipped item + if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, eslot)) + return; + + Item* item = GetPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, eslot); + + if (!item) + return; + + if (!item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)) + return; + + GetPlayer()->ApplyEnchantment(item, TEMP_ENCHANTMENT_SLOT, false); + item->ClearEnchantment(TEMP_ENCHANTMENT_SLOT); +} + +void WorldSession::HandleItemRefundInfoRequest(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_ITEM_REFUND_INFO"); + + uint64 guid; + recv_data >> guid; // item guid + + Item* item = _player->GetItemByGuid(guid); + if (!item) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "Item refund: item not found!"); + return; + } + + GetPlayer()->SendRefundInfo(item); +} + +void WorldSession::HandleItemRefund(WorldPacket &recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_ITEM_REFUND"); + uint64 guid; + recv_data >> guid; // item guid + + Item* item = _player->GetItemByGuid(guid); + if (!item) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "Item refund: item not found!"); + return; + } + + GetPlayer()->RefundItem(item); +} + +/** + * Handles the packet sent by the client when requesting information about item text. + * + * This function is called when player clicks on item which has some flag set + */ +void WorldSession::HandleItemTextQuery(WorldPacket & recv_data ) +{ + uint64 itemGuid; + recv_data >> itemGuid; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_ITEM_TEXT_QUERY item guid: %u", GUID_LOPART(itemGuid)); + + WorldPacket data(SMSG_ITEM_TEXT_QUERY_RESPONSE, (4+10)); // guess size + + if (Item* item = _player->GetItemByGuid(itemGuid)) + { + data << uint8(0); // has text + data << uint64(itemGuid); // item guid + data << item->GetText(); + } + else + { + data << uint8(1); // no text + } + + SendPacket(&data); +} diff --git a/src/server/game/Handlers/LFGHandler.cpp b/src/server/game/Handlers/LFGHandler.cpp new file mode 100755 index 00000000000..3c6bd28b5cb --- /dev/null +++ b/src/server/game/Handlers/LFGHandler.cpp @@ -0,0 +1,664 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "WorldSession.h" +#include "WorldPacket.h" +#include "DBCStores.h" +#include "Player.h" +#include "Group.h" +#include "LFGMgr.h" +#include "ObjectMgr.h" +#include "GroupMgr.h" +#include "InstanceScript.h" + +void BuildPlayerLockDungeonBlock(WorldPacket& data, const LfgLockMap& lock) +{ + data << uint32(lock.size()); // Size of lock dungeons + for (LfgLockMap::const_iterator it = lock.begin(); it != lock.end(); ++it) + { + data << uint32(it->first); // Dungeon entry (id + type) + data << uint32(it->second); // Lock status + } +} + +void BuildPartyLockDungeonBlock(WorldPacket& data, const LfgLockPartyMap& lockMap) +{ + data << uint8(lockMap.size()); + for (LfgLockPartyMap::const_iterator it = lockMap.begin(); it != lockMap.end(); ++it) + { + data << uint64(it->first); // Player guid + BuildPlayerLockDungeonBlock(data, it->second); + } +} + +void WorldSession::HandleLfgJoinOpcode(WorldPacket& recv_data) +{ + if (!sWorld->getBoolConfig(CONFIG_DUNGEON_FINDER_ENABLE) || + (GetPlayer()->GetGroup() && GetPlayer()->GetGroup()->GetLeaderGUID() != GetPlayer()->GetGUID() && + (GetPlayer()->GetGroup()->GetMembersCount() == MAXGROUPSIZE || !GetPlayer()->GetGroup()->isLFGGroup()))) + { + recv_data.rfinish(); + return; + } + + uint8 numDungeons; + uint32 dungeon; + uint32 roles; + + recv_data >> roles; + recv_data.read_skip(); // uint8 (always 0) - uint8 (always 0) + recv_data >> numDungeons; + if (!numDungeons) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_JOIN [" UI64FMTD "] no dungeons selected", GetPlayer()->GetGUID()); + recv_data.rfinish(); + return; + } + + LfgDungeonSet newDungeons; + for (int8 i = 0 ; i < numDungeons; ++i) + { + recv_data >> dungeon; + newDungeons.insert((dungeon & 0x00FFFFFF)); // remove the type from the dungeon entry + } + + recv_data.read_skip(); // for 0..uint8 (always 3) { uint8 (always 0) } + + std::string comment; + recv_data >> comment; + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_JOIN [" UI64FMTD "] roles: %u, Dungeons: %u, Comment: %s", GetPlayer()->GetGUID(), roles, uint8(newDungeons.size()), comment.c_str()); + sLFGMgr->Join(GetPlayer(), uint8(roles), newDungeons, comment); +} + +void WorldSession::HandleLfgLeaveOpcode(WorldPacket& /*recv_data*/) +{ + Group* grp = GetPlayer()->GetGroup(); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_LEAVE [" UI64FMTD "] in group: %u", GetPlayer()->GetGUID(), grp ? 1 : 0); + + // Check cheating - only leader can leave the queue + if (!grp || grp->GetLeaderGUID() == GetPlayer()->GetGUID()) + sLFGMgr->Leave(GetPlayer(), grp); +} + +void WorldSession::HandleLfgProposalResultOpcode(WorldPacket& recv_data) +{ + uint32 lfgGroupID; // Internal lfgGroupID + bool accept; // Accept to join? + recv_data >> lfgGroupID; + recv_data >> accept; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_PROPOSAL_RESULT [" UI64FMTD "] proposal: %u accept: %u", GetPlayer()->GetGUID(), lfgGroupID, accept ? 1 : 0); + sLFGMgr->UpdateProposal(lfgGroupID, GetPlayer()->GetGUID(), accept); +} + +void WorldSession::HandleLfgSetRolesOpcode(WorldPacket& recv_data) +{ + uint8 roles; + recv_data >> roles; // Player Group Roles + uint64 guid = GetPlayer()->GetGUID(); + Group* grp = GetPlayer()->GetGroup(); + if (!grp) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_SET_ROLES [" UI64FMTD "] Not in group", guid); + return; + } + uint64 gguid = grp->GetGUID(); + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_SET_ROLES: Group [" UI64FMTD "], Player [" UI64FMTD "], Roles: %u", gguid, guid, roles); + sLFGMgr->UpdateRoleCheck(gguid, guid, roles); +} + +void WorldSession::HandleLfgSetCommentOpcode(WorldPacket& recv_data) +{ + std::string comment; + recv_data >> comment; + uint64 guid = GetPlayer()->GetGUID(); + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_SET_LFG_COMMENT [" UI64FMTD "] comment: %s", guid, comment.c_str()); + + sLFGMgr->SetComment(guid, comment); +} + +void WorldSession::HandleLfgSetBootVoteOpcode(WorldPacket& recv_data) +{ + bool agree; // Agree to kick player + recv_data >> agree; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_SET_BOOT_VOTE [" UI64FMTD "] agree: %u", GetPlayer()->GetGUID(), agree ? 1 : 0); + sLFGMgr->UpdateBoot(GetPlayer(), agree); +} + +void WorldSession::HandleLfgTeleportOpcode(WorldPacket& recv_data) +{ + bool out; + recv_data >> out; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_TELEPORT [" UI64FMTD "] out: %u", GetPlayer()->GetGUID(), out ? 1 : 0); + sLFGMgr->TeleportPlayer(GetPlayer(), out, true); +} + +void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& /*recv_data*/) +{ + uint64 guid = GetPlayer()->GetGUID(); + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFD_PLAYER_LOCK_INFO_REQUEST [" UI64FMTD "]", guid); + + // Get Random dungeons that can be done at a certain level and expansion + // FIXME - Should return seasonals (when not disabled) + LfgDungeonSet randomDungeons; + uint8 level = GetPlayer()->getLevel(); + uint8 expansion = GetPlayer()->GetSession()->Expansion(); + for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i) + { + LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(i); + if (dungeon && dungeon->type == LFG_TYPE_RANDOM && dungeon->expansion <= expansion && + dungeon->minlevel <= level && level <= dungeon->maxlevel) + randomDungeons.insert(dungeon->Entry()); + } + + // Get player locked Dungeons + LfgLockMap lock = sLFGMgr->GetLockedDungeons(guid); + uint32 rsize = uint32(randomDungeons.size()); + uint32 lsize = uint32(lock.size()); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_PLAYER_INFO [" UI64FMTD "]", guid); + WorldPacket data(SMSG_LFG_PLAYER_INFO, 1 + rsize * (4 + 1 + 4 + 4 + 4 + 4 + 1 + 4 + 4 + 4) + 4 + lsize * (1 + 4 + 4 + 4 + 4 + 1 + 4 + 4 + 4)); + + data << uint8(randomDungeons.size()); // Random Dungeon count + for (LfgDungeonSet::const_iterator it = randomDungeons.begin(); it != randomDungeons.end(); ++it) + { + data << uint32(*it); // Dungeon Entry (id + type) + LfgReward const* reward = sLFGMgr->GetRandomDungeonReward(*it, level); + Quest const* qRew = NULL; + uint8 done = 0; + if (reward) + { + qRew = sObjectMgr->GetQuestTemplate(reward->reward[0].questId); + if (qRew) + { + done = !GetPlayer()->CanRewardQuest(qRew, false); + if (done) + qRew = sObjectMgr->GetQuestTemplate(reward->reward[1].questId); + } + } + if (qRew) + { + data << uint8(done); + data << uint32(qRew->GetRewOrReqMoney()); + data << uint32(qRew->XPValue(GetPlayer())); + data << uint32(reward->reward[done].variableMoney); + data << uint32(reward->reward[done].variableXP); + data << uint8(qRew->GetRewItemsCount()); + if (qRew->GetRewItemsCount()) + { + ItemTemplate const* iProto = NULL; + for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i) + { + if (!qRew->RewardItemId[i]) + continue; + + iProto = sObjectMgr->GetItemTemplate(qRew->RewardItemId[i]); + + data << uint32(qRew->RewardItemId[i]); + data << uint32(iProto ? iProto->DisplayInfoID : 0); + data << uint32(qRew->RewardItemIdCount[i]); + } + } + } + else + { + data << uint8(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint8(0); + } + } + BuildPlayerLockDungeonBlock(data, lock); + SendPacket(&data); +} + +void WorldSession::HandleLfgPartyLockInfoRequestOpcode(WorldPacket& /*recv_data*/) +{ + uint64 guid = GetPlayer()->GetGUID(); + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFD_PARTY_LOCK_INFO_REQUEST [" UI64FMTD "]", guid); + + Group* grp = GetPlayer()->GetGroup(); + if (!grp) + return; + + // Get the locked dungeons of the other party members + LfgLockPartyMap lockMap; + for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* plrg = itr->getSource(); + if (!plrg) + continue; + + uint64 pguid = plrg->GetGUID(); + if (pguid == guid) + continue; + + lockMap[pguid] = sLFGMgr->GetLockedDungeons(pguid); + } + + uint32 size = 0; + for (LfgLockPartyMap::const_iterator it = lockMap.begin(); it != lockMap.end(); ++it) + size += 8 + 4 + uint32(it->second.size()) * (4 + 4); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_PARTY_INFO [" UI64FMTD "]", guid); + WorldPacket data(SMSG_LFG_PARTY_INFO, 1 + size); + BuildPartyLockDungeonBlock(data, lockMap); + SendPacket(&data); +} + +void WorldSession::HandleLfrSearchOpcode(WorldPacket& recv_data) +{ + uint32 entry; // Raid id to search + recv_data >> entry; + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_SEARCH_LFG_JOIN [" UI64FMTD "] dungeon entry: %u", GetPlayer()->GetGUID(), entry); + //SendLfrUpdateListOpcode(entry); +} + +void WorldSession::HandleLfrLeaveOpcode(WorldPacket& recv_data) +{ + uint32 dungeonId; // Raid id queue to leave + recv_data >> dungeonId; + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_SEARCH_LFG_LEAVE [" UI64FMTD "] dungeonId: %u", GetPlayer()->GetGUID(), dungeonId); + //sLFGMgr->LeaveLfr(GetPlayer(), dungeonId); +} + +void WorldSession::SendLfgUpdatePlayer(const LfgUpdateData& updateData) +{ + bool queued = false; + bool extrainfo = false; + + switch (updateData.updateType) + { + case LFG_UPDATETYPE_JOIN_PROPOSAL: + case LFG_UPDATETYPE_ADDED_TO_QUEUE: + queued = true; + extrainfo = true; + break; + //case LFG_UPDATETYPE_CLEAR_LOCK_LIST: // TODO: Sometimes has extrainfo - Check ocurrences... + case LFG_UPDATETYPE_PROPOSAL_BEGIN: + extrainfo = true; + break; + default: + break; + } + + uint64 guid = GetPlayer()->GetGUID(); + uint8 size = uint8(updateData.dungeons.size()); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_UPDATE_PLAYER [" UI64FMTD "] updatetype: %u", guid, updateData.updateType); + WorldPacket data(SMSG_LFG_UPDATE_PLAYER, 1 + 1 + (extrainfo ? 1 : 0) * (1 + 1 + 1 + 1 + size * 4 + updateData.comment.length())); + data << uint8(updateData.updateType); // Lfg Update type + data << uint8(extrainfo); // Extra info + if (extrainfo) + { + data << uint8(queued); // Join the queue + data << uint8(0); // unk - Always 0 + data << uint8(0); // unk - Always 0 + + data << uint8(size); + if (size) + for (LfgDungeonSet::const_iterator it = updateData.dungeons.begin(); it != updateData.dungeons.end(); ++it) + data << uint32(*it); + data << updateData.comment; + } + SendPacket(&data); +} + +void WorldSession::SendLfgUpdateParty(const LfgUpdateData& updateData) +{ + bool join = false; + bool extrainfo = false; + bool queued = false; + + switch (updateData.updateType) + { + case LFG_UPDATETYPE_JOIN_PROPOSAL: + extrainfo = true; + break; + case LFG_UPDATETYPE_ADDED_TO_QUEUE: + extrainfo = true; + join = true; + queued = true; + break; + case LFG_UPDATETYPE_CLEAR_LOCK_LIST: + // join = true; // TODO: Sometimes queued and extrainfo - Check ocurrences... + queued = true; + break; + case LFG_UPDATETYPE_PROPOSAL_BEGIN: + extrainfo = true; + join = true; + break; + default: + break; + } + + uint64 guid = GetPlayer()->GetGUID(); + uint8 size = uint8(updateData.dungeons.size()); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_UPDATE_PARTY [" UI64FMTD "] updatetype: %u", guid, updateData.updateType); + WorldPacket data(SMSG_LFG_UPDATE_PARTY, 1 + 1 + (extrainfo ? 1 : 0) * (1 + 1 + 1 + 1 + 1 + size * 4 + updateData.comment.length())); + data << uint8(updateData.updateType); // Lfg Update type + data << uint8(extrainfo); // Extra info + if (extrainfo) + { + data << uint8(join); // LFG Join + data << uint8(queued); // Join the queue + data << uint8(0); // unk - Always 0 + data << uint8(0); // unk - Always 0 + for (uint8 i = 0; i < 3; ++i) + data << uint8(0); // unk - Always 0 + + data << uint8(size); + if (size) + for (LfgDungeonSet::const_iterator it = updateData.dungeons.begin(); it != updateData.dungeons.end(); ++it) + data << uint32(*it); + data << updateData.comment; + } + SendPacket(&data); +} + +void WorldSession::SendLfgRoleChosen(uint64 guid, uint8 roles) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_ROLE_CHOSEN [" UI64FMTD "] guid: [" UI64FMTD "] roles: %u", GetPlayer()->GetGUID(), guid, roles); + + WorldPacket data(SMSG_LFG_ROLE_CHOSEN, 8 + 1 + 4); + data << uint64(guid); // Guid + data << uint8(roles > 0); // Ready + data << uint32(roles); // Roles + SendPacket(&data); +} + +void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck* pRoleCheck) +{ + ASSERT(pRoleCheck); + LfgDungeonSet dungeons; + if (pRoleCheck->rDungeonId) + dungeons.insert(pRoleCheck->rDungeonId); + else + dungeons = pRoleCheck->dungeons; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_ROLE_CHECK_UPDATE [" UI64FMTD "]", GetPlayer()->GetGUID()); + WorldPacket data(SMSG_LFG_ROLE_CHECK_UPDATE, 4 + 1 + 1 + dungeons.size() * 4 + 1 + pRoleCheck->roles.size() * (8 + 1 + 4 + 1)); + + data << uint32(pRoleCheck->state); // Check result + data << uint8(pRoleCheck->state == LFG_ROLECHECK_INITIALITING); + data << uint8(dungeons.size()); // Number of dungeons + if (!dungeons.empty()) + { + for (LfgDungeonSet::iterator it = dungeons.begin(); it != dungeons.end(); ++it) + { + LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(*it); + data << uint32(dungeon ? dungeon->Entry() : 0); // Dungeon + } + } + + data << uint8(pRoleCheck->roles.size()); // Players in group + if (!pRoleCheck->roles.empty()) + { + // Leader info MUST be sent 1st :S + uint64 guid = pRoleCheck->leader; + uint8 roles = pRoleCheck->roles.find(guid)->second; + data << uint64(guid); // Guid + data << uint8(roles > 0); // Ready + data << uint32(roles); // Roles + Player* player = ObjectAccessor::FindPlayer(guid); + data << uint8(player ? player->getLevel() : 0); // Level + + for (LfgRolesMap::const_iterator it = pRoleCheck->roles.begin(); it != pRoleCheck->roles.end(); ++it) + { + if (it->first == pRoleCheck->leader) + continue; + + guid = it->first; + roles = it->second; + data << uint64(guid); // Guid + data << uint8(roles > 0); // Ready + data << uint32(roles); // Roles + player = ObjectAccessor::FindPlayer(guid); + data << uint8(player ? player->getLevel() : 0); // Level + } + } + SendPacket(&data); +} + +void WorldSession::SendLfgJoinResult(const LfgJoinResultData& joinData) +{ + uint32 size = 0; + for (LfgLockPartyMap::const_iterator it = joinData.lockmap.begin(); it != joinData.lockmap.end(); ++it) + size += 8 + 4 + uint32(it->second.size()) * (4 + 4); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_JOIN_RESULT [" UI64FMTD "] checkResult: %u checkValue: %u", GetPlayer()->GetGUID(), joinData.result, joinData.state); + WorldPacket data(SMSG_LFG_JOIN_RESULT, 4 + 4 + size); + data << uint32(joinData.result); // Check Result + data << uint32(joinData.state); // Check Value + if (!joinData.lockmap.empty()) + BuildPartyLockDungeonBlock(data, joinData.lockmap); + SendPacket(&data); +} + +void WorldSession::SendLfgQueueStatus(uint32 dungeon, int32 waitTime, int32 avgWaitTime, int32 waitTimeTanks, int32 waitTimeHealer, int32 waitTimeDps, uint32 queuedTime, uint8 tanks, uint8 healers, uint8 dps) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_QUEUE_STATUS [" UI64FMTD "] dungeon: %u - waitTime: %d - avgWaitTime: %d - waitTimeTanks: %d - waitTimeHealer: %d - waitTimeDps: %d - queuedTime: %u - tanks: %u - healers: %u - dps: %u", GetPlayer()->GetGUID(), dungeon, waitTime, avgWaitTime, waitTimeTanks, waitTimeHealer, waitTimeDps, queuedTime, tanks, healers, dps); + + WorldPacket data(SMSG_LFG_QUEUE_STATUS, 4 + 4 + 4 + 4 + 4 +4 + 1 + 1 + 1 + 4); + data << uint32(dungeon); // Dungeon + data << int32(avgWaitTime); // Average Wait time + data << int32(waitTime); // Wait Time + data << int32(waitTimeTanks); // Wait Tanks + data << int32(waitTimeHealer); // Wait Healers + data << int32(waitTimeDps); // Wait Dps + data << uint8(tanks); // Tanks needed + data << uint8(healers); // Healers needed + data << uint8(dps); // Dps needed + data << uint32(queuedTime); // Player wait time in queue + SendPacket(&data); +} + +void WorldSession::SendLfgPlayerReward(uint32 rdungeonEntry, uint32 sdungeonEntry, uint8 done, const LfgReward* reward, const Quest* qRew) +{ + if (!rdungeonEntry || !sdungeonEntry || !qRew) + return; + + uint8 itemNum = uint8(qRew ? qRew->GetRewItemsCount() : 0); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_PLAYER_REWARD [" UI64FMTD "] rdungeonEntry: %u - sdungeonEntry: %u - done: %u", GetPlayer()->GetGUID(), rdungeonEntry, sdungeonEntry, done); + WorldPacket data(SMSG_LFG_PLAYER_REWARD, 4 + 4 + 1 + 4 + 4 + 4 + 4 + 4 + 1 + itemNum * (4 + 4 + 4)); + data << uint32(rdungeonEntry); // Random Dungeon Finished + data << uint32(sdungeonEntry); // Dungeon Finished + data << uint8(done); + data << uint32(1); + data << uint32(qRew->GetRewOrReqMoney()); + data << uint32(qRew->XPValue(GetPlayer())); + data << uint32(reward->reward[done].variableMoney); + data << uint32(reward->reward[done].variableXP); + data << uint8(itemNum); + if (itemNum) + { + ItemTemplate const* iProto = NULL; + for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i) + { + if (!qRew->RewardItemId[i]) + continue; + + iProto = sObjectMgr->GetItemTemplate(qRew->RewardItemId[i]); + + data << uint32(qRew->RewardItemId[i]); + data << uint32(iProto ? iProto->DisplayInfoID : 0); + data << uint32(qRew->RewardItemIdCount[i]); + } + } + SendPacket(&data); +} + +void WorldSession::SendLfgBootPlayer(const LfgPlayerBoot* pBoot) +{ + uint64 guid = GetPlayer()->GetGUID(); + LfgAnswer playerVote = pBoot->votes.find(guid)->second; + uint8 votesNum = 0; + uint8 agreeNum = 0; + uint32 secsleft = uint8((pBoot->cancelTime - time(NULL)) / 1000); + for (LfgAnswerMap::const_iterator it = pBoot->votes.begin(); it != pBoot->votes.end(); ++it) + { + if (it->second != LFG_ANSWER_PENDING) + { + ++votesNum; + if (it->second == LFG_ANSWER_AGREE) + ++agreeNum; + } + } + sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_BOOT_PLAYER [" UI64FMTD "] inProgress: %u - didVote: %u - agree: %u - victim: [" UI64FMTD "] votes: %u - agrees: %u - left: %u - needed: %u - reason %s", + guid, uint8(pBoot->inProgress), uint8(playerVote != LFG_ANSWER_PENDING), uint8(playerVote == LFG_ANSWER_AGREE), pBoot->victim, votesNum, agreeNum, secsleft, pBoot->votedNeeded, pBoot->reason.c_str()); + WorldPacket data(SMSG_LFG_BOOT_PLAYER, 1 + 1 + 1 + 8 + 4 + 4 + 4 + 4 + pBoot->reason.length()); + data << uint8(pBoot->inProgress); // Vote in progress + data << uint8(playerVote != LFG_ANSWER_PENDING); // Did Vote + data << uint8(playerVote == LFG_ANSWER_AGREE); // Agree + data << uint64(pBoot->victim); // Victim GUID + data << uint32(votesNum); // Total Votes + data << uint32(agreeNum); // Agree Count + data << uint32(secsleft); // Time Left + data << uint32(pBoot->votedNeeded); // Needed Votes + data << pBoot->reason.c_str(); // Kick reason + SendPacket(&data); +} + +void WorldSession::SendLfgUpdateProposal(uint32 proposalId, const LfgProposal* pProp) +{ + if (!pProp) + return; + + uint64 guid = GetPlayer()->GetGUID(); + LfgProposalPlayerMap::const_iterator itPlayer = pProp->players.find(guid); + if (itPlayer == pProp->players.end()) // Player MUST be in the proposal + return; + + LfgProposalPlayer* ppPlayer = itPlayer->second; + uint32 pLowGroupGuid = ppPlayer->groupLowGuid; + uint32 dLowGuid = pProp->groupLowGuid; + uint32 dungeonId = pProp->dungeonId; + bool isSameDungeon = false; + bool isContinue = false; + Group* grp = dLowGuid ? sGroupMgr->GetGroupByGUID(dLowGuid) : NULL; + uint32 completedEncounters = 0; + if (grp) + { + uint64 gguid = grp->GetGUID(); + isContinue = grp->isLFGGroup() && sLFGMgr->GetState(gguid) != LFG_STATE_FINISHED_DUNGEON; + isSameDungeon = GetPlayer()->GetGroup() == grp && isContinue; + } + + sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_PROPOSAL_UPDATE [" UI64FMTD "] state: %u", GetPlayer()->GetGUID(), pProp->state); + WorldPacket data(SMSG_LFG_PROPOSAL_UPDATE, 4 + 1 + 4 + 4 + 1 + 1 + pProp->players.size() * (4 + 1 + 1 + 1 + 1 +1)); + + if (!isContinue) // Only show proposal dungeon if it's continue + { + LfgDungeonSet playerDungeons = sLFGMgr->GetSelectedDungeons(guid); + if (playerDungeons.size() == 1) + dungeonId = (*playerDungeons.begin()); + } + + if (LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(dungeonId)) + { + dungeonId = dungeon->Entry(); + + // Select a player inside to be get completed encounters from + if (grp) + { + for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* groupMember = itr->getSource(); + if (groupMember && groupMember->GetMapId() == uint32(dungeon->map)) + { + if (InstanceScript* instance = groupMember->GetInstanceScript()) + completedEncounters = instance->GetCompletedEncounterMask(); + break; + } + } + } + } + + data << uint32(dungeonId); // Dungeon + data << uint8(pProp->state); // Result state + data << uint32(proposalId); // Internal Proposal ID + data << uint32(completedEncounters); // Bosses killed + data << uint8(isSameDungeon); // Silent (show client window) + data << uint8(pProp->players.size()); // Group size + + for (itPlayer = pProp->players.begin(); itPlayer != pProp->players.end(); ++itPlayer) + { + ppPlayer = itPlayer->second; + data << uint32(ppPlayer->role); // Role + data << uint8(itPlayer->first == guid); // Self player + if (!ppPlayer->groupLowGuid) // Player not it a group + { + data << uint8(0); // Not in dungeon + data << uint8(0); // Not same group + } + else + { + data << uint8(ppPlayer->groupLowGuid == dLowGuid); // In dungeon (silent) + data << uint8(ppPlayer->groupLowGuid == pLowGroupGuid); // Same Group than player + } + data << uint8(ppPlayer->accept != LFG_ANSWER_PENDING); // Answered + data << uint8(ppPlayer->accept == LFG_ANSWER_AGREE); // Accepted + } + SendPacket(&data); +} + +void WorldSession::SendLfgUpdateSearch(bool update) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_UPDATE_SEARCH [" UI64FMTD "] update: %u", GetPlayer()->GetGUID(), update ? 1 : 0); + WorldPacket data(SMSG_LFG_UPDATE_SEARCH, 1); + data << uint8(update); // In Lfg Queue? + SendPacket(&data); +} + +void WorldSession::SendLfgDisabled() +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_DISABLED [" UI64FMTD "]", GetPlayer()->GetGUID()); + WorldPacket data(SMSG_LFG_DISABLED, 0); + SendPacket(&data); +} + +void WorldSession::SendLfgOfferContinue(uint32 dungeonEntry) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_OFFER_CONTINUE [" UI64FMTD "] dungeon entry: %u", GetPlayer()->GetGUID(), dungeonEntry); + WorldPacket data(SMSG_LFG_OFFER_CONTINUE, 4); + data << uint32(dungeonEntry); + SendPacket(&data); +} + +void WorldSession::SendLfgTeleportError(uint8 err) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_TELEPORT_DENIED [" UI64FMTD "] reason: %u", GetPlayer()->GetGUID(), err); + WorldPacket data(SMSG_LFG_TELEPORT_DENIED, 4); + data << uint32(err); // Error + SendPacket(&data); +} + +/* +void WorldSession::SendLfrUpdateListOpcode(uint32 dungeonEntry) +{ + sLog->outDebug(LOG_FILTER_PACKETIO, "SMSG_UPDATE_LFG_LIST [" UI64FMTD "] dungeon entry: %u", GetPlayer()->GetGUID(), dungeonEntry); + WorldPacket data(SMSG_UPDATE_LFG_LIST); + SendPacket(&data); +} +*/ diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp new file mode 100755 index 00000000000..6508f08dc22 --- /dev/null +++ b/src/server/game/Handlers/LootHandler.cpp @@ -0,0 +1,508 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "WorldPacket.h" +#include "Log.h" +#include "Corpse.h" +#include "GameObject.h" +#include "Player.h" +#include "ObjectAccessor.h" +#include "WorldSession.h" +#include "LootMgr.h" +#include "Object.h" +#include "Group.h" +#include "World.h" +#include "Util.h" + +void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AUTOSTORE_LOOT_ITEM"); + Player* player = GetPlayer(); + uint64 lguid = player->GetLootGUID(); + Loot* loot = NULL; + uint8 lootSlot = 0; + + recv_data >> lootSlot; + + if (IS_GAMEOBJECT_GUID(lguid)) + { + GameObject* go = player->GetMap()->GetGameObject(lguid); + + // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO + if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player, INTERACTION_DISTANCE))) + { + player->SendLootRelease(lguid); + return; + } + + loot = &go->loot; + } + else if (IS_ITEM_GUID(lguid)) + { + Item* pItem = player->GetItemByGuid(lguid); + + if (!pItem) + { + player->SendLootRelease(lguid); + return; + } + + loot = &pItem->loot; + } + else if (IS_CORPSE_GUID(lguid)) + { + Corpse* bones = ObjectAccessor::GetCorpse(*player, lguid); + if (!bones) + { + player->SendLootRelease(lguid); + return; + } + + loot = &bones->loot; + } + else + { + Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid); + + bool ok_loot = creature && creature->isAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed); + + if (!ok_loot || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) + { + player->SendLootRelease(lguid); + return; + } + + loot = &creature->loot; + } + + player->StoreLootItem(lootSlot, loot); +} + +void WorldSession::HandleLootMoneyOpcode(WorldPacket & /*recv_data*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_LOOT_MONEY"); + + Player* player = GetPlayer(); + uint64 guid = player->GetLootGUID(); + if (!guid) + return; + + Loot* loot = NULL; + bool shareMoney = true; + + switch (GUID_HIPART(guid)) + { + case HIGHGUID_GAMEOBJECT: + { + GameObject* go = GetPlayer()->GetMap()->GetGameObject(guid); + + // do not check distance for GO if player is the owner of it (ex. fishing bobber) + if (go && ((go->GetOwnerGUID() == player->GetGUID() || go->IsWithinDistInMap(player, INTERACTION_DISTANCE)))) + loot = &go->loot; + + break; + } + case HIGHGUID_CORPSE: // remove insignia ONLY in BG + { + Corpse* bones = ObjectAccessor::GetCorpse(*player, guid); + + if (bones && bones->IsWithinDistInMap(player, INTERACTION_DISTANCE)) + { + loot = &bones->loot; + shareMoney = false; + } + + break; + } + case HIGHGUID_ITEM: + { + if (Item* item = player->GetItemByGuid(guid)) + { + loot = &item->loot; + shareMoney = false; + } + break; + } + case HIGHGUID_UNIT: + case HIGHGUID_VEHICLE: + { + Creature* creature = player->GetMap()->GetCreature(guid); + bool lootAllowed = creature && creature->isAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed); + if (lootAllowed && creature->IsWithinDistInMap(player, INTERACTION_DISTANCE)) + { + loot = &creature->loot; + if (creature->isAlive()) + shareMoney = false; + } + break; + } + default: + return; // unlootable type + } + + if (loot) + { + loot->NotifyMoneyRemoved(); + if (shareMoney && player->GetGroup()) //item, pickpocket and players can be looted only single player + { + Group* group = player->GetGroup(); + + std::vector playersNear; + for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* member = itr->getSource(); + if (!member) + continue; + + if (player->IsWithinDistInMap(member, sWorld->getFloatConfig(CONFIG_GROUP_XP_DISTANCE), false)) + playersNear.push_back(member); + } + + uint32 goldPerPlayer = uint32((loot->gold) / (playersNear.size())); + + for (std::vector::const_iterator i = playersNear.begin(); i != playersNear.end(); ++i) + { + (*i)->ModifyMoney(goldPerPlayer); + (*i)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, goldPerPlayer); + + WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4 + 1); + data << uint32(goldPerPlayer); + data << uint8(playersNear.size() > 1 ? 0 : 1); // Controls the text displayed in chat. 0 is "Your share is..." and 1 is "You loot..." + (*i)->GetSession()->SendPacket(&data); + } + } + else + { + player->ModifyMoney(loot->gold); + player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, loot->gold); + + WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4 + 1); + data << uint32(loot->gold); + data << uint8(1); // "You loot..." + SendPacket(&data); + } + + loot->gold = 0; + } +} + +void WorldSession::HandleLootOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_LOOT"); + + uint64 guid; + recv_data >> guid; + + // Check possible cheat + if (!_player->isAlive()) + return; + + GetPlayer()->SendLoot(guid, LOOT_CORPSE); + + // interrupt cast + if (GetPlayer()->IsNonMeleeSpellCasted(false)) + GetPlayer()->InterruptNonMeleeSpells(false); +} + +void WorldSession::HandleLootReleaseOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_LOOT_RELEASE"); + + // cheaters can modify lguid to prevent correct apply loot release code and re-loot + // use internal stored guid + recv_data.read_skip(); // guid; + + if (uint64 lguid = GetPlayer()->GetLootGUID()) + DoLootRelease(lguid); +} + +void WorldSession::DoLootRelease(uint64 lguid) +{ + Player *player = GetPlayer(); + Loot *loot; + + player->SetLootGUID(0); + player->SendLootRelease(lguid); + + player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); + + if (!player->IsInWorld()) + return; + + if (IS_GAMEOBJECT_GUID(lguid)) + { + GameObject* go = GetPlayer()->GetMap()->GetGameObject(lguid); + + // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO + if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player, INTERACTION_DISTANCE))) + return; + + loot = &go->loot; + + if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR) + { + // locked doors are opened with spelleffect openlock, prevent remove its as looted + go->UseDoorOrButton(); + } + else if (loot->isLooted() || go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE) + { + // GO is mineral vein? so it is not removed after its looted + if (go->GetGoType() == GAMEOBJECT_TYPE_CHEST) + { + uint32 go_min = go->GetGOInfo()->chest.minSuccessOpens; + uint32 go_max = go->GetGOInfo()->chest.maxSuccessOpens; + + // only vein pass this check + if (go_min != 0 && go_max > go_min) + { + float amount_rate = sWorld->getRate(RATE_MINING_AMOUNT); + float min_amount = go_min*amount_rate; + float max_amount = go_max*amount_rate; + + go->AddUse(); + float uses = float(go->GetUseCount()); + + if (uses < max_amount) + { + if (uses >= min_amount) + { + float chance_rate = sWorld->getRate(RATE_MINING_NEXT); + + int32 ReqValue = 175; + LockEntry const* lockInfo = sLockStore.LookupEntry(go->GetGOInfo()->chest.lockId); + if (lockInfo) + ReqValue = lockInfo->Skill[0]; + float skill = float(player->GetSkillValue(SKILL_MINING))/(ReqValue+25); + double chance = pow(0.8*chance_rate, 4*(1/double(max_amount))*double(uses)); + if (roll_chance_f((float)(100*chance+skill))) + { + go->SetLootState(GO_READY); + } + else // not have more uses + go->SetLootState(GO_JUST_DEACTIVATED); + } + else // 100% chance until min uses + go->SetLootState(GO_READY); + } + else // max uses already + go->SetLootState(GO_JUST_DEACTIVATED); + } + else // not vein + go->SetLootState(GO_JUST_DEACTIVATED); + } + else if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGHOLE) + { // The fishing hole used once more + go->AddUse(); // if the max usage is reached, will be despawned in next tick + if (go->GetUseCount() >= urand(go->GetGOInfo()->fishinghole.minSuccessOpens, go->GetGOInfo()->fishinghole.maxSuccessOpens)) + { + go->SetLootState(GO_JUST_DEACTIVATED); + } + else + go->SetLootState(GO_READY); + } + else // not chest (or vein/herb/etc) + go->SetLootState(GO_JUST_DEACTIVATED); + + loot->clear(); + } + else + { + // not fully looted object + go->SetLootState(GO_ACTIVATED, player); + + // if the round robin player release, reset it. + if (player->GetGUID() == loot->roundRobinPlayer) + { + if (Group* group = player->GetGroup()) + { + if (group->GetLootMethod() != MASTER_LOOT) + { + loot->roundRobinPlayer = 0; + } + } + else + loot->roundRobinPlayer = 0; + } + } + } + else if (IS_CORPSE_GUID(lguid)) // ONLY remove insignia at BG + { + Corpse* corpse = ObjectAccessor::GetCorpse(*player, lguid); + if (!corpse || !corpse->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) + return; + + loot = &corpse->loot; + + if (loot->isLooted()) + { + loot->clear(); + corpse->RemoveFlag(CORPSE_FIELD_DYNAMIC_FLAGS, CORPSE_DYNFLAG_LOOTABLE); + } + } + else if (IS_ITEM_GUID(lguid)) + { + Item* pItem = player->GetItemByGuid(lguid); + if (!pItem) + return; + + ItemTemplate const* proto = pItem->GetTemplate(); + + // destroy only 5 items from stack in case prospecting and milling + if (proto->Flags & (ITEM_PROTO_FLAG_PROSPECTABLE | ITEM_PROTO_FLAG_MILLABLE)) + { + pItem->m_lootGenerated = false; + pItem->loot.clear(); + + uint32 count = pItem->GetCount(); + + // >=5 checked in spell code, but will work for cheating cases also with removing from another stacks. + if (count > 5) + count = 5; + + player->DestroyItemCount(pItem, count, true); + } + else + // FIXME: item must not be deleted in case not fully looted state. But this pre-request implement loot saving in DB at item save. Or cheating possible. + player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); + return; // item can be looted only single player + } + else + { + Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid); + + bool ok_loot = creature && creature->isAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed); + if (!ok_loot || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) + return; + + loot = &creature->loot; + if (loot->isLooted()) + { + // skip pickpocketing loot for speed, skinning timer reduction is no-op in fact + if (!creature->isAlive()) + creature->AllLootRemovedFromCorpse(); + + creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + loot->clear(); + } + else + { + // if the round robin player release, reset it. + if (player->GetGUID() == loot->roundRobinPlayer) + { + if (Group* group = player->GetGroup()) + { + if (group->GetLootMethod() != MASTER_LOOT) + { + loot->roundRobinPlayer = 0; + group->SendLooter(creature, NULL); + + // force update of dynamic flags, otherwise other group's players still not able to loot. + creature->ForceValuesUpdateAtIndex(UNIT_DYNAMIC_FLAGS); + } + } + else + loot->roundRobinPlayer = 0; + } + } + } + + //Player is not looking at loot list, he doesn't need to see updates on the loot list + loot->RemoveLooter(player->GetGUID()); +} + +void WorldSession::HandleLootMasterGiveOpcode(WorldPacket & recv_data) +{ + uint8 slotid; + uint64 lootguid, target_playerguid; + + recv_data >> lootguid >> slotid >> target_playerguid; + + if (!_player->GetGroup() || _player->GetGroup()->GetLooterGuid() != _player->GetGUID()) + { + _player->SendLootRelease(GetPlayer()->GetLootGUID()); + return; + } + + Player* target = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(target_playerguid, 0, HIGHGUID_PLAYER)); + if (!target) + return; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WorldSession::HandleLootMasterGiveOpcode (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = [%s].", target->GetName()); + + if (_player->GetLootGUID() != lootguid) + return; + + Loot* pLoot = NULL; + + if (IS_CRE_OR_VEH_GUID(GetPlayer()->GetLootGUID())) + { + Creature* creature = GetPlayer()->GetMap()->GetCreature(lootguid); + if (!creature) + return; + + pLoot = &creature->loot; + } + else if (IS_GAMEOBJECT_GUID(GetPlayer()->GetLootGUID())) + { + GameObject* pGO = GetPlayer()->GetMap()->GetGameObject(lootguid); + if (!pGO) + return; + + pLoot = &pGO->loot; + } + + if (!pLoot) + return; + + if (slotid > pLoot->items.size()) + { + sLog->outDebug(LOG_FILTER_LOOT, "MasterLootItem: Player %s might be using a hack! (slot %d, size %lu)", GetPlayer()->GetName(), slotid, (unsigned long)pLoot->items.size()); + return; + } + + LootItem& item = pLoot->items[slotid]; + + ItemPosCountVec dest; + InventoryResult msg = target->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.itemid, item.count); + if (msg != EQUIP_ERR_OK) + { + target->SendEquipError(msg, NULL, NULL, item.itemid); + // send duplicate of error massage to master looter + _player->SendEquipError(msg, NULL, NULL, item.itemid); + return; + } + + // list of players allowed to receive this item in trade + AllowedLooterSet looters = item.GetAllowedLooters(); + + // not move item from loot to target inventory + Item* newitem = target->StoreNewItem(dest, item.itemid, true, item.randomPropertyId, looters); + target->SendNewItem(newitem, uint32(item.count), false, false, true); + target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item.itemid, item.count); + target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, pLoot->loot_type, item.count); + target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item.itemid, item.count); + + // mark as looted + item.count=0; + item.is_looted=true; + + pLoot->NotifyItemRemoved(slotid); + --pLoot->unlootedCount; +} + diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp new file mode 100755 index 00000000000..a8522bb2582 --- /dev/null +++ b/src/server/game/Handlers/MailHandler.cpp @@ -0,0 +1,773 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "DatabaseEnv.h" +#include "Mail.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Opcodes.h" +#include "Log.h" +#include "World.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "Language.h" +#include "DBCStores.h" +#include "Item.h" +#include "AccountMgr.h" + +void WorldSession::HandleSendMail(WorldPacket & recv_data) +{ + uint64 mailbox, unk3; + std::string receiver, subject, body; + uint32 unk1, unk2, money, COD; + uint8 unk4; + recv_data >> mailbox; + recv_data >> receiver; + + recv_data >> subject; + + recv_data >> body; + + recv_data >> unk1; // stationery? + recv_data >> unk2; // 0x00000000 + + uint8 items_count; + recv_data >> items_count; // attached items count + + if (items_count > MAX_MAIL_ITEMS) // client limit + { + GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_TOO_MANY_ATTACHMENTS); + recv_data.rfinish(); // set to end to avoid warnings spam + return; + } + + uint64 itemGUIDs[MAX_MAIL_ITEMS]; + + for (uint8 i = 0; i < items_count; ++i) + { + recv_data.read_skip(); // item slot in mail, not used + recv_data >> itemGUIDs[i]; + } + + recv_data >> money >> COD; // money and cod + recv_data >> unk3; // const 0 + recv_data >> unk4; // const 0 + + // packet read complete, now do check + + if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) + return; + + if (receiver.empty()) + return; + + Player* player = _player; + + if (player->getLevel() < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)) + { + SendNotification(GetTrinityString(LANG_MAIL_SENDER_REQ), sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)); + return; + } + + uint64 rc = 0; + if (normalizePlayerName(receiver)) + rc = sObjectMgr->GetPlayerGUIDByName(receiver); + + if (!rc) + { + sLog->outDetail("Player %u is sending mail to %s (GUID: not existed!) with subject %s and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", + player->GetGUIDLow(), receiver.c_str(), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); + player->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_NOT_FOUND); + return; + } + + sLog->outDetail("Player %u is sending mail to %s (GUID: %u) with subject %s and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", player->GetGUIDLow(), receiver.c_str(), GUID_LOPART(rc), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); + + if (player->GetGUID() == rc) + { + player->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANNOT_SEND_TO_SELF); + return; + } + + uint32 cost = items_count ? 30 * items_count : 30; // price hardcoded in client + + uint32 reqmoney = cost + money; + + if (!player->HasEnoughMoney(reqmoney)) + { + player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY); + return; + } + + Player* receive = ObjectAccessor::FindPlayer(rc); + + uint32 rc_team = 0; + uint8 mails_count = 0; //do not allow to send to one player more than 100 mails + uint8 receiveLevel = 0; + + if (receive) + { + rc_team = receive->GetTeam(); + mails_count = receive->GetMailSize(); + receiveLevel = receive->getLevel(); + } + else + { + rc_team = sObjectMgr->GetPlayerTeamByGUID(rc); + if (QueryResult result = CharacterDatabase.PQuery("SELECT COUNT(*) FROM mail WHERE receiver = '%u'", GUID_LOPART(rc))) + { + Field* fields = result->Fetch(); + mails_count = fields[0].GetUInt32(); + } + if (QueryResult result = CharacterDatabase.PQuery("SELECT level FROM characters WHERE guid = '%u'", GUID_LOPART(rc))) + { + Field* fields = result->Fetch(); + receiveLevel = fields[0].GetUInt8(); + } + } + //do not allow to have more than 100 mails in mailbox.. mails count is in opcode uint8!!! - so max can be 255.. + if (mails_count > 100) + { + player->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_CAP_REACHED); + return; + } + // test the receiver's Faction... or all items are account bound + bool accountBound = items_count ? true : false; + for (uint8 i = 0; i < items_count; ++i) + { + Item* item = player->GetItemByGuid(itemGUIDs[i]); + if (item) + { + ItemTemplate const* itemProto = item->GetTemplate(); + if (!itemProto || !(itemProto->Flags & ITEM_PROTO_FLAG_BIND_TO_ACCOUNT)) + { + accountBound = false; + break; + } + } + } + + if (!accountBound && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL) && player->GetTeam() != rc_team && AccountMgr::IsPlayerAccount(GetSecurity())) + { + player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_YOUR_TEAM); + return; + } + + if (receiveLevel < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)) + { + SendNotification(GetTrinityString(LANG_MAIL_RECEIVER_REQ), sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)); + return; + } + + uint32 rc_account = receive + ? receive->GetSession()->GetAccountId() + : sObjectMgr->GetPlayerAccountIdByGUID(rc); + + Item* items[MAX_MAIL_ITEMS]; + + for (uint8 i = 0; i < items_count; ++i) + { + if (!itemGUIDs[i]) + { + player->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); + return; + } + + Item* item = player->GetItemByGuid(itemGUIDs[i]); + + // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail) + if (!item) + { + player->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); + return; + } + + if (!item->CanBeTraded(true)) + { + player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); + return; + } + + if (item->IsBoundAccountWide() && item->IsSoulBound() && player->GetSession()->GetAccountId() != rc_account) + { + player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_ARTEFACTS_ONLY_FOR_OWN_CHARACTERS); + return; + } + + if (item->GetTemplate()->Flags & ITEM_PROTO_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION)) + { + player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); + return; + } + + if (COD && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) + { + player->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD); + return; + } + + if (item->IsNotEmptyBag()) + { + player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS); + return; + } + + items[i] = item; + } + + player->SendMailResult(0, MAIL_SEND, MAIL_OK); + + player->ModifyMoney(-int32(reqmoney)); + player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL, cost); + + bool needItemDelay = false; + + MailDraft draft(subject, body); + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + + if (items_count > 0 || money > 0) + { + if (items_count > 0) + { + for (uint8 i = 0; i < items_count; ++i) + { + Item* item = items[i]; + if (!AccountMgr::IsPlayerAccount(GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) + { + sLog->outCommand(GetAccountId(), "GM %s (Account: %u) mail item: %s (Entry: %u Count: %u) to player: %s (Account: %u)", + GetPlayerName(), GetAccountId(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount(), receiver.c_str(), rc_account); + } + + item->SetNotRefundable(GetPlayer()); // makes the item no longer refundable + player->MoveItemFromInventory(items[i]->GetBagSlot(), item->GetSlot(), true); + + item->DeleteFromInventoryDB(trans); // deletes item from character's inventory + item->SetOwnerGUID(rc); + item->SaveToDB(trans); // recursive and not have transaction guard into self, item not in inventory and can be save standalone + + draft.AddItem(item); + } + + // if item send to character at another account, then apply item delivery delay + needItemDelay = player->GetSession()->GetAccountId() != rc_account; + } + + if (money > 0 && !AccountMgr::IsPlayerAccount(GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) + { + sLog->outCommand(GetAccountId(), "GM %s (Account: %u) mail money: %u to player: %s (Account: %u)", + GetPlayerName(), GetAccountId(), money, receiver.c_str(), rc_account); + } + } + + // If theres is an item, there is a one hour delivery delay if sent to another account's character. + uint32 deliver_delay = needItemDelay ? sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY) : 0; + + // will delete item or place to receiver mail list + draft + .AddMoney(money) + .AddCOD(COD) + .SendMailTo(trans, MailReceiver(receive, GUID_LOPART(rc)), MailSender(player), body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay); + + player->SaveInventoryAndGoldToDB(trans); + CharacterDatabase.CommitTransaction(trans); +} + +//called when mail is read +void WorldSession::HandleMailMarkAsRead(WorldPacket & recv_data) +{ + uint64 mailbox; + uint32 mailId; + recv_data >> mailbox; + recv_data >> mailId; + + if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) + return; + + Player* player = _player; + Mail* m = player->GetMail(mailId); + if (m) + { + if (player->unReadMails) + --player->unReadMails; + m->checked = m->checked | MAIL_CHECK_MASK_READ; + player->m_mailsUpdated = true; + m->state = MAIL_STATE_CHANGED; + } +} + +//called when client deletes mail +void WorldSession::HandleMailDelete(WorldPacket & recv_data) +{ + uint64 mailbox; + uint32 mailId; + recv_data >> mailbox; + recv_data >> mailId; + recv_data.read_skip(); // mailTemplateId + + if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) + return; + + Mail* m = _player->GetMail(mailId); + Player* player = _player; + player->m_mailsUpdated = true; + if (m) + { + // delete shouldn't show up for COD mails + if (m->COD) + { + player->SendMailResult(mailId, MAIL_DELETED, MAIL_ERR_INTERNAL_ERROR); + return; + } + + m->state = MAIL_STATE_DELETED; + } + player->SendMailResult(mailId, MAIL_DELETED, MAIL_OK); +} + +void WorldSession::HandleMailReturnToSender(WorldPacket & recv_data) +{ + uint64 mailbox; + uint32 mailId; + recv_data >> mailbox; + recv_data >> mailId; + recv_data.read_skip(); // original sender GUID for return to, not used + + if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) + return; + + Player* player = _player; + Mail* m = player->GetMail(mailId); + if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) + { + player->SendMailResult(mailId, MAIL_RETURNED_TO_SENDER, MAIL_ERR_INTERNAL_ERROR); + return; + } + //we can return mail now + //so firstly delete the old one + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + trans->PAppend("DELETE FROM mail WHERE id = '%u'", mailId); // needed? + trans->PAppend("DELETE FROM mail_items WHERE mail_id = '%u'", mailId); + player->RemoveMail(mailId); + + // only return mail if the player exists (and delete if not existing) + if (m->messageType == MAIL_NORMAL && m->sender) + { + MailDraft draft(m->subject, m->body); + if (m->mailTemplateId) + draft = MailDraft(m->mailTemplateId, false); // items already included + + if (m->HasItems()) + { + for (MailItemInfoVec::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2) + { + Item* item = player->GetMItem(itr2->item_guid); + if (item) + draft.AddItem(item); + else + { + //WTF? + } + + player->RemoveMItem(itr2->item_guid); + } + } + draft.AddMoney(m->money).SendReturnToSender(GetAccountId(), m->receiver, m->sender, trans); + } + + CharacterDatabase.CommitTransaction(trans); + + delete m; //we can deallocate old mail + player->SendMailResult(mailId, MAIL_RETURNED_TO_SENDER, MAIL_OK); +} + +//called when player takes item attached in mail +void WorldSession::HandleMailTakeItem(WorldPacket & recv_data) +{ + uint64 mailbox; + uint32 mailId; + uint32 itemId; + recv_data >> mailbox; + recv_data >> mailId; + recv_data >> itemId; // item guid low + + if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) + return; + + Player* player = _player; + + Mail* m = player->GetMail(mailId); + if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) + { + player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR); + return; + } + + // prevent cheating with skip client money check + if (!player->HasEnoughMoney(m->COD)) + { + player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_NOT_ENOUGH_MONEY); + return; + } + + Item* it = player->GetMItem(itemId); + + ItemPosCountVec dest; + uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, it, false); + if (msg == EQUIP_ERR_OK) + { + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + m->RemoveItem(itemId); + m->removedItems.push_back(itemId); + + if (m->COD > 0) //if there is COD, take COD money from player and send them to sender by mail + { + uint64 sender_guid = MAKE_NEW_GUID(m->sender, 0, HIGHGUID_PLAYER); + Player* receive = ObjectAccessor::FindPlayer(sender_guid); + + uint32 sender_accId = 0; + + if (!AccountMgr::IsPlayerAccount(GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) + { + std::string sender_name; + if (receive) + { + sender_accId = receive->GetSession()->GetAccountId(); + sender_name = receive->GetName(); + } + else + { + // can be calculated early + sender_accId = sObjectMgr->GetPlayerAccountIdByGUID(sender_guid); + + if (!sObjectMgr->GetPlayerNameByGUID(sender_guid, sender_name)) + sender_name = sObjectMgr->GetTrinityStringForDBCLocale(LANG_UNKNOWN); + } + sLog->outCommand(GetAccountId(), "GM %s (Account: %u) receive mail item: %s (Entry: %u Count: %u) and send COD money: %u to player: %s (Account: %u)", + GetPlayerName(), GetAccountId(), it->GetTemplate()->Name1.c_str(), it->GetEntry(), it->GetCount(), m->COD, sender_name.c_str(), sender_accId); + } + else if (!receive) + sender_accId = sObjectMgr->GetPlayerAccountIdByGUID(sender_guid); + + // check player existence + if (receive || sender_accId) + { + MailDraft(m->subject, "") + .AddMoney(m->COD) + .SendMailTo(trans, MailReceiver(receive, m->sender), MailSender(MAIL_NORMAL, m->receiver), MAIL_CHECK_MASK_COD_PAYMENT); + } + + player->ModifyMoney(-int32(m->COD)); + } + m->COD = 0; + m->state = MAIL_STATE_CHANGED; + player->m_mailsUpdated = true; + player->RemoveMItem(it->GetGUIDLow()); + + uint32 count = it->GetCount(); // save counts before store and possible merge with deleting + player->MoveItemToInventory(dest, it, true); + + player->SaveInventoryAndGoldToDB(trans); + player->_SaveMail(trans); + CharacterDatabase.CommitTransaction(trans); + + player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_OK, 0, itemId, count); + } + else + player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_EQUIP_ERROR, msg); +} + +void WorldSession::HandleMailTakeMoney(WorldPacket & recv_data) +{ + uint64 mailbox; + uint32 mailId; + recv_data >> mailbox; + recv_data >> mailId; + + if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) + return; + + Player* player = _player; + + Mail* m = player->GetMail(mailId); + if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) + { + player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_ERR_INTERNAL_ERROR); + return; + } + + player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_OK); + + player->ModifyMoney(m->money); + m->money = 0; + m->state = MAIL_STATE_CHANGED; + player->m_mailsUpdated = true; + + // save money and mail to prevent cheating + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + player->SaveGoldToDB(trans); + player->_SaveMail(trans); + CharacterDatabase.CommitTransaction(trans); +} + +//called when player lists his received mails +void WorldSession::HandleGetMailList(WorldPacket & recv_data) +{ + uint64 mailbox; + recv_data >> mailbox; + + if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) + return; + + Player* player = _player; + + //load players mails, and mailed items + if (!player->m_mailsLoaded) + player ->_LoadMail(); + + // client can't work with packets > max int16 value + const uint32 maxPacketSize = 32767; + + uint32 mailsCount = 0; // real send to client mails amount + uint32 realCount = 0; // real mails amount + + WorldPacket data(SMSG_MAIL_LIST_RESULT, (200)); // guess size + data << uint32(0); // real mail's count + data << uint8(0); // mail's count + time_t cur_time = time(NULL); + + for (PlayerMails::iterator itr = player->GetMailBegin(); itr != player->GetMailEnd(); ++itr) + { + // packet send mail count as uint8, prevent overflow + if (mailsCount >= 254) + { + realCount += 1; + continue; + } + + // skip deleted or not delivered (deliver delay not expired) mails + if ((*itr)->state == MAIL_STATE_DELETED || cur_time < (*itr)->deliver_time) + continue; + + uint8 item_count = (*itr)->items.size(); // max count is MAX_MAIL_ITEMS (12) + + size_t next_mail_size = 2+4+1+((*itr)->messageType == MAIL_NORMAL ? 8 : 4)+4*8+((*itr)->subject.size()+1)+((*itr)->body.size()+1)+1+item_count*(1+4+4+7*3*4+4+4+4+4+4+4+1); + + if (data.wpos()+next_mail_size > maxPacketSize) + { + realCount += 1; + continue; + } + + data << uint16(next_mail_size); // Message size + data << uint32((*itr)->messageID); // Message ID + data << uint8((*itr)->messageType); // Message Type + + switch ((*itr)->messageType) + { + case MAIL_NORMAL: // sender guid + data << uint64(MAKE_NEW_GUID((*itr)->sender, 0, HIGHGUID_PLAYER)); + break; + case MAIL_CREATURE: + case MAIL_GAMEOBJECT: + case MAIL_AUCTION: + data << uint32((*itr)->sender); // creature/gameobject entry, auction id + break; + case MAIL_ITEM: // item entry (?) sender = "Unknown", NYI + data << uint32(0); // item entry + break; + } + + data << uint32((*itr)->COD); // COD + data << uint32(0); // probably changed in 3.3.3 + data << uint32((*itr)->stationery); // stationery (Stationery.dbc) + data << uint32((*itr)->money); // Gold + data << uint32((*itr)->checked); // flags + data << float(((*itr)->expire_time-time(NULL))/DAY); // Time + data << uint32((*itr)->mailTemplateId); // mail template (MailTemplate.dbc) + data << (*itr)->subject; // Subject string - once 00, when mail type = 3, max 256 + data << (*itr)->body; // message? max 8000 + data << uint8(item_count); // client limit is 0x10 + + for (uint8 i = 0; i < item_count; ++i) + { + Item* item = player->GetMItem((*itr)->items[i].item_guid); + // item index (0-6?) + data << uint8(i); + // item guid low? + data << uint32((item ? item->GetGUIDLow() : 0)); + // entry + data << uint32((item ? item->GetEntry() : 0)); + for (uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; ++j) + { + data << uint32((item ? item->GetEnchantmentId((EnchantmentSlot)j) : 0)); + data << uint32((item ? item->GetEnchantmentDuration((EnchantmentSlot)j) : 0)); + data << uint32((item ? item->GetEnchantmentCharges((EnchantmentSlot)j) : 0)); + } + // can be negative + data << int32((item ? item->GetItemRandomPropertyId() : 0)); + // unk + data << uint32((item ? item->GetItemSuffixFactor() : 0)); + // stack count + data << uint32((item ? item->GetCount() : 0)); + // charges + data << uint32((item ? item->GetSpellCharges() : 0)); + // durability + data << uint32((item ? item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY) : 0)); + // durability + data << uint32((item ? item->GetUInt32Value(ITEM_FIELD_DURABILITY) : 0)); + // unknown wotlk + data << uint8(0); + } + + realCount += 1; + mailsCount += 1; + } + + data.put(0, realCount); // this will display warning about undelivered mail to player if realCount > mailsCount + data.put(4, mailsCount); // set real send mails to client + SendPacket(&data); + + // recalculate m_nextMailDelivereTime and unReadMails + _player->UpdateNextMailTimeAndUnreads(); +} + +//used when player copies mail body to his inventory +void WorldSession::HandleMailCreateTextItem(WorldPacket & recv_data) +{ + uint64 mailbox; + uint32 mailId; + + recv_data >> mailbox; + recv_data >> mailId; + + if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) + return; + + Player* player = _player; + + Mail* m = player->GetMail(mailId); + if (!m || (m->body.empty() && !m->mailTemplateId) || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) + { + player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR); + return; + } + + Item* bodyItem = new Item; // This is not bag and then can be used new Item. + if (!bodyItem->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_ITEM), MAIL_BODY_ITEM_TEMPLATE, player)) + { + delete bodyItem; + return; + } + + // in mail template case we need create new item text + if (m->mailTemplateId) + { + MailTemplateEntry const* mailTemplateEntry = sMailTemplateStore.LookupEntry(m->mailTemplateId); + if (!mailTemplateEntry) + { + player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR); + return; + } + + bodyItem->SetText(mailTemplateEntry->content[GetSessionDbcLocale()]); + } + else + bodyItem->SetText(m->body); + + bodyItem->SetUInt32Value(ITEM_FIELD_CREATOR, m->sender); + bodyItem->SetFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_MAIL_TEXT_MASK); + + sLog->outDetail("HandleMailCreateTextItem mailid=%u", mailId); + + ItemPosCountVec dest; + uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, bodyItem, false); + if (msg == EQUIP_ERR_OK) + { + m->checked = m->checked | MAIL_CHECK_MASK_COPIED; + m->state = MAIL_STATE_CHANGED; + player->m_mailsUpdated = true; + + player->StoreItem(dest, bodyItem, true); + player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_OK); + } + else + { + player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_EQUIP_ERROR, msg); + delete bodyItem; + } +} + +//TODO Fix me! ... this void has probably bad condition, but good data are sent +void WorldSession::HandleQueryNextMailTime(WorldPacket & /*recv_data*/) +{ + WorldPacket data(MSG_QUERY_NEXT_MAIL_TIME, 8); + + if (!_player->m_mailsLoaded) + _player->_LoadMail(); + + if (_player->unReadMails > 0) + { + data << uint32(0); // float + data << uint32(0); // count + + uint32 count = 0; + time_t now = time(NULL); + for (PlayerMails::iterator itr = _player->GetMailBegin(); itr != _player->GetMailEnd(); ++itr) + { + Mail* m = (*itr); + // must be not checked yet + if (m->checked & MAIL_CHECK_MASK_READ) + continue; + + // and already delivered + if (now < m->deliver_time) + continue; + + if (m->messageType) + data << uint64(m->sender); // player guid + else + data << uint32(m->sender); // creature entry + + switch (m->messageType) + { + case MAIL_AUCTION: + data << uint32(2); + data << uint32(2); + data << uint32(m->stationery); + break; + default: + data << uint32(0); + data << uint32(0); + data << uint32(m->stationery); + break; + } + data << uint32(0xC6000000); // float unk, time or something + + ++count; + if (count == 2) // do not display more than 2 mails + break; + } + data.put(4, count); + } + else + { + data << uint32(0xC7A8C000); + data << uint32(0x00000000); + } + SendPacket(&data); +} diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp new file mode 100755 index 00000000000..d1227c9b7d7 --- /dev/null +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -0,0 +1,1729 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "Language.h" +#include "DatabaseEnv.h" +#include "WorldPacket.h" +#include "Opcodes.h" +#include "Log.h" +#include "Player.h" +#include "GossipDef.h" +#include "World.h" +#include "ObjectMgr.h" +#include "GuildMgr.h" +#include "WorldSession.h" +#include "BigNumber.h" +#include "SHA1.h" +#include "UpdateData.h" +#include "LootMgr.h" +#include "Chat.h" +#include "zlib.h" +#include "ObjectAccessor.h" +#include "Object.h" +#include "Battleground.h" +#include "OutdoorPvP.h" +#include "Pet.h" +#include "SocialMgr.h" +#include "CellImpl.h" +#include "AccountMgr.h" +#include "Vehicle.h" +#include "CreatureAI.h" +#include "DBCEnums.h" +#include "ScriptMgr.h" +#include "MapManager.h" +#include "InstanceScript.h" +#include "GameObjectAI.h" +#include "Group.h" +#include "AccountMgr.h" + +void WorldSession::HandleRepopRequestOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_REPOP_REQUEST Message"); + + recv_data.read_skip(); + + if (GetPlayer()->isAlive() || GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) + return; + + if (GetPlayer()->HasAuraType(SPELL_AURA_PREVENT_RESURRECTION)) + return; // silently return, client should display the error by itself + + // the world update order is sessions, players, creatures + // the netcode runs in parallel with all of these + // creatures can kill players + // so if the server is lagging enough the player can + // release spirit after he's killed but before he is updated + if (GetPlayer()->getDeathState() == JUST_DIED) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "HandleRepopRequestOpcode: got request after player %s(%d) was killed and before he was updated", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow()); + GetPlayer()->KillPlayer(); + } + + //this is spirit release confirm? + GetPlayer()->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true); + GetPlayer()->BuildPlayerRepop(); + GetPlayer()->RepopAtGraveyard(); +} + +void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_GOSSIP_SELECT_OPTION"); + + uint32 gossipListId; + uint32 menuId; + uint64 guid; + std::string code = ""; + + recv_data >> guid >> menuId >> gossipListId; + + if (_player->PlayerTalkClass->IsGossipOptionCoded(gossipListId)) + recv_data >> code; + + Creature* unit = NULL; + GameObject* go = NULL; + if (IS_CRE_OR_VEH_GUID(guid)) + { + unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); + if (!unit) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleGossipSelectOptionOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + return; + } + } + else if (IS_GAMEOBJECT_GUID(guid)) + { + go = _player->GetMap()->GetGameObject(guid); + if (!go) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleGossipSelectOptionOpcode - GameObject (GUID: %u) not found.", uint32(GUID_LOPART(guid))); + return; + } + } + else + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleGossipSelectOptionOpcode - unsupported GUID type for highguid %u. lowpart %u.", uint32(GUID_HIPART(guid)), uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + if ((unit && unit->GetCreatureInfo()->ScriptID != unit->LastUsedScriptID) || (go && go->GetGOInfo()->ScriptId != go->LastUsedScriptID)) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleGossipSelectOptionOpcode - Script reloaded while in use, ignoring and set new scipt id"); + if (unit) + unit->LastUsedScriptID = unit->GetCreatureInfo()->ScriptID; + if (go) + go->LastUsedScriptID = go->GetGOInfo()->ScriptId; + _player->PlayerTalkClass->SendCloseGossip(); + return; + } + if (!code.empty()) + { + if (unit) + { + unit->AI()->sGossipSelectCode(_player, menuId, gossipListId, code.c_str()); + if (!sScriptMgr->OnGossipSelectCode(_player, unit, _player->PlayerTalkClass->GetGossipOptionSender(gossipListId), _player->PlayerTalkClass->GetGossipOptionAction(gossipListId), code.c_str())) + _player->OnGossipSelect(unit, gossipListId, menuId); + } + else + { + go->AI()->GossipSelectCode(_player, menuId, gossipListId, code.c_str()); + sScriptMgr->OnGossipSelectCode(_player, go, _player->PlayerTalkClass->GetGossipOptionSender(gossipListId), _player->PlayerTalkClass->GetGossipOptionAction(gossipListId), code.c_str()); + } + } + else + { + if (unit) + { + unit->AI()->sGossipSelect(_player, menuId, gossipListId); + if (!sScriptMgr->OnGossipSelect(_player, unit, _player->PlayerTalkClass->GetGossipOptionSender(gossipListId), _player->PlayerTalkClass->GetGossipOptionAction(gossipListId))) + _player->OnGossipSelect(unit, gossipListId, menuId); + } + else + { + go->AI()->GossipSelect(_player, menuId, gossipListId); + if (!sScriptMgr->OnGossipSelect(_player, go, _player->PlayerTalkClass->GetGossipOptionSender(gossipListId), _player->PlayerTalkClass->GetGossipOptionAction(gossipListId))) + _player->OnGossipSelect(go, gossipListId, menuId); + } + } +} + +void WorldSession::HandleWhoOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_WHO Message"); + + time_t now = time(NULL); + if (now - timeLastWhoCommand < 5) + return; + else timeLastWhoCommand = now; + + uint32 matchcount = 0; + + uint32 level_min, level_max, racemask, classmask, zones_count, str_count; + uint32 zoneids[10]; // 10 is client limit + std::string player_name, guild_name; + + recv_data >> level_min; // maximal player level, default 0 + recv_data >> level_max; // minimal player level, default 100 (MAX_LEVEL) + recv_data >> player_name; // player name, case sensitive... + + recv_data >> guild_name; // guild name, case sensitive... + + recv_data >> racemask; // race mask + recv_data >> classmask; // class mask + recv_data >> zones_count; // zones count, client limit = 10 (2.0.10) + + if (zones_count > 10) + return; // can't be received from real client or broken packet + + for (uint32 i = 0; i < zones_count; ++i) + { + uint32 temp; + recv_data >> temp; // zone id, 0 if zone is unknown... + zoneids[i] = temp; + sLog->outDebug(LOG_FILTER_NETWORKIO, "Zone %u: %u", i, zoneids[i]); + } + + recv_data >> str_count; // user entered strings count, client limit=4 (checked on 2.0.10) + + if (str_count > 4) + return; // can't be received from real client or broken packet + + sLog->outDebug(LOG_FILTER_NETWORKIO, "Minlvl %u, maxlvl %u, name %s, guild %s, racemask %u, classmask %u, zones %u, strings %u", level_min, level_max, player_name.c_str(), guild_name.c_str(), racemask, classmask, zones_count, str_count); + + std::wstring str[4]; // 4 is client limit + for (uint32 i = 0; i < str_count; ++i) + { + std::string temp; + recv_data >> temp; // user entered string, it used as universal search pattern(guild+player name)? + + if (!Utf8toWStr(temp, str[i])) + continue; + + wstrToLower(str[i]); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "String %u: %s", i, temp.c_str()); + } + + std::wstring wplayer_name; + std::wstring wguild_name; + if (!(Utf8toWStr(player_name, wplayer_name) && Utf8toWStr(guild_name, wguild_name))) + return; + wstrToLower(wplayer_name); + wstrToLower(wguild_name); + + // client send in case not set max level value 100 but Trinity supports 255 max level, + // update it to show GMs with characters after 100 level + if (level_max >= MAX_LEVEL) + level_max = STRONG_MAX_LEVEL; + + uint32 team = _player->GetTeam(); + uint32 security = GetSecurity(); + bool allowTwoSideWhoList = sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST); + uint32 gmLevelInWhoList = sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST); + uint32 displaycount = 0; + + WorldPacket data(SMSG_WHO, 50); // guess size + data << uint32(matchcount); // placeholder, count of players matching criteria + data << uint32(displaycount); // placeholder, count of players displayed + + TRINITY_READ_GUARD(HashMapHolder::LockType, *HashMapHolder::GetLock()); + HashMapHolder::MapType const& m = sObjectAccessor->GetPlayers(); + for (HashMapHolder::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr) + { + if (AccountMgr::IsPlayerAccount(security)) + { + // player can see member of other team only if CONFIG_ALLOW_TWO_SIDE_WHO_LIST + if (itr->second->GetTeam() != team && !allowTwoSideWhoList) + continue; + + // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST + if ((itr->second->GetSession()->GetSecurity() > AccountTypes(gmLevelInWhoList))) + continue; + } + + //do not process players which are not in world + if (!(itr->second->IsInWorld())) + continue; + + // check if target is globally visible for player + if (!(itr->second->IsVisibleGloballyFor(_player))) + continue; + + // check if target's level is in level range + uint8 lvl = itr->second->getLevel(); + if (lvl < level_min || lvl > level_max) + continue; + + // check if class matches classmask + uint32 class_ = itr->second->getClass(); + if (!(classmask & (1 << class_))) + continue; + + // check if race matches racemask + uint32 race = itr->second->getRace(); + if (!(racemask & (1 << race))) + continue; + + uint32 pzoneid = itr->second->GetZoneId(); + uint8 gender = itr->second->getGender(); + + bool z_show = true; + for (uint32 i = 0; i < zones_count; ++i) + { + if (zoneids[i] == pzoneid) + { + z_show = true; + break; + } + + z_show = false; + } + if (!z_show) + continue; + + std::string pname = itr->second->GetName(); + std::wstring wpname; + if (!Utf8toWStr(pname, wpname)) + continue; + wstrToLower(wpname); + + if (!(wplayer_name.empty() || wpname.find(wplayer_name) != std::wstring::npos)) + continue; + + std::string gname = sGuildMgr->GetGuildNameById(itr->second->GetGuildId()); + std::wstring wgname; + if (!Utf8toWStr(gname, wgname)) + continue; + wstrToLower(wgname); + + if (!(wguild_name.empty() || wgname.find(wguild_name) != std::wstring::npos)) + continue; + + std::string aname; + if (AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(itr->second->GetZoneId())) + aname = areaEntry->area_name[GetSessionDbcLocale()]; + + bool s_show = true; + for (uint32 i = 0; i < str_count; ++i) + { + if (!str[i].empty()) + { + if (wgname.find(str[i]) != std::wstring::npos || + wpname.find(str[i]) != std::wstring::npos || + Utf8FitTo(aname, str[i])) + { + s_show = true; + break; + } + s_show = false; + } + } + if (!s_show) + continue; + + // 49 is maximum player count sent to client - can be overridden + // through config, but is unstable + if ((matchcount++) >= sWorld->getIntConfig(CONFIG_MAX_WHO)) + continue; + + data << pname; // player name + data << gname; // guild name + data << uint32(lvl); // player level + data << uint32(class_); // player class + data << uint32(race); // player race + data << uint8(gender); // player gender + data << uint32(pzoneid); // player zone id + + ++displaycount; + } + + data.put(0, displaycount); // insert right count, count displayed + data.put(4, matchcount); // insert right count, count of matches + + SendPacket(&data); + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Send SMSG_WHO Message"); +} + +void WorldSession::HandleLogoutRequestOpcode(WorldPacket & /*recv_data*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_LOGOUT_REQUEST Message, security - %u", GetSecurity()); + + if (uint64 lguid = GetPlayer()->GetLootGUID()) + DoLootRelease(lguid); + + uint8 reason = 0; + + if (GetPlayer()->isInCombat()) + reason = 1; + else if (GetPlayer()->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_JUMPING | MOVEMENTFLAG_FALLING)) + reason = 3; // is jumping or falling + else if (GetPlayer()->duel || GetPlayer()->HasAura(9454)) // is dueling or frozen by GM via freeze command + reason = 2; // FIXME - Need the correct value + + if (reason) + { + WorldPacket data(SMSG_LOGOUT_RESPONSE, 1+4); + data << uint8(reason); + data << uint32(0); + SendPacket(&data); + LogoutRequest(0); + return; + } + + //instant logout in taverns/cities or on taxi or for admins, gm's, mod's if its enabled in worldserver.conf + if (GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) || GetPlayer()->isInFlight() || + GetSecurity() >= AccountTypes(sWorld->getIntConfig(CONFIG_INSTANT_LOGOUT))) + { + WorldPacket data(SMSG_LOGOUT_RESPONSE, 1+4); + data << uint8(0); + data << uint32(16777216); + SendPacket(&data); + LogoutPlayer(true); + return; + } + + // not set flags if player can't free move to prevent lost state at logout cancel + if (GetPlayer()->CanFreeMove()) + { + GetPlayer()->SetStandState(UNIT_STAND_STATE_SIT); + + WorldPacket data(SMSG_FORCE_MOVE_ROOT, (8+4)); // guess size + data.append(GetPlayer()->GetPackGUID()); + data << (uint32)2; + SendPacket(&data); + GetPlayer()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); + } + + WorldPacket data(SMSG_LOGOUT_RESPONSE, 1+4); + data << uint8(0); + data << uint32(0); + SendPacket(&data); + LogoutRequest(time(NULL)); +} + +void WorldSession::HandlePlayerLogoutOpcode(WorldPacket & /*recv_data*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_PLAYER_LOGOUT Message"); +} + +void WorldSession::HandleLogoutCancelOpcode(WorldPacket & /*recv_data*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_LOGOUT_CANCEL Message"); + + LogoutRequest(0); + + WorldPacket data(SMSG_LOGOUT_CANCEL_ACK, 0); + SendPacket(&data); + + // not remove flags if can't free move - its not set in Logout request code. + if (GetPlayer()->CanFreeMove()) + { + //!we can move again + data.Initialize(SMSG_FORCE_MOVE_UNROOT, 8); // guess size + data.append(GetPlayer()->GetPackGUID()); + data << uint32(0); + SendPacket(&data); + + //! Stand Up + GetPlayer()->SetStandState(UNIT_STAND_STATE_STAND); + + //! DISABLE_ROTATE + GetPlayer()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); + } + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_LOGOUT_CANCEL_ACK Message"); +} + +void WorldSession::HandleTogglePvP(WorldPacket & recv_data) +{ + // this opcode can be used in two ways: Either set explicit new status or toggle old status + if (recv_data.size() == 1) + { + bool newPvPStatus; + recv_data >> newPvPStatus; + GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP, newPvPStatus); + GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER, !newPvPStatus); + } + else + { + GetPlayer()->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP); + GetPlayer()->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER); + } + + if (GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP)) + { + if (!GetPlayer()->IsPvP() || GetPlayer()->pvpInfo.endTimer != 0) + GetPlayer()->UpdatePvP(true, true); + } + else + { + if (!GetPlayer()->pvpInfo.inHostileArea && GetPlayer()->IsPvP()) + GetPlayer()->pvpInfo.endTimer = time(NULL); // start toggle-off + } + + //if (OutdoorPvP* pvp = _player->GetOutdoorPvP()) + // pvp->HandlePlayerActivityChanged(_player); +} + +void WorldSession::HandleZoneUpdateOpcode(WorldPacket & recv_data) +{ + uint32 newZone; + recv_data >> newZone; + + sLog->outDetail("WORLD: Recvd ZONE_UPDATE: %u", newZone); + + // use server size data + uint32 newzone, newarea; + GetPlayer()->GetZoneAndAreaId(newzone, newarea); + GetPlayer()->UpdateZone(newzone, newarea); + //GetPlayer()->SendInitWorldStates(true, newZone); +} + +void WorldSession::HandleSetSelectionOpcode(WorldPacket & recv_data) +{ + uint64 guid; + recv_data >> guid; + + _player->SetSelection(guid); +} + +void WorldSession::HandleStandStateChangeOpcode(WorldPacket & recv_data) +{ + // sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: Received CMSG_STANDSTATECHANGE"); -- too many spam in log at lags/debug stop + uint32 animstate; + recv_data >> animstate; + + _player->SetStandState(animstate); +} + +void WorldSession::HandleContactListOpcode(WorldPacket & recv_data) +{ + uint32 unk; + recv_data >> unk; + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_CONTACT_LIST - Unk: %d", unk); + _player->GetSocial()->SendSocialList(_player); +} + +void WorldSession::HandleAddFriendOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_ADD_FRIEND"); + + std::string friendName = GetTrinityString(LANG_FRIEND_IGNORE_UNKNOWN); + std::string friendNote; + + recv_data >> friendName; + + recv_data >> friendNote; + + if (!normalizePlayerName(friendName)) + return; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: %s asked to add friend : '%s'", GetPlayer()->GetName(), friendName.c_str()); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUID_RACE_ACC_BY_NAME); + + stmt->setString(0, friendName); + + _addFriendCallback.SetParam(friendNote); + _addFriendCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); +} + +void WorldSession::HandleAddFriendOpcodeCallBack(PreparedQueryResult result, std::string friendNote) +{ + if (!GetPlayer()) + return; + + uint64 friendGuid; + uint32 friendAccountId; + uint32 team; + FriendsResult friendResult; + + friendResult = FRIEND_NOT_FOUND; + friendGuid = 0; + + if (result) + { + Field* fields = result->Fetch(); + + friendGuid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); + team = Player::TeamForRace(fields[1].GetUInt8()); + friendAccountId = fields[2].GetUInt32(); + + if (!AccountMgr::IsPlayerAccount(GetSecurity()) || sWorld->getBoolConfig(CONFIG_ALLOW_GM_FRIEND) || AccountMgr::IsPlayerAccount(AccountMgr::GetSecurity(friendAccountId, realmID))) + { + if (friendGuid) + { + if (friendGuid == GetPlayer()->GetGUID()) + friendResult = FRIEND_SELF; + else if (GetPlayer()->GetTeam() != team && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND) && AccountMgr::IsPlayerAccount(GetSecurity())) + friendResult = FRIEND_ENEMY; + else if (GetPlayer()->GetSocial()->HasFriend(GUID_LOPART(friendGuid))) + friendResult = FRIEND_ALREADY; + else + { + Player* pFriend = ObjectAccessor::FindPlayer(friendGuid); + if (pFriend && pFriend->IsInWorld() && pFriend->IsVisibleGloballyFor(GetPlayer())) + friendResult = FRIEND_ADDED_ONLINE; + else + friendResult = FRIEND_ADDED_OFFLINE; + if (!GetPlayer()->GetSocial()->AddToSocialList(GUID_LOPART(friendGuid), false)) + { + friendResult = FRIEND_LIST_FULL; + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: %s's friend list is full.", GetPlayer()->GetName()); + } + } + GetPlayer()->GetSocial()->SetFriendNote(GUID_LOPART(friendGuid), friendNote); + } + } + } + + sSocialMgr->SendFriendStatus(GetPlayer(), friendResult, GUID_LOPART(friendGuid), false); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent (SMSG_FRIEND_STATUS)"); +} + +void WorldSession::HandleDelFriendOpcode(WorldPacket & recv_data) +{ + uint64 FriendGUID; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_DEL_FRIEND"); + + recv_data >> FriendGUID; + + _player->GetSocial()->RemoveFromSocialList(GUID_LOPART(FriendGUID), false); + + sSocialMgr->SendFriendStatus(GetPlayer(), FRIEND_REMOVED, GUID_LOPART(FriendGUID), false); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent motd (SMSG_FRIEND_STATUS)"); +} + +void WorldSession::HandleAddIgnoreOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_ADD_IGNORE"); + + std::string ignoreName = GetTrinityString(LANG_FRIEND_IGNORE_UNKNOWN); + + recv_data >> ignoreName; + + if (!normalizePlayerName(ignoreName)) + return; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: %s asked to Ignore: '%s'", + GetPlayer()->GetName(), ignoreName.c_str()); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUID_BY_NAME); + + stmt->setString(0, ignoreName); + + _addIgnoreCallback = CharacterDatabase.AsyncQuery(stmt); +} + +void WorldSession::HandleAddIgnoreOpcodeCallBack(PreparedQueryResult result) +{ + if (!GetPlayer()) + return; + + uint64 IgnoreGuid; + FriendsResult ignoreResult; + + ignoreResult = FRIEND_IGNORE_NOT_FOUND; + IgnoreGuid = 0; + + if (result) + { + IgnoreGuid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER); + + if (IgnoreGuid) + { + if (IgnoreGuid == GetPlayer()->GetGUID()) //not add yourself + ignoreResult = FRIEND_IGNORE_SELF; + else if (GetPlayer()->GetSocial()->HasIgnore(GUID_LOPART(IgnoreGuid))) + ignoreResult = FRIEND_IGNORE_ALREADY; + else + { + ignoreResult = FRIEND_IGNORE_ADDED; + + // ignore list full + if (!GetPlayer()->GetSocial()->AddToSocialList(GUID_LOPART(IgnoreGuid), true)) + ignoreResult = FRIEND_IGNORE_FULL; + } + } + } + + sSocialMgr->SendFriendStatus(GetPlayer(), ignoreResult, GUID_LOPART(IgnoreGuid), false); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent (SMSG_FRIEND_STATUS)"); +} + +void WorldSession::HandleDelIgnoreOpcode(WorldPacket & recv_data) +{ + uint64 IgnoreGUID; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_DEL_IGNORE"); + + recv_data >> IgnoreGUID; + + _player->GetSocial()->RemoveFromSocialList(GUID_LOPART(IgnoreGUID), true); + + sSocialMgr->SendFriendStatus(GetPlayer(), FRIEND_IGNORE_REMOVED, GUID_LOPART(IgnoreGUID), false); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent motd (SMSG_FRIEND_STATUS)"); +} + +void WorldSession::HandleSetContactNotesOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_SET_CONTACT_NOTES"); + uint64 guid; + std::string note; + recv_data >> guid >> note; + _player->GetSocial()->SetFriendNote(GUID_LOPART(guid), note); +} + +void WorldSession::HandleBugOpcode(WorldPacket & recv_data) +{ + uint32 suggestion, contentlen, typelen; + std::string content, type; + + recv_data >> suggestion >> contentlen >> content; + + recv_data >> typelen >> type; + + if (suggestion == 0) + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_BUG [Bug Report]"); + else + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_BUG [Suggestion]"); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "%s", type.c_str()); + sLog->outDebug(LOG_FILTER_NETWORKIO, "%s", content.c_str()); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_BUG_REPORT); + + stmt->setString(0, type); + stmt->setString(1, content); + + CharacterDatabase.Execute(stmt); +} + +void WorldSession::HandleReclaimCorpseOpcode(WorldPacket &recv_data) +{ + sLog->outDetail("WORLD: Received CMSG_RECLAIM_CORPSE"); + + uint64 guid; + recv_data >> guid; + + if (GetPlayer()->isAlive()) + return; + + // do not allow corpse reclaim in arena + if (GetPlayer()->InArena()) + return; + + // body not released yet + if (!GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) + return; + + Corpse* corpse = GetPlayer()->GetCorpse(); + + if (!corpse) + return; + + // prevent resurrect before 30-sec delay after body release not finished + if (time_t(corpse->GetGhostTime() + GetPlayer()->GetCorpseReclaimDelay(corpse->GetType() == CORPSE_RESURRECTABLE_PVP)) > time_t(time(NULL))) + return; + + if (!corpse->IsWithinDistInMap(GetPlayer(), CORPSE_RECLAIM_RADIUS, true)) + return; + + // resurrect + GetPlayer()->ResurrectPlayer(GetPlayer()->InBattleground() ? 1.0f : 0.5f); + + // spawn bones + GetPlayer()->SpawnCorpseBones(); +} + +void WorldSession::HandleResurrectResponseOpcode(WorldPacket & recv_data) +{ + sLog->outDetail("WORLD: Received CMSG_RESURRECT_RESPONSE"); + + uint64 guid; + uint8 status; + recv_data >> guid; + recv_data >> status; + + if (GetPlayer()->isAlive()) + return; + + if (status == 0) + { + GetPlayer()->clearResurrectRequestData(); // reject + return; + } + + if (!GetPlayer()->isRessurectRequestedBy(guid)) + return; + + GetPlayer()->ResurectUsingRequestData(); +} + +void WorldSession::SendAreaTriggerMessage(const char* Text, ...) +{ + va_list ap; + char szStr [1024]; + szStr[0] = '\0'; + + va_start(ap, Text); + vsnprintf(szStr, 1024, Text, ap); + va_end(ap); + + uint32 length = strlen(szStr)+1; + WorldPacket data(SMSG_AREA_TRIGGER_MESSAGE, 4+length); + data << length; + data << szStr; + SendPacket(&data); +} + +void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recv_data) +{ + uint32 triggerId; + recv_data >> triggerId; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_AREATRIGGER. Trigger ID: %u", triggerId); + + Player* player = GetPlayer(); + if (player->isInFlight()) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "Player '%s' (GUID: %u) in flight, ignore Area Trigger ID:%u", + player->GetName(), player->GetGUIDLow(), triggerId); + return; + } + + AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(triggerId); + if (!atEntry) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "Player '%s' (GUID: %u) send unknown (by DBC) Area Trigger ID:%u", + player->GetName(), player->GetGUIDLow(), triggerId); + return; + } + + if (player->GetMapId() != atEntry->mapid) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "Player '%s' (GUID: %u) too far (trigger map: %u player map: %u), ignore Area Trigger ID: %u", + player->GetName(), atEntry->mapid, player->GetMapId(), player->GetGUIDLow(), triggerId); + return; + } + + // delta is safe radius + const float delta = 5.0f; + + if (atEntry->radius > 0) + { + // if we have radius check it + float dist = player->GetDistance(atEntry->x, atEntry->y, atEntry->z); + if (dist > atEntry->radius + delta) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "Player '%s' (GUID: %u) too far (radius: %f distance: %f), ignore Area Trigger ID: %u", + player->GetName(), player->GetGUIDLow(), atEntry->radius, dist, triggerId); + return; + } + } + else + { + // we have only extent + + // rotate the players position instead of rotating the whole cube, that way we can make a simplified + // is-in-cube check and we have to calculate only one point instead of 4 + + // 2PI = 360°, keep in mind that ingame orientation is counter-clockwise + double rotation = 2 * M_PI - atEntry->box_orientation; + double sinVal = sin(rotation); + double cosVal = cos(rotation); + + float playerBoxDistX = player->GetPositionX() - atEntry->x; + float playerBoxDistY = player->GetPositionY() - atEntry->y; + + float rotPlayerX = float(atEntry->x + playerBoxDistX * cosVal - playerBoxDistY*sinVal); + float rotPlayerY = float(atEntry->y + playerBoxDistY * cosVal + playerBoxDistX*sinVal); + + // box edges are parallel to coordiante axis, so we can treat every dimension independently :D + float dz = player->GetPositionZ() - atEntry->z; + float dx = rotPlayerX - atEntry->x; + float dy = rotPlayerY - atEntry->y; + if ((fabs(dx) > atEntry->box_x / 2 + delta) || + (fabs(dy) > atEntry->box_y / 2 + delta) || + (fabs(dz) > atEntry->box_z / 2 + delta)) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "Player '%s' (GUID: %u) too far (1/2 box X: %f 1/2 box Y: %f 1/2 box Z: %f rotatedPlayerX: %f rotatedPlayerY: %f dZ:%f), ignore Area Trigger ID: %u", + player->GetName(), player->GetGUIDLow(), atEntry->box_x/2, atEntry->box_y/2, atEntry->box_z/2, rotPlayerX, rotPlayerY, dz, triggerId); + return; + } + } + + if (player->isDebugAreaTriggers) + ChatHandler(player).PSendSysMessage(LANG_DEBUG_AREATRIGGER_REACHED, triggerId); + + if (sScriptMgr->OnAreaTrigger(player, atEntry)) + return; + + if (player->isAlive()) + if (uint32 questId = sObjectMgr->GetQuestForAreaTrigger(triggerId)) + if (player->GetQuestStatus(questId) == QUEST_STATUS_INCOMPLETE) + player->AreaExploredOrEventHappens(questId); + + if (sObjectMgr->IsTavernAreaTrigger(triggerId)) + { + // set resting flag we are in the inn + player->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); + player->InnEnter(time(NULL), atEntry->mapid, atEntry->x, atEntry->y, atEntry->z); + player->SetRestType(REST_TYPE_IN_TAVERN); + + if (sWorld->IsFFAPvPRealm()) + player->RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); + + return; + } + + if (Battleground* bg = player->GetBattleground()) + if (bg->GetStatus() == STATUS_IN_PROGRESS) + { + bg->HandleAreaTrigger(player, triggerId); + return; + } + + if (OutdoorPvP* pvp = player->GetOutdoorPvP()) + if (pvp->HandleAreaTrigger(_player, triggerId)) + return; + + AreaTrigger const* at = sObjectMgr->GetAreaTrigger(triggerId); + if (!at) + return; + + bool teleported = false; + if (player->GetMapId() != at->target_mapId) + { + if (!sMapMgr->CanPlayerEnter(at->target_mapId, player, false)) + return; + + if (Group* group = player->GetGroup()) + if (group->isLFGGroup() && player->GetMap()->IsDungeon()) + teleported = player->TeleportToBGEntryPoint(); + } + + if (!teleported) + player->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, at->target_Orientation, TELE_TO_NOT_LEAVE_TRANSPORT); +} + +void WorldSession::HandleUpdateAccountData(WorldPacket &recv_data) +{ + sLog->outDetail("WORLD: Received CMSG_UPDATE_ACCOUNT_DATA"); + + uint32 type, timestamp, decompressedSize; + recv_data >> type >> timestamp >> decompressedSize; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "UAD: type %u, time %u, decompressedSize %u", type, timestamp, decompressedSize); + + if (type > NUM_ACCOUNT_DATA_TYPES) + return; + + if (decompressedSize == 0) // erase + { + SetAccountData(AccountDataType(type), 0, ""); + + WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA_COMPLETE, 4+4); + data << uint32(type); + data << uint32(0); + SendPacket(&data); + + return; + } + + if (decompressedSize > 0xFFFF) + { + recv_data.rfinish(); // unnneded warning spam in this case + sLog->outError("UAD: Account data packet too big, size %u", decompressedSize); + return; + } + + ByteBuffer dest; + dest.resize(decompressedSize); + + uLongf realSize = decompressedSize; + if (uncompress(const_cast(dest.contents()), &realSize, const_cast(recv_data.contents() + recv_data.rpos()), recv_data.size() - recv_data.rpos()) != Z_OK) + { + recv_data.rfinish(); // unnneded warning spam in this case + sLog->outError("UAD: Failed to decompress account data"); + return; + } + + recv_data.rfinish(); // uncompress read (recv_data.size() - recv_data.rpos()) + + std::string adata; + dest >> adata; + + SetAccountData(AccountDataType(type), timestamp, adata); + + WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA_COMPLETE, 4+4); + data << uint32(type); + data << uint32(0); + SendPacket(&data); +} + +void WorldSession::HandleRequestAccountData(WorldPacket& recv_data) +{ + sLog->outDetail("WORLD: Received CMSG_REQUEST_ACCOUNT_DATA"); + + uint32 type; + recv_data >> type; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "RAD: type %u", type); + + if (type > NUM_ACCOUNT_DATA_TYPES) + return; + + AccountData* adata = GetAccountData(AccountDataType(type)); + + uint32 size = adata->Data.size(); + + uLongf destSize = compressBound(size); + + ByteBuffer dest; + dest.resize(destSize); + + if (size && compress(const_cast(dest.contents()), &destSize, (uint8*)adata->Data.c_str(), size) != Z_OK) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "RAD: Failed to compress account data"); + return; + } + + dest.resize(destSize); + + WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA, 8+4+4+4+destSize); + data << uint64(_player ? _player->GetGUID() : 0); // player guid + data << uint32(type); // type (0-7) + data << uint32(adata->Time); // unix time + data << uint32(size); // decompressed length + data.append(dest); // compressed data + SendPacket(&data); +} + +void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_SET_ACTION_BUTTON"); + uint8 button; + uint32 packetData; + recv_data >> button >> packetData; + + uint32 action = ACTION_BUTTON_ACTION(packetData); + uint8 type = ACTION_BUTTON_TYPE(packetData); + + sLog->outDetail("BUTTON: %u ACTION: %u TYPE: %u", button, action, type); + if (!packetData) + { + sLog->outDetail("MISC: Remove action from button %u", button); + GetPlayer()->removeActionButton(button); + } + else + { + switch (type) + { + case ACTION_BUTTON_MACRO: + case ACTION_BUTTON_CMACRO: + sLog->outDetail("MISC: Added Macro %u into button %u", action, button); + break; + case ACTION_BUTTON_EQSET: + sLog->outDetail("MISC: Added EquipmentSet %u into button %u", action, button); + break; + case ACTION_BUTTON_SPELL: + sLog->outDetail("MISC: Added Spell %u into button %u", action, button); + break; + case ACTION_BUTTON_ITEM: + sLog->outDetail("MISC: Added Item %u into button %u", action, button); + break; + default: + sLog->outError("MISC: Unknown action button type %u for action %u into button %u", type, action, button); + return; + } + GetPlayer()->addActionButton(button, action, type); + } +} + +void WorldSession::HandleCompleteCinematic(WorldPacket & /*recv_data*/) +{ + sLog->outStaticDebug("WORLD: Player is watching cinema"); +} + +void WorldSession::HandleNextCinematicCamera(WorldPacket & /*recv_data*/) +{ + sLog->outStaticDebug("WORLD: Which movie to play"); +} + +void WorldSession::HandleMoveTimeSkippedOpcode(WorldPacket & recv_data) +{ + /* WorldSession::Update(getMSTime());*/ + sLog->outStaticDebug("WORLD: Time Lag/Synchronization Resent/Update"); + + uint64 guid; + recv_data.readPackGUID(guid); + recv_data.read_skip(); + /* + uint64 guid; + uint32 time_skipped; + recv_data >> guid; + recv_data >> time_skipped; + sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_MOVE_TIME_SKIPPED"); + + /// TODO + must be need use in Trinity + We substract server Lags to move time (AntiLags) + for exmaple + GetPlayer()->ModifyLastMoveTime(-int32(time_skipped)); + */ +} + +void WorldSession::HandleFeatherFallAck(WorldPacket &recv_data) +{ + sLog->outStaticDebug("WORLD: CMSG_MOVE_FEATHER_FALL_ACK"); + + // no used + recv_data.rfinish(); // prevent warnings spam +} + +void WorldSession::HandleMoveUnRootAck(WorldPacket& recv_data) +{ + // no used + recv_data.rfinish(); // prevent warnings spam +/* + uint64 guid; + recv_data >> guid; + + // now can skip not our packet + if (_player->GetGUID() != guid) + { + recv_data.rfinish(); // prevent warnings spam + return; + } + + sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_FORCE_MOVE_UNROOT_ACK"); + + recv_data.read_skip(); // unk + + MovementInfo movementInfo; + movementInfo.guid = guid; + ReadMovementInfo(recv_data, &movementInfo); + recv_data.read_skip(); // unk2 +*/ +} + +void WorldSession::HandleMoveRootAck(WorldPacket& recv_data) +{ + // no used + recv_data.rfinish(); // prevent warnings spam +/* + uint64 guid; + recv_data >> guid; + + // now can skip not our packet + if (_player->GetGUID() != guid) + { + recv_data.rfinish(); // prevent warnings spam + return; + } + + sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_FORCE_MOVE_ROOT_ACK"); + + recv_data.read_skip(); // unk + + MovementInfo movementInfo; + ReadMovementInfo(recv_data, &movementInfo); +*/ +} + +void WorldSession::HandleSetActionBarToggles(WorldPacket& recv_data) +{ + uint8 ActionBar; + + recv_data >> ActionBar; + + if (!GetPlayer()) // ignore until not logged (check needed because STATUS_AUTHED) + { + if (ActionBar != 0) + sLog->outError("WorldSession::HandleSetActionBarToggles in not logged state with value: %u, ignored", uint32(ActionBar)); + return; + } + + GetPlayer()->SetByteValue(PLAYER_FIELD_BYTES, 2, ActionBar); +} + +void WorldSession::HandleWardenDataOpcode(WorldPacket& recv_data) +{ + recv_data.read_skip(); + /* + uint8 tmp; + recv_data >> tmp; + sLog->outDebug("Received opcode CMSG_WARDEN_DATA, not resolve.uint8 = %u", tmp); + */ +} + +void WorldSession::HandlePlayedTime(WorldPacket& recv_data) +{ + uint8 unk1; + recv_data >> unk1; // 0 or 1 expected + + WorldPacket data(SMSG_PLAYED_TIME, 4 + 4 + 1); + data << uint32(_player->GetTotalPlayedTime()); + data << uint32(_player->GetLevelPlayedTime()); + data << uint8(unk1); // 0 - will not show in chat frame + SendPacket(&data); +} + +void WorldSession::HandleInspectOpcode(WorldPacket& recv_data) +{ + uint64 guid; + recv_data >> guid; + sLog->outStaticDebug("Inspected guid is " UI64FMTD, guid); + + _player->SetSelection(guid); + + Player* player = ObjectAccessor::FindPlayer(guid); + if (!player) // wrong player + return; + + uint32 talent_points = 0x47; + uint32 guid_size = player->GetPackGUID().wpos(); + WorldPacket data(SMSG_INSPECT_TALENT, guid_size+4+talent_points); + data.append(player->GetPackGUID()); + + if (sWorld->getBoolConfig(CONFIG_TALENTS_INSPECTING) || _player->isGameMaster()) + { + player->BuildPlayerTalentsInfoData(&data); + } + else + { + data << uint32(0); // unspentTalentPoints + data << uint8(0); // talentGroupCount + data << uint8(0); // talentGroupIndex + } + + player->BuildEnchantmentsInfoData(&data); + SendPacket(&data); +} + +void WorldSession::HandleInspectHonorStatsOpcode(WorldPacket& recv_data) +{ + uint64 guid; + recv_data >> guid; + + Player* player = ObjectAccessor::FindPlayer(guid); + + if (!player) + { + sLog->outError("InspectHonorStats: WTF, player not found..."); + return; + } + + WorldPacket data(MSG_INSPECT_HONOR_STATS, 8+1+4*4); + data << uint64(player->GetGUID()); + data << uint8(player->GetHonorPoints()); + data << uint32(player->GetUInt32Value(PLAYER_FIELD_KILLS)); + data << uint32(player->GetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION)); + data << uint32(player->GetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION)); + data << uint32(player->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS)); + SendPacket(&data); +} + +void WorldSession::HandleWorldTeleportOpcode(WorldPacket& recv_data) +{ + // write in client console: worldport 469 452 6454 2536 180 or /console worldport 469 452 6454 2536 180 + // Received opcode CMSG_WORLD_TELEPORT + // Time is ***, map=469, x=452.000000, y=6454.000000, z=2536.000000, orient=3.141593 + + uint32 time; + uint32 mapid; + float PositionX; + float PositionY; + float PositionZ; + float Orientation; + + recv_data >> time; // time in m.sec. + recv_data >> mapid; + recv_data >> PositionX; + recv_data >> PositionY; + recv_data >> PositionZ; + recv_data >> Orientation; // o (3.141593 = 180 degrees) + + //sLog->outDebug("Received opcode CMSG_WORLD_TELEPORT"); + if (GetPlayer()->isInFlight()) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "Player '%s' (GUID: %u) in flight, ignore worldport command.", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow()); + return; + } + + sLog->outStaticDebug("Time %u sec, map=%u, x=%f, y=%f, z=%f, orient=%f", time/1000, mapid, PositionX, PositionY, PositionZ, Orientation); + + if (AccountMgr::IsAdminAccount(GetSecurity())) + GetPlayer()->TeleportTo(mapid, PositionX, PositionY, PositionZ, Orientation); + else + SendNotification(LANG_YOU_NOT_HAVE_PERMISSION); + sLog->outDebug(LOG_FILTER_NETWORKIO, "Received worldport command from player %s", GetPlayer()->GetName()); +} + +void WorldSession::HandleWhoisOpcode(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode CMSG_WHOIS"); + std::string charname; + recv_data >> charname; + + if (!AccountMgr::IsAdminAccount(GetSecurity())) + { + SendNotification(LANG_YOU_NOT_HAVE_PERMISSION); + return; + } + + if (charname.empty() || !normalizePlayerName (charname)) + { + SendNotification(LANG_NEED_CHARACTER_NAME); + return; + } + + Player* player = sObjectAccessor->FindPlayerByName(charname.c_str()); + + if (!player) + { + SendNotification(LANG_PLAYER_NOT_EXIST_OR_OFFLINE, charname.c_str()); + return; + } + + uint32 accid = player->GetSession()->GetAccountId(); + + QueryResult result = LoginDatabase.PQuery("SELECT username, email, last_ip FROM account WHERE id=%u", accid); + if (!result) + { + SendNotification(LANG_ACCOUNT_FOR_PLAYER_NOT_FOUND, charname.c_str()); + return; + } + + Field* fields = result->Fetch(); + std::string acc = fields[0].GetString(); + if (acc.empty()) + acc = "Unknown"; + std::string email = fields[1].GetString(); + if (email.empty()) + email = "Unknown"; + std::string lastip = fields[2].GetString(); + if (lastip.empty()) + lastip = "Unknown"; + + std::string msg = charname + "'s " + "account is " + acc + ", e-mail: " + email + ", last ip: " + lastip; + + WorldPacket data(SMSG_WHOIS, msg.size()+1); + data << msg; + _player->GetSession()->SendPacket(&data); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "Received whois command from player %s for character %s", GetPlayer()->GetName(), charname.c_str()); +} + +void WorldSession::HandleComplainOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_COMPLAIN"); + + uint8 spam_type; // 0 - mail, 1 - chat + uint64 spammer_guid; + uint32 unk1 = 0; + uint32 unk2 = 0; + uint32 unk3 = 0; + uint32 unk4 = 0; + std::string description = ""; + recv_data >> spam_type; // unk 0x01 const, may be spam type (mail/chat) + recv_data >> spammer_guid; // player guid + switch (spam_type) + { + case 0: + recv_data >> unk1; // const 0 + recv_data >> unk2; // probably mail id + recv_data >> unk3; // const 0 + break; + case 1: + recv_data >> unk1; // probably language + recv_data >> unk2; // message type? + recv_data >> unk3; // probably channel id + recv_data >> unk4; // unk random value + recv_data >> description; // spam description string (messagetype, channel name, player name, message) + break; + } + + // NOTE: all chat messages from this spammer automatically ignored by spam reporter until logout in case chat spam. + // if it's mail spam - ALL mails from this spammer automatically removed by client + + // Complaint Received message + WorldPacket data(SMSG_COMPLAIN_RESULT, 1); + data << uint8(0); + SendPacket(&data); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "REPORT SPAM: type %u, guid %u, unk1 %u, unk2 %u, unk3 %u, unk4 %u, message %s", spam_type, GUID_LOPART(spammer_guid), unk1, unk2, unk3, unk4, description.c_str()); +} + +void WorldSession::HandleRealmSplitOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_REALM_SPLIT"); + + uint32 unk; + std::string split_date = "01/01/01"; + recv_data >> unk; + + WorldPacket data(SMSG_REALM_SPLIT, 4+4+split_date.size()+1); + data << unk; + data << uint32(0x00000000); // realm split state + // split states: + // 0x0 realm normal + // 0x1 realm split + // 0x2 realm split pending + data << split_date; + SendPacket(&data); + //sLog->outDebug("response sent %u", unk); +} + +void WorldSession::HandleFarSightOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_FAR_SIGHT"); + + uint8 apply; + recv_data >> apply; + + switch (apply) + { + case 0: + sLog->outDebug(LOG_FILTER_NETWORKIO, "Player %u set vision to self", _player->GetGUIDLow()); + _player->SetSeer(_player); + break; + case 1: + sLog->outDebug(LOG_FILTER_NETWORKIO, "Added FarSight " UI64FMTD " to player %u", _player->GetUInt64Value(PLAYER_FARSIGHT), _player->GetGUIDLow()); + if (WorldObject* target = _player->GetViewpoint()) + _player->SetSeer(target); + else + sLog->outError("Player %s requests non-existing seer " UI64FMTD, _player->GetName(), _player->GetUInt64Value(PLAYER_FARSIGHT)); + break; + default: + sLog->outDebug(LOG_FILTER_NETWORKIO, "Unhandled mode in CMSG_FAR_SIGHT: %u", apply); + return; + } + + GetPlayer()->UpdateVisibilityForPlayer(); +} + +void WorldSession::HandleSetTitleOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_SET_TITLE"); + + int32 title; + recv_data >> title; + + // -1 at none + if (title > 0 && title < MAX_TITLE_INDEX) + { + if (!GetPlayer()->HasTitle(title)) + return; + } + else + title = 0; + + GetPlayer()->SetUInt32Value(PLAYER_CHOSEN_TITLE, title); +} + +void WorldSession::HandleTimeSyncResp(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_TIME_SYNC_RESP"); + + uint32 counter, clientTicks; + recv_data >> counter >> clientTicks; + + if (counter != _player->m_timeSyncCounter - 1) + sLog->outDebug(LOG_FILTER_NETWORKIO, "Wrong time sync counter from player %s (cheater?)", _player->GetName()); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "Time sync received: counter %u, client ticks %u, time since last sync %u", counter, clientTicks, clientTicks - _player->m_timeSyncClient); + + uint32 ourTicks = clientTicks + (getMSTime() - _player->m_timeSyncServer); + + // diff should be small + sLog->outDebug(LOG_FILTER_NETWORKIO, "Our ticks: %u, diff %u, latency %u", ourTicks, ourTicks - clientTicks, GetLatency()); + + _player->m_timeSyncClient = clientTicks; +} + +void WorldSession::HandleResetInstancesOpcode(WorldPacket & /*recv_data*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_RESET_INSTANCES"); + Group* group = _player->GetGroup(); + if (group) + { + if (group->IsLeader(_player->GetGUID())) + { + group->ResetInstances(INSTANCE_RESET_ALL, false, _player); + group->ResetInstances(INSTANCE_RESET_ALL, true, _player); + } + } + else + { + _player->ResetInstances(INSTANCE_RESET_ALL, false); + _player->ResetInstances(INSTANCE_RESET_ALL, true); + } +} + +void WorldSession::HandleSetDungeonDifficultyOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "MSG_SET_DUNGEON_DIFFICULTY"); + + uint32 mode; + recv_data >> mode; + + if (mode >= MAX_DUNGEON_DIFFICULTY) + { + sLog->outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode); + return; + } + + if (Difficulty(mode) == _player->GetDungeonDifficulty()) + return; + + // cannot reset while in an instance + Map* map = _player->GetMap(); + if (map && map->IsDungeon()) + { + sLog->outError("WorldSession::HandleSetDungeonDifficultyOpcode: player (Name: %s, GUID: %u) tried to reset the instance while player is inside!", _player->GetName(), _player->GetGUIDLow()); + return; + } + + Group* group = _player->GetGroup(); + if (group) + { + if (group->IsLeader(_player->GetGUID())) + { + for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* pGroupGuy = itr->getSource(); + if (!pGroupGuy) + continue; + + if (!pGroupGuy->IsInMap(pGroupGuy)) + return; + + map = pGroupGuy->GetMap(); + if (map && map->IsNonRaidDungeon()) + { + sLog->outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d tried to reset the instance while group member (Name: %s, GUID: %u) is inside!", _player->GetGUIDLow(), pGroupGuy->GetName(), pGroupGuy->GetGUIDLow()); + return; + } + } + // the difficulty is set even if the instances can't be reset + //_player->SendDungeonDifficulty(true); + group->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, false, _player); + group->SetDungeonDifficulty(Difficulty(mode)); + } + } + else + { + _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, false); + _player->SetDungeonDifficulty(Difficulty(mode)); + } +} + +void WorldSession::HandleSetRaidDifficultyOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "MSG_SET_RAID_DIFFICULTY"); + + uint32 mode; + recv_data >> mode; + + if (mode >= MAX_RAID_DIFFICULTY) + { + sLog->outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode); + return; + } + + // cannot reset while in an instance + Map* map = _player->GetMap(); + if (map && map->IsDungeon()) + { + sLog->outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow()); + return; + } + + if (Difficulty(mode) == _player->GetRaidDifficulty()) + return; + + Group* group = _player->GetGroup(); + if (group) + { + if (group->IsLeader(_player->GetGUID())) + { + for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* pGroupGuy = itr->getSource(); + if (!pGroupGuy) + continue; + + if (!pGroupGuy->IsInMap(pGroupGuy)) + return; + + map = pGroupGuy->GetMap(); + if (map && map->IsRaid()) + { + sLog->outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow()); + return; + } + } + // the difficulty is set even if the instances can't be reset + //_player->SendDungeonDifficulty(true); + group->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true, _player); + group->SetRaidDifficulty(Difficulty(mode)); + } + } + else + { + _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true); + _player->SetRaidDifficulty(Difficulty(mode)); + } +} + +void WorldSession::HandleCancelMountAuraOpcode(WorldPacket & /*recv_data*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CANCEL_MOUNT_AURA"); + + //If player is not mounted, so go out :) + if (!_player->IsMounted()) // not blizz like; no any messages on blizz + { + ChatHandler(this).SendSysMessage(LANG_CHAR_NON_MOUNTED); + return; + } + + if (_player->isInFlight()) // not blizz like; no any messages on blizz + { + ChatHandler(this).SendSysMessage(LANG_YOU_IN_FLIGHT); + return; + } + + _player->Dismount(); + _player->RemoveAurasByType(SPELL_AURA_MOUNTED); +} + +void WorldSession::HandleMoveSetCanFlyAckOpcode(WorldPacket & recv_data) +{ + // fly mode on/off + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_MOVE_SET_CAN_FLY_ACK"); + + uint64 guid; // guid - unused + recv_data.readPackGUID(guid); + + recv_data.read_skip(); // unk + + MovementInfo movementInfo; + movementInfo.guid = guid; + ReadMovementInfo(recv_data, &movementInfo); + + recv_data.read_skip(); // unk2 + + _player->m_mover->m_movementInfo.flags = movementInfo.GetMovementFlags(); +} + +void WorldSession::HandleRequestPetInfoOpcode(WorldPacket & /*recv_data */) +{ + /* + sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_REQUEST_PET_INFO"); + recv_data.hexlike(); + */ +} + +void WorldSession::HandleSetTaxiBenchmarkOpcode(WorldPacket & recv_data) +{ + uint8 mode; + recv_data >> mode; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "Client used \"/timetest %d\" command", mode); +} + +void WorldSession::HandleQueryInspectAchievements(WorldPacket & recv_data) +{ + uint64 guid; + recv_data.readPackGUID(guid); + + Player* player = ObjectAccessor::FindPlayer(guid); + if (!player) + return; + + player->GetAchievementMgr().SendRespondInspectAchievements(_player); +} + +void WorldSession::HandleWorldStateUITimerUpdate(WorldPacket& /*recv_data*/) +{ + // empty opcode + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_WORLD_STATE_UI_TIMER_UPDATE"); + + WorldPacket data(SMSG_WORLD_STATE_UI_TIMER_UPDATE, 4); + data << uint32(time(NULL)); + SendPacket(&data); +} + +void WorldSession::HandleReadyForAccountDataTimes(WorldPacket& /*recv_data*/) +{ + // empty opcode + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_READY_FOR_ACCOUNT_DATA_TIMES"); + + SendAccountDataTimes(GLOBAL_CACHE_MASK); +} + +void WorldSession::SendSetPhaseShift(uint32 PhaseShift) +{ + WorldPacket data(SMSG_SET_PHASE_SHIFT, 4); + data << uint32(PhaseShift); + SendPacket(&data); +} + +void WorldSession::HandleHearthAndResurrect(WorldPacket& /*recv_data*/) +{ + if (_player->isInFlight()) + return; + + AreaTableEntry const* atEntry = GetAreaEntryByAreaID(_player->GetAreaId()); + if (!atEntry || !(atEntry->flags & AREA_FLAG_WINTERGRASP_2)) + return; + + _player->BuildPlayerRepop(); + _player->ResurrectPlayer(100); + _player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->GetOrientation()); +} + +void WorldSession::HandleInstanceLockResponse(WorldPacket& recvPacket) +{ + uint8 accept; + recvPacket >> accept; + + if (!_player->HasPendingBind()) + { + sLog->outDetail("InstanceLockResponse: Player %s (guid %u) tried to bind himself/teleport to graveyard without a pending bind!", _player->GetName(), _player->GetGUIDLow()); + return; + } + + if (accept) + _player->BindToInstance(); + else + _player->RepopAtGraveyard(); + + _player->SetPendingBind(0, 0); +} diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp new file mode 100755 index 00000000000..7d1233c8f70 --- /dev/null +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -0,0 +1,573 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Opcodes.h" +#include "Log.h" +#include "Corpse.h" +#include "Player.h" +#include "SpellAuras.h" +#include "MapManager.h" +#include "Transport.h" +#include "Battleground.h" +#include "WaypointMovementGenerator.h" +#include "InstanceSaveMgr.h" +#include "ObjectMgr.h" + +void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket & /*recv_data*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: got MSG_MOVE_WORLDPORT_ACK."); + HandleMoveWorldportAckOpcode(); +} + +void WorldSession::HandleMoveWorldportAckOpcode() +{ + // ignore unexpected far teleports + if (!GetPlayer()->IsBeingTeleportedFar()) + return; + + GetPlayer()->SetSemaphoreTeleportFar(false); + + // get the teleport destination + WorldLocation &loc = GetPlayer()->GetTeleportDest(); + + // possible errors in the coordinate validity check + if (!MapManager::IsValidMapCoord(loc)) + { + LogoutPlayer(false); + return; + } + + // get the destination map entry, not the current one, this will fix homebind and reset greeting + MapEntry const* mEntry = sMapStore.LookupEntry(loc.GetMapId()); + InstanceTemplate const* mInstance = sObjectMgr->GetInstanceTemplate(loc.GetMapId()); + + // reset instance validity, except if going to an instance inside an instance + if (GetPlayer()->m_InstanceValid == false && !mInstance) + GetPlayer()->m_InstanceValid = true; + + Map* oldMap = GetPlayer()->GetMap(); + ASSERT(oldMap); + if (GetPlayer()->IsInWorld()) + { + sLog->outCrash("Player (Name %s) is still in world when teleported from map %u to new map %u", GetPlayer()->GetName(), oldMap->GetId(), loc.GetMapId()); + oldMap->RemovePlayerFromMap(GetPlayer(), false); + } + + // relocate the player to the teleport destination + Map* newMap = sMapMgr->CreateMap(loc.GetMapId(), GetPlayer()); + // the CanEnter checks are done in TeleporTo but conditions may change + // while the player is in transit, for example the map may get full + if (!newMap || !newMap->CanEnter(GetPlayer())) + { + sLog->outError("Map %d could not be created for player %d, porting player to homebind", loc.GetMapId(), GetPlayer()->GetGUIDLow()); + GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation()); + return; + } + else + GetPlayer()->Relocate(&loc); + + GetPlayer()->ResetMap(); + GetPlayer()->SetMap(newMap); + + GetPlayer()->SendInitialPacketsBeforeAddToMap(); + if (!GetPlayer()->GetMap()->AddPlayerToMap(GetPlayer())) + { + sLog->outError("WORLD: failed to teleport player %s (%d) to map %d because of unknown reason!", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), loc.GetMapId()); + GetPlayer()->ResetMap(); + GetPlayer()->SetMap(oldMap); + GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation()); + return; + } + + // battleground state prepare (in case join to BG), at relogin/tele player not invited + // only add to bg group and object, if the player was invited (else he entered through command) + if (_player->InBattleground()) + { + // cleanup setting if outdated + if (!mEntry->IsBattlegroundOrArena()) + { + // We're not in BG + _player->SetBattlegroundId(0, BATTLEGROUND_TYPE_NONE); + // reset destination bg team + _player->SetBGTeam(0); + } + // join to bg case + else if (Battleground* bg = _player->GetBattleground()) + { + if (_player->IsInvitedForBattlegroundInstance(_player->GetBattlegroundId())) + bg->AddPlayer(_player); + } + } + + GetPlayer()->SendInitialPacketsAfterAddToMap(); + + // flight fast teleport case + if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) + { + if (!_player->InBattleground()) + { + // short preparations to continue flight + FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top()); + flight->Initialize(*GetPlayer()); + return; + } + + // battleground state prepare, stop flight + GetPlayer()->GetMotionMaster()->MovementExpired(); + GetPlayer()->CleanupAfterTaxiFlight(); + } + + // resurrect character at enter into instance where his corpse exist after add to map + Corpse* corpse = GetPlayer()->GetCorpse(); + if (corpse && corpse->GetType() != CORPSE_BONES && corpse->GetMapId() == GetPlayer()->GetMapId()) + { + if (mEntry->IsDungeon()) + { + GetPlayer()->ResurrectPlayer(0.5f, false); + GetPlayer()->SpawnCorpseBones(); + } + } + + bool allowMount = !mEntry->IsDungeon() || mEntry->IsBattlegroundOrArena(); + if (mInstance) + { + Difficulty diff = GetPlayer()->GetDifficulty(mEntry->IsRaid()); + if (MapDifficulty const* mapDiff = GetMapDifficultyData(mEntry->MapID, diff)) + { + if (mapDiff->resetTime) + { + if (time_t timeReset = sInstanceSaveMgr->GetResetTimeFor(mEntry->MapID, diff)) + { + uint32 timeleft = uint32(timeReset - time(NULL)); + GetPlayer()->SendInstanceResetWarning(mEntry->MapID, diff, timeleft); + } + } + } + allowMount = mInstance->AllowMount; + } + + // mount allow check + if (!allowMount) + _player->RemoveAurasByType(SPELL_AURA_MOUNTED); + + // update zone immediately, otherwise leave channel will cause crash in mtmap + uint32 newzone, newarea; + GetPlayer()->GetZoneAndAreaId(newzone, newarea); + GetPlayer()->UpdateZone(newzone, newarea); + + // honorless target + if (GetPlayer()->pvpInfo.inHostileArea) + GetPlayer()->CastSpell(GetPlayer(), 2479, true); + + // in friendly area + else if (GetPlayer()->IsPvP() && !GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP)) + GetPlayer()->UpdatePvP(false, false); + + // resummon pet + GetPlayer()->ResummonPetTemporaryUnSummonedIfAny(); + + //lets process all delayed operations on successful teleport + GetPlayer()->ProcessDelayedOperations(); +} + +void WorldSession::HandleMoveTeleportAck(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "MSG_MOVE_TELEPORT_ACK"); + uint64 guid; + + recv_data.readPackGUID(guid); + + uint32 flags, time; + recv_data >> flags >> time; + sLog->outStaticDebug("Guid " UI64FMTD, guid); + sLog->outStaticDebug("Flags %u, time %u", flags, time/IN_MILLISECONDS); + + Unit* mover = _player->m_mover; + Player* plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; + + if (!plMover || !plMover->IsBeingTeleportedNear()) + return; + + if (guid != plMover->GetGUID()) + return; + + plMover->SetSemaphoreTeleportNear(false); + + uint32 old_zone = plMover->GetZoneId(); + + WorldLocation const& dest = plMover->GetTeleportDest(); + + plMover->UpdatePosition(dest, true); + + uint32 newzone, newarea; + plMover->GetZoneAndAreaId(newzone, newarea); + plMover->UpdateZone(newzone, newarea); + + // new zone + if (old_zone != newzone) + { + // honorless target + if (plMover->pvpInfo.inHostileArea) + plMover->CastSpell(plMover, 2479, true); + + // in friendly area + else if (plMover->IsPvP() && !plMover->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP)) + plMover->UpdatePvP(false, false); + } + + // resummon pet + GetPlayer()->ResummonPetTemporaryUnSummonedIfAny(); + + //lets process all delayed operations on successful teleport + GetPlayer()->ProcessDelayedOperations(); +} + +void WorldSession::HandleMovementOpcodes(WorldPacket & recv_data) +{ + uint16 opcode = recv_data.GetOpcode(); + + Unit* mover = _player->m_mover; + + ASSERT(mover != NULL); // there must always be a mover + + Player* plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; + + // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck + if (plMover && plMover->IsBeingTeleported()) + { + recv_data.rfinish(); // prevent warnings spam + return; + } + + /* extract packet */ + uint64 guid; + + recv_data.readPackGUID(guid); + + MovementInfo movementInfo; + movementInfo.guid = guid; + ReadMovementInfo(recv_data, &movementInfo); + + recv_data.rfinish(); // prevent warnings spam + + // prevent tampered movement data + if (guid != mover->GetGUID()) + return; + + if (!movementInfo.pos.IsPositionValid()) + { + recv_data.rfinish(); // prevent warnings spam + return; + } + + /* handle special cases */ + if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) + { + // transports size limited + // (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) + if (movementInfo.t_pos.GetPositionX() > 50 || movementInfo.t_pos.GetPositionY() > 50 || movementInfo.t_pos.GetPositionZ() > 50) + { + recv_data.rfinish(); // prevent warnings spam + return; + } + + if (!Trinity::IsValidMapCoord(movementInfo.pos.GetPositionX() + movementInfo.t_pos.GetPositionX(), movementInfo.pos.GetPositionY() + movementInfo.t_pos.GetPositionY(), + movementInfo.pos.GetPositionZ() + movementInfo.t_pos.GetPositionZ(), movementInfo.pos.GetOrientation() + movementInfo.t_pos.GetOrientation())) + { + recv_data.rfinish(); // prevent warnings spam + return; + } + + // if we boarded a transport, add us to it + if (plMover && !plMover->GetTransport()) + { + // elevators also cause the client to send MOVEMENTFLAG_ONTRANSPORT - just dismount if the guid can be found in the transport list + for (MapManager::TransportSet::const_iterator iter = sMapMgr->m_Transports.begin(); iter != sMapMgr->m_Transports.end(); ++iter) + { + if ((*iter)->GetGUID() == movementInfo.t_guid) + { + plMover->m_transport = (*iter); + (*iter)->AddPassenger(plMover); + break; + } + } + } + + if (!mover->GetTransport() && !mover->GetVehicle()) + { + GameObject* go = mover->GetMap()->GetGameObject(movementInfo.t_guid); + if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT) + movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; + } + } + else if (plMover && plMover->GetTransport()) // if we were on a transport, leave + { + plMover->m_transport->RemovePassenger(plMover); + plMover->m_transport = NULL; + movementInfo.t_pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f); + movementInfo.t_time = 0; + movementInfo.t_seat = -1; + } + + // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map). + if (opcode == MSG_MOVE_FALL_LAND && plMover && !plMover->isInFlight()) + plMover->HandleFall(movementInfo); + + if (plMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plMover->IsInWater()) + { + // now client not include swimming flag in case jumping under water + plMover->SetInWater(!plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ())); + } + + /*----------------------*/ + + /* process position-change */ + WorldPacket data(opcode, recv_data.size()); + movementInfo.time = getMSTime(); + movementInfo.guid = mover->GetGUID(); + WriteMovementInfo(&data, &movementInfo); + mover->SendMessageToSet(&data, _player); + + mover->m_movementInfo = movementInfo; + + // this is almost never true (not sure why it is sometimes, but it is), normally use mover->IsVehicle() + if (mover->GetVehicle()) + { + mover->SetOrientation(movementInfo.pos.GetOrientation()); + return; + } + + mover->UpdatePosition(movementInfo.pos); + + if (plMover) // nothing is charmed, or player charmed + { + plMover->UpdateFallInformationIfNeed(movementInfo, opcode); + + if (movementInfo.pos.GetPositionZ() < -500.0f) + { + if (!(plMover->InBattleground() + && plMover->GetBattleground() + && plMover->GetBattleground()->HandlePlayerUnderMap(_player))) + { + // NOTE: this is actually called many times while falling + // even after the player has been teleported away + // TODO: discard movement packets after the player is rooted + if (plMover->isAlive()) + { + plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); + // player can be alive if GM/etc + // change the death state to CORPSE to prevent the death timer from + // starting in the next player update + if (!plMover->isAlive()) + plMover->KillPlayer(); + } + } + } + } +} + +void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recv_data) +{ + uint32 opcode = recv_data.GetOpcode(); + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); + + /* extract packet */ + uint64 guid; + uint32 unk1; + float newspeed; + + recv_data.readPackGUID(guid); + + // now can skip not our packet + if (_player->GetGUID() != guid) + { + recv_data.rfinish(); // prevent warnings spam + return; + } + + // continue parse packet + + recv_data >> unk1; // counter or moveEvent + + MovementInfo movementInfo; + movementInfo.guid = guid; + ReadMovementInfo(recv_data, &movementInfo); + + recv_data >> newspeed; + /*----------------*/ + + // client ACK send one packet for mounted/run case and need skip all except last from its + // in other cases anti-cheat check can be fail in false case + UnitMoveType move_type; + UnitMoveType force_move_type; + + static char const* move_type_name[MAX_MOVE_TYPE] = { "Walk", "Run", "RunBack", "Swim", "SwimBack", "TurnRate", "Flight", "FlightBack", "PitchRate" }; + + switch (opcode) + { + case CMSG_FORCE_WALK_SPEED_CHANGE_ACK: move_type = MOVE_WALK; force_move_type = MOVE_WALK; break; + case CMSG_FORCE_RUN_SPEED_CHANGE_ACK: move_type = MOVE_RUN; force_move_type = MOVE_RUN; break; + case CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK: move_type = MOVE_RUN_BACK; force_move_type = MOVE_RUN_BACK; break; + case CMSG_FORCE_SWIM_SPEED_CHANGE_ACK: move_type = MOVE_SWIM; force_move_type = MOVE_SWIM; break; + case CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK: move_type = MOVE_SWIM_BACK; force_move_type = MOVE_SWIM_BACK; break; + case CMSG_FORCE_TURN_RATE_CHANGE_ACK: move_type = MOVE_TURN_RATE; force_move_type = MOVE_TURN_RATE; break; + case CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT; force_move_type = MOVE_FLIGHT; break; + case CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT_BACK; force_move_type = MOVE_FLIGHT_BACK; break; + case CMSG_FORCE_PITCH_RATE_CHANGE_ACK: move_type = MOVE_PITCH_RATE; force_move_type = MOVE_PITCH_RATE; break; + default: + sLog->outError("WorldSession::HandleForceSpeedChangeAck: Unknown move type opcode: %u", opcode); + return; + } + + // skip all forced speed changes except last and unexpected + // in run/mounted case used one ACK and it must be skipped.m_forced_speed_changes[MOVE_RUN} store both. + if (_player->m_forced_speed_changes[force_move_type] > 0) + { + --_player->m_forced_speed_changes[force_move_type]; + if (_player->m_forced_speed_changes[force_move_type] > 0) + return; + } + + if (!_player->GetTransport() && fabs(_player->GetSpeed(move_type) - newspeed) > 0.01f) + { + if (_player->GetSpeed(move_type) > newspeed) // must be greater - just correct + { + sLog->outError("%sSpeedChange player %s is NOT correct (must be %f instead %f), force set to correct value", + move_type_name[move_type], _player->GetName(), _player->GetSpeed(move_type), newspeed); + _player->SetSpeed(move_type, _player->GetSpeedRate(move_type), true); + } + else // must be lesser - cheating + { + sLog->outBasic("Player %s from account id %u kicked for incorrect speed (must be %f instead %f)", + _player->GetName(), _player->GetSession()->GetAccountId(), _player->GetSpeed(move_type), newspeed); + _player->GetSession()->KickPlayer(); + } + } +} + +void WorldSession::HandleSetActiveMoverOpcode(WorldPacket &recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_SET_ACTIVE_MOVER"); + + uint64 guid; + recv_data >> guid; + + if (GetPlayer()->IsInWorld()) + { + if (_player->m_mover->GetGUID() != guid) + sLog->outError("HandleSetActiveMoverOpcode: incorrect mover guid: mover is " UI64FMTD " (%s - Entry: %u) and should be " UI64FMTD, guid, GetLogNameForGuid(guid), GUID_ENPART(guid), _player->m_mover->GetGUID()); + } +} + +void WorldSession::HandleMoveNotActiveMover(WorldPacket &recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_MOVE_NOT_ACTIVE_MOVER"); + + uint64 old_mover_guid; + recv_data.readPackGUID(old_mover_guid); + + MovementInfo mi; + mi.guid = old_mover_guid; + ReadMovementInfo(recv_data, &mi); + + _player->m_movementInfo = mi; +} + +void WorldSession::HandleMountSpecialAnimOpcode(WorldPacket& /*recv_data*/) +{ + WorldPacket data(SMSG_MOUNTSPECIAL_ANIM, 8); + data << uint64(GetPlayer()->GetGUID()); + + GetPlayer()->SendMessageToSet(&data, false); +} + +void WorldSession::HandleMoveKnockBackAck(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_MOVE_KNOCK_BACK_ACK"); + + uint64 guid; + recv_data.readPackGUID(guid); + + if (_player->m_mover->GetGUID() != guid) + return; + + recv_data.read_skip(); // unk + + MovementInfo movementInfo; + ReadMovementInfo(recv_data, &movementInfo); + _player->m_movementInfo = movementInfo; + + WorldPacket data(MSG_MOVE_KNOCK_BACK, 66); + data.appendPackGUID(guid); + _player->BuildMovementPacket(&data); + + // knockback specific info + data << movementInfo.j_sinAngle; + data << movementInfo.j_cosAngle; + data << movementInfo.j_xyspeed; + data << movementInfo.j_zspeed; + + _player->SendMessageToSet(&data, false); +} + +void WorldSession::HandleMoveHoverAck(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_MOVE_HOVER_ACK"); + + uint64 guid; // guid - unused + recv_data.readPackGUID(guid); + + recv_data.read_skip(); // unk + + MovementInfo movementInfo; + ReadMovementInfo(recv_data, &movementInfo); + + recv_data.read_skip(); // unk2 +} + +void WorldSession::HandleMoveWaterWalkAck(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_MOVE_WATER_WALK_ACK"); + + uint64 guid; // guid - unused + recv_data.readPackGUID(guid); + + recv_data.read_skip(); // unk + + MovementInfo movementInfo; + ReadMovementInfo(recv_data, &movementInfo); + + recv_data.read_skip(); // unk2 +} + +void WorldSession::HandleSummonResponseOpcode(WorldPacket& recv_data) +{ + if (!_player->isAlive() || _player->isInCombat()) + return; + + uint64 summoner_guid; + bool agree; + recv_data >> summoner_guid; + recv_data >> agree; + + _player->SummonIfPossible(agree); +} + diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp new file mode 100755 index 00000000000..ef49b337b44 --- /dev/null +++ b/src/server/game/Handlers/NPCHandler.cpp @@ -0,0 +1,909 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "Language.h" +#include "DatabaseEnv.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Opcodes.h" +#include "Log.h" +#include "ObjectMgr.h" +#include "SpellMgr.h" +#include "Player.h" +#include "GossipDef.h" +#include "UpdateMask.h" +#include "ObjectAccessor.h" +#include "Creature.h" +#include "Pet.h" +#include "BattlegroundMgr.h" +#include "Battleground.h" +#include "ScriptMgr.h" +#include "CreatureAI.h" +#include "SpellInfo.h" + +enum StableResultCode +{ + STABLE_ERR_MONEY = 0x01, // "you don't have enough money" + STABLE_ERR_STABLE = 0x06, // currently used in most fail cases + STABLE_SUCCESS_STABLE = 0x08, // stable success + STABLE_SUCCESS_UNSTABLE = 0x09, // unstable/swap success + STABLE_SUCCESS_BUY_SLOT = 0x0A, // buy slot success + STABLE_ERR_EXOTIC = 0x0C, // "you are unable to control exotic creatures" +}; + +void WorldSession::HandleTabardVendorActivateOpcode(WorldPacket & recv_data) +{ + uint64 guid; + recv_data >> guid; + + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TABARDDESIGNER); + if (!unit) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleTabardVendorActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + SendTabardVendorActivate(guid); +} + +void WorldSession::SendTabardVendorActivate(uint64 guid) +{ + WorldPacket data(MSG_TABARDVENDOR_ACTIVATE, 8); + data << guid; + SendPacket(&data); +} + +void WorldSession::HandleBankerActivateOpcode(WorldPacket & recv_data) +{ + uint64 guid; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_BANKER_ACTIVATE"); + + recv_data >> guid; + + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_BANKER); + if (!unit) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleBankerActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + SendShowBank(guid); +} + +void WorldSession::SendShowBank(uint64 guid) +{ + WorldPacket data(SMSG_SHOW_BANK, 8); + data << guid; + SendPacket(&data); +} + +void WorldSession::HandleTrainerListOpcode(WorldPacket & recv_data) +{ + uint64 guid; + + recv_data >> guid; + SendTrainerList(guid); +} + +void WorldSession::SendTrainerList(uint64 guid) +{ + std::string str = GetTrinityString(LANG_NPC_TAINER_HELLO); + SendTrainerList(guid, str); +} + +void WorldSession::SendTrainerList(uint64 guid, const std::string& strTitle) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: SendTrainerList"); + + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER); + if (!unit) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: SendTrainerList - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + // trainer list loaded at check; + if (!unit->isCanTrainingOf(_player, true)) + return; + + CreatureTemplate const* ci = unit->GetCreatureInfo(); + + if (!ci) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: SendTrainerList - (GUID: %u) NO CREATUREINFO!", GUID_LOPART(guid)); + return; + } + + TrainerSpellData const* trainer_spells = unit->GetTrainerSpells(); + if (!trainer_spells) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: SendTrainerList - Training spells not found for creature (GUID: %u Entry: %u)", + GUID_LOPART(guid), unit->GetEntry()); + return; + } + + WorldPacket data(SMSG_TRAINER_LIST, 8+4+4+trainer_spells->spellList.size()*38 + strTitle.size()+1); + data << guid; + data << uint32(trainer_spells->trainerType); + + size_t count_pos = data.wpos(); + data << uint32(trainer_spells->spellList.size()); + + // reputation discount + float fDiscountMod = _player->GetReputationPriceDiscount(unit); + bool can_learn_primary_prof = GetPlayer()->GetFreePrimaryProfessionPoints() > 0; + + uint32 count = 0; + for (TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr) + { + TrainerSpell const* tSpell = &itr->second; + + bool valid = true; + bool primary_prof_first_rank = false; + for (uint8 i = 0; i < MAX_SPELL_EFFECTS ; ++i) + { + if (!tSpell->learnedSpell[i]) + continue; + if (!_player->IsSpellFitByClassAndRace(tSpell->learnedSpell[i])) + { + valid = false; + break; + } + SpellInfo const* learnedSpellInfo = sSpellMgr->GetSpellInfo(tSpell->learnedSpell[i]); + if (learnedSpellInfo && learnedSpellInfo->IsPrimaryProfessionFirstRank()) + primary_prof_first_rank = true; + } + if (!valid) + continue; + + TrainerSpellState state = _player->GetTrainerSpellState(tSpell); + + data << uint32(tSpell->spell); // learned spell (or cast-spell in profession case) + data << uint8(state == TRAINER_SPELL_GREEN_DISABLED ? TRAINER_SPELL_GREEN : state); + data << uint32(floor(tSpell->spellCost * fDiscountMod)); + + data << uint32(primary_prof_first_rank && can_learn_primary_prof ? 1 : 0); + // primary prof. learn confirmation dialog + data << uint32(primary_prof_first_rank ? 1 : 0); // must be equal prev. field to have learn button in enabled state + data << uint8(tSpell->reqLevel); + data << uint32(tSpell->reqSkill); + data << uint32(tSpell->reqSkillValue); + //prev + req or req + 0 + uint8 maxReq = 0; + for (uint8 i = 0; i < MAX_SPELL_EFFECTS ; ++i) + { + if (!tSpell->learnedSpell[i]) + continue; + if (uint32 prevSpellId = sSpellMgr->GetPrevSpellInChain(tSpell->learnedSpell[i])) + { + data << uint32(prevSpellId); + ++maxReq; + } + if (maxReq == 3) + break; + SpellsRequiringSpellMapBounds spellsRequired = sSpellMgr->GetSpellsRequiredForSpellBounds(tSpell->learnedSpell[i]); + for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequired.first; itr2 != spellsRequired.second && maxReq < 3; ++itr2) + { + data << uint32(itr2->second); + ++maxReq; + } + if (maxReq == 3) + break; + } + while (maxReq < 3) + { + data << uint32(0); + ++maxReq; + } + + ++count; + } + + data << strTitle; + + data.put(count_pos, count); + SendPacket(&data); +} + +void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket & recv_data) +{ + uint64 guid; + uint32 spellId = 0; + + recv_data >> guid >> spellId; + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_TRAINER_BUY_SPELL NpcGUID=%u, learn spell id is: %u", uint32(GUID_LOPART(guid)), spellId); + + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER); + if (!unit) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleTrainerBuySpellOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + if (!unit->isCanTrainingOf(_player, true)) + return; + + // check present spell in trainer spell list + TrainerSpellData const* trainer_spells = unit->GetTrainerSpells(); + if (!trainer_spells) + return; + + // not found, cheat? + TrainerSpell const* trainer_spell = trainer_spells->Find(spellId); + if (!trainer_spell) + return; + + // can't be learn, cheat? Or double learn with lags... + if (_player->GetTrainerSpellState(trainer_spell) != TRAINER_SPELL_GREEN) + return; + + // apply reputation discount + uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(unit))); + + // check money requirement + if (!_player->HasEnoughMoney(nSpellCost)) + return; + + _player->ModifyMoney(-int32(nSpellCost)); + + unit->SendPlaySpellVisual(179); // 53 SpellCastDirected + unit->SendPlaySpellImpact(_player->GetGUID(), 362); // 113 EmoteSalute + + // learn explicitly or cast explicitly + if (trainer_spell->IsCastable()) + _player->CastSpell(_player, trainer_spell->spell, true); + else + _player->learnSpell(spellId, false); + + WorldPacket data(SMSG_TRAINER_BUY_SUCCEEDED, 12); + data << uint64(guid); + data << uint32(spellId); // should be same as in packet from client + SendPacket(&data); +} + +void WorldSession::HandleGossipHelloOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GOSSIP_HELLO"); + + uint64 guid; + recv_data >> guid; + + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); + if (!unit) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleGossipHelloOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // set faction visible if needed + if (FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->getFaction())) + _player->GetReputationMgr().SetVisible(factionTemplateEntry); + + GetPlayer()->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK); + // remove fake death + //if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + // GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + if (unit->isArmorer() || unit->isCivilian() || unit->isQuestGiver() || unit->isServiceProvider() || unit->isGuard()) + { + unit->StopMoving(); + } + + // If spiritguide, no need for gossip menu, just put player into resurrect queue + if (unit->isSpiritGuide()) + { + Battleground* bg = _player->GetBattleground(); + if (bg) + { + bg->AddPlayerToResurrectQueue(unit->GetGUID(), _player->GetGUID()); + sBattlegroundMgr->SendAreaSpiritHealerQueryOpcode(_player, bg, unit->GetGUID()); + return; + } + } + + if (!sScriptMgr->OnGossipHello(_player, unit)) + { +// _player->TalkedToCreature(unit->GetEntry(), unit->GetGUID()); + _player->PrepareGossipMenu(unit, unit->GetCreatureInfo()->GossipMenuId, true); + _player->SendPreparedGossip(unit); + } + unit->AI()->sGossipHello(_player); +} + +/*void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_GOSSIP_SELECT_OPTION"); + + uint32 option; + uint32 unk; + uint64 guid; + std::string code = ""; + + recv_data >> guid >> unk >> option; + + if (_player->PlayerTalkClass->GossipOptionCoded(option)) + { + sLog->outDebug(LOG_FILTER_PACKETIO, "reading string"); + recv_data >> code; + sLog->outDebug(LOG_FILTER_PACKETIO, "string read: %s", code.c_str()); + } + + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); + if (!unit) + { + sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: HandleGossipSelectOptionOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + if (!code.empty()) + { + if (!Script->GossipSelectWithCode(_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction(option), code.c_str())) + unit->OnGossipSelect (_player, option); + } + else + { + if (!Script->OnGossipSelect (_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction (option))) + unit->OnGossipSelect (_player, option); + } +}*/ + +void WorldSession::HandleSpiritHealerActivateOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_SPIRIT_HEALER_ACTIVATE"); + + uint64 guid; + + recv_data >> guid; + + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_SPIRITHEALER); + if (!unit) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleSpiritHealerActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + SendSpiritResurrect(); +} + +void WorldSession::SendSpiritResurrect() +{ + _player->ResurrectPlayer(0.5f, true); + + _player->DurabilityLossAll(0.25f, true); + + // get corpse nearest graveyard + WorldSafeLocsEntry const* corpseGrave = NULL; + Corpse* corpse = _player->GetCorpse(); + if (corpse) + corpseGrave = sObjectMgr->GetClosestGraveYard( + corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetMapId(), _player->GetTeam()); + + // now can spawn bones + _player->SpawnCorpseBones(); + + // teleport to nearest from corpse graveyard, if different from nearest to player ghost + if (corpseGrave) + { + WorldSafeLocsEntry const* ghostGrave = sObjectMgr->GetClosestGraveYard( + _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetMapId(), _player->GetTeam()); + + if (corpseGrave != ghostGrave) + _player->TeleportTo(corpseGrave->map_id, corpseGrave->x, corpseGrave->y, corpseGrave->z, _player->GetOrientation()); + // or update at original position + else + _player->UpdateObjectVisibility(); + } + // or update at original position + else + _player->UpdateObjectVisibility(); +} + +void WorldSession::HandleBinderActivateOpcode(WorldPacket & recv_data) +{ + uint64 npcGUID; + recv_data >> npcGUID; + + if (!GetPlayer()->IsInWorld() || !GetPlayer()->isAlive()) + return; + + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_INNKEEPER); + if (!unit) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleBinderActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID))); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + SendBindPoint(unit); +} + +void WorldSession::SendBindPoint(Creature* npc) +{ + // prevent set homebind to instances in any case + if (GetPlayer()->GetMap()->Instanceable()) + return; + + uint32 bindspell = 3286; + + // update sql homebind + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PLAYER_HOMEBIND); + stmt->setUInt16(0, _player->GetMapId()); + stmt->setUInt16(1, _player->GetAreaId()); + stmt->setFloat (2, _player->GetPositionX()); + stmt->setFloat (3, _player->GetPositionY()); + stmt->setFloat (4, _player->GetPositionZ()); + stmt->setUInt32(5, _player->GetGUIDLow()); + CharacterDatabase.Execute(stmt); + + _player->m_homebindMapId = _player->GetMapId(); + _player->m_homebindAreaId = _player->GetAreaId(); + _player->m_homebindX = _player->GetPositionX(); + _player->m_homebindY = _player->GetPositionY(); + _player->m_homebindZ = _player->GetPositionZ(); + + // send spell for homebinding (3286) + npc->CastSpell(_player, bindspell, true); + + WorldPacket data(SMSG_TRAINER_BUY_SUCCEEDED, (8+4)); + data << uint64(npc->GetGUID()); + data << uint32(bindspell); + SendPacket(&data); + + _player->PlayerTalkClass->SendCloseGossip(); +} + +void WorldSession::HandleListStabledPetsOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recv MSG_LIST_STABLED_PETS"); + uint64 npcGUID; + + recv_data >> npcGUID; + + if (!CheckStableMaster(npcGUID)) + return; + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + // remove mounts this fix bug where getting pet from stable while mounted deletes pet. + if (GetPlayer()->IsMounted()) + GetPlayer()->RemoveAurasByType(SPELL_AURA_MOUNTED); + + SendStablePet(npcGUID); +} + +void WorldSession::SendStablePet(uint64 guid) +{ + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SLOTS_DETAIL); + + stmt->setUInt32(0, _player->GetGUIDLow()); + stmt->setUInt8(1, PET_SAVE_FIRST_STABLE_SLOT); + stmt->setUInt8(2, PET_SAVE_LAST_STABLE_SLOT); + + _sendStabledPetCallback.SetParam(guid); + _sendStabledPetCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); +} + +void WorldSession::SendStablePetCallback(PreparedQueryResult result, uint64 guid) +{ + if (!GetPlayer()) + return; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recv MSG_LIST_STABLED_PETS Send."); + + WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size + + data << uint64 (guid); + + Pet* pet = _player->GetPet(); + + size_t wpos = data.wpos(); + data << uint8(0); // place holder for slot show number + + data << uint8(GetPlayer()->m_stableSlots); + + uint8 num = 0; // counter for place holder + + // not let move dead pet in slot + if (pet && pet->isAlive() && pet->getPetType() == HUNTER_PET) + { + data << uint32(pet->GetCharmInfo()->GetPetNumber()); + data << uint32(pet->GetEntry()); + data << uint32(pet->getLevel()); + data << pet->GetName(); // petname + data << uint8(1); // 1 = current, 2/3 = in stable (any from 4, 5, ... create problems with proper show) + ++num; + } + + if (result) + { + do + { + Field* fields = result->Fetch(); + + data << uint32(fields[1].GetUInt32()); // petnumber + data << uint32(fields[2].GetUInt32()); // creature entry + data << uint32(fields[3].GetUInt16()); // level + data << fields[4].GetString(); // name + data << uint8(2); // 1 = current, 2/3 = in stable (any from 4, 5, ... create problems with proper show) + + ++num; + } + while (result->NextRow()); + } + + data.put(wpos, num); // set real data to placeholder + SendPacket(&data); + +} + +void WorldSession::SendStableResult(uint8 res) +{ + WorldPacket data(SMSG_STABLE_RESULT, 1); + data << uint8(res); + SendPacket(&data); +} + +void WorldSession::HandleStablePet(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recv CMSG_STABLE_PET"); + uint64 npcGUID; + + recv_data >> npcGUID; + + if (!GetPlayer()->isAlive()) + { + SendStableResult(STABLE_ERR_STABLE); + return; + } + + if (!CheckStableMaster(npcGUID)) + { + SendStableResult(STABLE_ERR_STABLE); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + Pet* pet = _player->GetPet(); + + // can't place in stable dead pet + if (!pet||!pet->isAlive()||pet->getPetType() != HUNTER_PET) + { + SendStableResult(STABLE_ERR_STABLE); + return; + } + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SLOTS); + + stmt->setUInt32(0, _player->GetGUIDLow()); + stmt->setUInt8(1, PET_SAVE_FIRST_STABLE_SLOT); + stmt->setUInt8(2, PET_SAVE_LAST_STABLE_SLOT); + + _stablePetCallback = CharacterDatabase.AsyncQuery(stmt); +} + +void WorldSession::HandleStablePetCallback(PreparedQueryResult result) +{ + if (!GetPlayer()) + return; + + uint8 freeSlot = 1; + if (result) + { + do + { + Field* fields = result->Fetch(); + + uint8 slot = fields[1].GetUInt8(); + + // slots ordered in query, and if not equal then free + if (slot != freeSlot) + break; + + // this slot not free, skip + ++freeSlot; + } + while (result->NextRow()); + } + + WorldPacket data(SMSG_STABLE_RESULT, 1); + if (freeSlot > 0 && freeSlot <= GetPlayer()->m_stableSlots) + { + _player->RemovePet(_player->GetPet(), PetSaveMode(freeSlot)); + SendStableResult(STABLE_SUCCESS_STABLE); + } + else + SendStableResult(STABLE_ERR_STABLE); +} + +void WorldSession::HandleUnstablePet(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recv CMSG_UNSTABLE_PET."); + uint64 npcGUID; + uint32 petnumber; + + recv_data >> npcGUID >> petnumber; + + if (!CheckStableMaster(npcGUID)) + { + SendStableResult(STABLE_ERR_STABLE); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_ENTRY); + + stmt->setUInt32(0, _player->GetGUIDLow()); + stmt->setUInt32(1, petnumber); + stmt->setUInt8(2, PET_SAVE_FIRST_STABLE_SLOT); + stmt->setUInt8(3, PET_SAVE_LAST_STABLE_SLOT); + + _unstablePetCallback.SetParam(petnumber); + _unstablePetCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); +} + +void WorldSession::HandleUnstablePetCallback(PreparedQueryResult result, uint32 petId) +{ + if (!GetPlayer()) + return; + + uint32 petEntry = 0; + if (result) + { + Field* fields = result->Fetch(); + petEntry = fields[0].GetUInt32(); + } + + if (!petEntry) + { + SendStableResult(STABLE_ERR_STABLE); + return; + } + + CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(petEntry); + if (!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets())) + { + // if problem in exotic pet + if (creatureInfo && creatureInfo->isTameable(true)) + SendStableResult(STABLE_ERR_EXOTIC); + else + SendStableResult(STABLE_ERR_STABLE); + return; + } + + Pet* pet = _player->GetPet(); + if (pet && pet->isAlive()) + { + SendStableResult(STABLE_ERR_STABLE); + return; + } + + // delete dead pet + if (pet) + _player->RemovePet(pet, PET_SAVE_AS_DELETED); + + Pet* newPet = new Pet(_player, HUNTER_PET); + if (!newPet->LoadPetFromDB(_player, petEntry, petId)) + { + delete newPet; + newPet = NULL; + SendStableResult(STABLE_ERR_STABLE); + return; + } + + SendStableResult(STABLE_SUCCESS_UNSTABLE); +} + +void WorldSession::HandleBuyStableSlot(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recv CMSG_BUY_STABLE_SLOT."); + uint64 npcGUID; + + recv_data >> npcGUID; + + if (!CheckStableMaster(npcGUID)) + { + SendStableResult(STABLE_ERR_STABLE); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + if (GetPlayer()->m_stableSlots < MAX_PET_STABLES) + { + StableSlotPricesEntry const* SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots+1); + if (_player->HasEnoughMoney(SlotPrice->Price)) + { + ++GetPlayer()->m_stableSlots; + _player->ModifyMoney(-int32(SlotPrice->Price)); + SendStableResult(STABLE_SUCCESS_BUY_SLOT); + } + else + SendStableResult(STABLE_ERR_MONEY); + } + else + SendStableResult(STABLE_ERR_STABLE); +} + +void WorldSession::HandleStableRevivePet(WorldPacket &/* recv_data */) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "HandleStableRevivePet: Not implemented"); +} + +void WorldSession::HandleStableSwapPet(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recv CMSG_STABLE_SWAP_PET."); + uint64 npcGUID; + uint32 petId; + + recv_data >> npcGUID >> petId; + + if (!CheckStableMaster(npcGUID)) + { + SendStableResult(STABLE_ERR_STABLE); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + Pet* pet = _player->GetPet(); + + if (!pet || pet->getPetType() != HUNTER_PET) + { + SendStableResult(STABLE_ERR_STABLE); + return; + } + + // Find swapped pet slot in stable + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SLOT_BY_ID); + + stmt->setUInt32(0, _player->GetGUIDLow()); + stmt->setUInt32(1, petId); + + _stableSwapCallback.SetParam(petId); + _stableSwapCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); +} + +void WorldSession::HandleStableSwapPetCallback(PreparedQueryResult result, uint32 petId) +{ + if (!GetPlayer()) + return; + + if (!result) + { + SendStableResult(STABLE_ERR_STABLE); + return; + } + + Field* fields = result->Fetch(); + + uint32 slot = fields[0].GetUInt8(); + uint32 petEntry = fields[1].GetUInt32(); + + if (!petEntry) + { + SendStableResult(STABLE_ERR_STABLE); + return; + } + + CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(petEntry); + if (!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets())) + { + // if problem in exotic pet + if (creatureInfo && creatureInfo->isTameable(true)) + SendStableResult(STABLE_ERR_EXOTIC); + else + SendStableResult(STABLE_ERR_STABLE); + return; + } + + // move alive pet to slot or delete dead pet + Pet* pet = _player->GetPet(); + + _player->RemovePet(pet, pet->isAlive() ? PetSaveMode(slot) : PET_SAVE_AS_DELETED); + + // summon unstabled pet + Pet* newpet = new Pet(_player); + if (!newpet->LoadPetFromDB(_player, petEntry, petId)) + { + delete newpet; + SendStableResult(STABLE_ERR_STABLE); + } + else + SendStableResult(STABLE_SUCCESS_UNSTABLE); +} + +void WorldSession::HandleRepairItemOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_REPAIR_ITEM"); + + uint64 npcGUID, itemGUID; + uint8 guildBank; // new in 2.3.2, bool that means from guild bank money + + recv_data >> npcGUID >> itemGUID >> guildBank; + + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_REPAIR); + if (!unit) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleRepairItemOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID))); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + // reputation discount + float discountMod = _player->GetReputationPriceDiscount(unit); + + if (itemGUID) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "ITEM: Repair item, itemGUID = %u, npcGUID = %u", GUID_LOPART(itemGUID), GUID_LOPART(npcGUID)); + + Item* item = _player->GetItemByGuid(itemGUID); + if (item) + _player->DurabilityRepair(item->GetPos(), true, discountMod, guildBank); + } + else + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "ITEM: Repair all items, npcGUID = %u", GUID_LOPART(npcGUID)); + _player->DurabilityRepairAll(true, discountMod, guildBank); + } +} + diff --git a/src/server/game/Handlers/NPCHandler.h b/src/server/game/Handlers/NPCHandler.h new file mode 100755 index 00000000000..af84b71a74f --- /dev/null +++ b/src/server/game/Handlers/NPCHandler.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef __NPCHANDLER_H +#define __NPCHANDLER_H + +struct QEmote +{ + uint32 _Emote; + uint32 _Delay; +}; + +#define MAX_GOSSIP_TEXT_EMOTES 3 + +struct GossipTextOption +{ + std::string Text_0; + std::string Text_1; + uint32 Language; + float Probability; + QEmote Emotes[MAX_GOSSIP_TEXT_EMOTES]; +}; + +#define MAX_GOSSIP_TEXT_OPTIONS 8 + +struct GossipText +{ + GossipTextOption Options[MAX_GOSSIP_TEXT_OPTIONS]; +}; + +struct PageTextLocale +{ + StringVector Text; +}; + +struct NpcTextLocale +{ + NpcTextLocale() { Text_0.resize(8); Text_1.resize(8); } + + std::vector Text_0; + std::vector Text_1; +}; +#endif + diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp new file mode 100755 index 00000000000..68ce3153450 --- /dev/null +++ b/src/server/game/Handlers/PetHandler.cpp @@ -0,0 +1,879 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "ObjectMgr.h" +#include "SpellMgr.h" +#include "Log.h" +#include "Opcodes.h" +#include "Spell.h" +#include "ObjectAccessor.h" +#include "CreatureAI.h" +#include "Util.h" +#include "Pet.h" +#include "World.h" +#include "Group.h" +#include "SpellInfo.h" + +void WorldSession::HandleDismissCritter(WorldPacket &recv_data) +{ + uint64 guid; + recv_data >> guid; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_DISMISS_CRITTER for GUID " UI64FMTD, guid); + + Unit* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); + + if (!pet) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "Vanitypet (guid: %u) does not exist - player '%s' (guid: %u / account: %u) attempted to dismiss it (possibly lagged out)", + uint32(GUID_LOPART(guid)), GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), GetAccountId()); + return; + } + + if (_player->GetCritterGUID() == pet->GetGUID()) + { + if (pet->GetTypeId() == TYPEID_UNIT && pet->ToCreature()->isSummon()) + pet->ToTempSummon()->UnSummon(); + } +} + +void WorldSession::HandlePetAction(WorldPacket & recv_data) +{ + uint64 guid1; + uint32 data; + uint64 guid2; + recv_data >> guid1; //pet guid + recv_data >> data; + recv_data >> guid2; //tag guid + + uint32 spellid = UNIT_ACTION_BUTTON_ACTION(data); + uint8 flag = UNIT_ACTION_BUTTON_TYPE(data); //delete = 0x07 CastSpell = C1 + + // used also for charmed creature + Unit* pet= ObjectAccessor::GetUnit(*_player, guid1); + sLog->outDetail("HandlePetAction: Pet %u - flag: %u, spellid: %u, target: %u.", uint32(GUID_LOPART(guid1)), uint32(flag), spellid, uint32(GUID_LOPART(guid2))); + + if (!pet) + { + sLog->outError("HandlePetAction: Pet (GUID: %u) doesn't exist for player '%s'", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName()); + return; + } + + if (pet != GetPlayer()->GetFirstControlled()) + { + sLog->outError("HandlePetAction: Pet (GUID: %u) does not belong to player '%s'", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName()); + return; + } + + if (!pet->isAlive()) + { + SpellInfo const* spell = (flag == ACT_ENABLED || flag == ACT_PASSIVE) ? sSpellMgr->GetSpellInfo(spellid) : NULL; + if (!spell) + return; + if (!(spell->Attributes & SPELL_ATTR0_CASTABLE_WHILE_DEAD)) + return; + } + + //TODO: allow control charmed player? + if (pet->GetTypeId() == TYPEID_PLAYER && !(flag == ACT_COMMAND && spellid == COMMAND_ATTACK)) + return; + + if (GetPlayer()->m_Controlled.size() == 1) + HandlePetActionHelper(pet, guid1, spellid, flag, guid2); + else + { + //If a pet is dismissed, m_Controlled will change + std::vector controlled; + for (Unit::ControlList::iterator itr = GetPlayer()->m_Controlled.begin(); itr != GetPlayer()->m_Controlled.end(); ++itr) + if ((*itr)->GetEntry() == pet->GetEntry() && (*itr)->isAlive()) + controlled.push_back(*itr); + for (std::vector::iterator itr = controlled.begin(); itr != controlled.end(); ++itr) + HandlePetActionHelper(*itr, guid1, spellid, flag, guid2); + } +} + +void WorldSession::HandlePetStopAttack(WorldPacket &recv_data) +{ + uint64 guid; + recv_data >> guid; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_PET_STOP_ATTACK for GUID " UI64FMTD "", guid); + + Unit* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); + + if (!pet) + { + sLog->outError("HandlePetStopAttack: Pet %u does not exist", uint32(GUID_LOPART(guid))); + return; + } + + if (pet != GetPlayer()->GetPet() && pet != GetPlayer()->GetCharm()) + { + sLog->outError("HandlePetStopAttack: Pet GUID %u isn't a pet or charmed creature of player %s", uint32(GUID_LOPART(guid)), GetPlayer()->GetName()); + return; + } + + if (!pet->isAlive()) + return; + + pet->AttackStop(); +} + +void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint16 spellid, uint16 flag, uint64 guid2) +{ + CharmInfo* charmInfo = pet->GetCharmInfo(); + if (!charmInfo) + { + sLog->outError("WorldSession::HandlePetAction(petGuid: " UI64FMTD ", tagGuid: " UI64FMTD ", spellId: %u, flag: %u): object (entry: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", + guid1, guid2, spellid, flag, pet->GetGUIDLow(), pet->GetTypeId()); + return; + } + + switch (flag) + { + case ACT_COMMAND: //0x07 + switch (spellid) + { + case COMMAND_STAY: //flat=1792 //STAY + pet->AttackStop(); + pet->InterruptNonMeleeSpells(false); + pet->GetMotionMaster()->Clear(false); + pet->GetMotionMaster()->MoveIdle(); + charmInfo->SetCommandState(COMMAND_STAY); + + charmInfo->SetIsCommandAttack(false); + charmInfo->SetIsAtStay(true); + charmInfo->SetIsFollowing(false); + charmInfo->SetIsReturning(false); + charmInfo->SaveStayPosition(); + break; + case COMMAND_FOLLOW: //spellid=1792 //FOLLOW + pet->AttackStop(); + pet->InterruptNonMeleeSpells(false); + pet->GetMotionMaster()->MoveFollow(_player, PET_FOLLOW_DIST, pet->GetFollowAngle()); + charmInfo->SetCommandState(COMMAND_FOLLOW); + + charmInfo->SetIsCommandAttack(false); + charmInfo->SetIsAtStay(false); + charmInfo->SetIsReturning(true); + charmInfo->SetIsFollowing(false); + break; + case COMMAND_ATTACK: //spellid=1792 //ATTACK + { + // Can't attack if owner is pacified + if (_player->HasAuraType(SPELL_AURA_MOD_PACIFY)) + { + //pet->SendPetCastFail(spellid, SPELL_FAILED_PACIFIED); + //TODO: Send proper error message to client + return; + } + + // only place where pet can be player + Unit* TargetUnit = ObjectAccessor::GetUnit(*_player, guid2); + if (!TargetUnit) + return; + + if (Unit* owner = pet->GetOwner()) + if (!owner->IsValidAttackTarget(TargetUnit)) + return; + + // Not let attack through obstructions + if (sWorld->getBoolConfig(CONFIG_PET_LOS)) + { + if (!pet->IsWithinLOSInMap(TargetUnit)) + return; + } + + pet->ClearUnitState(UNIT_STAT_FOLLOW); + // This is true if pet has no target or has target but targets differs. + if (pet->getVictim() != TargetUnit || (pet->getVictim() == TargetUnit && !pet->GetCharmInfo()->IsCommandAttack())) + { + if (pet->getVictim()) + pet->AttackStop(); + + if (pet->GetTypeId() != TYPEID_PLAYER && pet->ToCreature()->IsAIEnabled) + { + charmInfo->SetIsCommandAttack(true); + charmInfo->SetIsAtStay(false); + charmInfo->SetIsFollowing(false); + charmInfo->SetIsReturning(false); + + pet->ToCreature()->AI()->AttackStart(TargetUnit); + + //10% chance to play special pet attack talk, else growl + if (pet->ToCreature()->isPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != TargetUnit && urand(0, 100) < 10) + pet->SendPetTalk((uint32)PET_TALK_ATTACK); + else + { + // 90% chance for pet and 100% chance for charmed creature + pet->SendPetAIReaction(guid1); + } + } + else // charmed player + { + if (pet->getVictim() && pet->getVictim() != TargetUnit) + pet->AttackStop(); + + charmInfo->SetIsCommandAttack(true); + charmInfo->SetIsAtStay(false); + charmInfo->SetIsFollowing(false); + charmInfo->SetIsReturning(false); + + pet->Attack(TargetUnit, true); + pet->SendPetAIReaction(guid1); + } + } + break; + } + case COMMAND_ABANDON: // abandon (hunter pet) or dismiss (summoned pet) + if (pet->GetCharmerGUID() == GetPlayer()->GetGUID()) + _player->StopCastingCharm(); + else if (pet->GetOwnerGUID() == GetPlayer()->GetGUID()) + { + ASSERT(pet->GetTypeId() == TYPEID_UNIT); + if (pet->isPet()) + { + if (((Pet*)pet)->getPetType() == HUNTER_PET) + GetPlayer()->RemovePet((Pet*)pet, PET_SAVE_AS_DELETED); + else + //dismissing a summoned pet is like killing them (this prevents returning a soulshard...) + pet->setDeathState(CORPSE); + } + else if (pet->HasUnitTypeMask(UNIT_MASK_MINION)) + { + ((Minion*)pet)->UnSummon(); + } + } + break; + default: + sLog->outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid); + } + break; + case ACT_REACTION: // 0x6 + switch (spellid) + { + case REACT_PASSIVE: //passive + pet->AttackStop(); + + case REACT_DEFENSIVE: //recovery + case REACT_AGGRESSIVE: //activete + if (pet->GetTypeId() == TYPEID_UNIT) + pet->ToCreature()->SetReactState(ReactStates(spellid)); + break; + } + break; + case ACT_DISABLED: // 0x81 spell (disabled), ignore + case ACT_PASSIVE: // 0x01 + case ACT_ENABLED: // 0xC1 spell + { + Unit* unit_target = NULL; + + if (guid2) + unit_target = ObjectAccessor::GetUnit(*_player, guid2); + + // do not cast unknown spells + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid); + if (!spellInfo) + { + sLog->outError("WORLD: unknown PET spell id %i", spellid); + return; + } + + if (spellInfo->StartRecoveryCategory > 0) + if (pet->GetCharmInfo() && pet->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) + return; + + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if (spellInfo->Effects[i].TargetA.GetTarget() == TARGET_UNIT_SRC_AREA_ENEMY || spellInfo->Effects[i].TargetA.GetTarget() == TARGET_UNIT_DEST_AREA_ENEMY || spellInfo->Effects[i].TargetA.GetTarget() == TARGET_DEST_DYNOBJ_ENEMY) + return; + } + + // do not cast not learned spells + if (!pet->HasSpell(spellid) || spellInfo->IsPassive()) + return; + + // Clear the flags as if owner clicked 'attack'. AI will reset them + // after AttackStart, even if spell failed + if (pet->GetCharmInfo()) + { + pet->GetCharmInfo()->SetIsAtStay(false); + pet->GetCharmInfo()->SetIsCommandAttack(true); + pet->GetCharmInfo()->SetIsReturning(false); + pet->GetCharmInfo()->SetIsFollowing(false); + } + + Spell* spell = new Spell(pet, spellInfo, TRIGGERED_NONE); + + SpellCastResult result = spell->CheckPetCast(unit_target); + + //auto turn to target unless possessed + if (result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->isPossessed() && !pet->IsVehicle()) + { + if (unit_target) + { + pet->SetInFront(unit_target); + if (unit_target->GetTypeId() == TYPEID_PLAYER) + pet->SendUpdateToPlayer((Player*)unit_target); + } + else if (Unit* unit_target2 = spell->m_targets.GetUnitTarget()) + { + pet->SetInFront(unit_target2); + if (unit_target2->GetTypeId() == TYPEID_PLAYER) + pet->SendUpdateToPlayer((Player*)unit_target2); + } + if (Unit* powner = pet->GetCharmerOrOwner()) + if (powner->GetTypeId() == TYPEID_PLAYER) + pet->SendUpdateToPlayer(powner->ToPlayer()); + result = SPELL_CAST_OK; + } + + if (result == SPELL_CAST_OK) + { + pet->ToCreature()->AddCreatureSpellCooldown(spellid); + + unit_target = spell->m_targets.GetUnitTarget(); + + //10% chance to play special pet attack talk, else growl + //actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell + if (pet->ToCreature()->isPet() && (((Pet*)pet)->getPetType() == SUMMON_PET) && (pet != unit_target) && (urand(0, 100) < 10)) + pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL); + else + { + pet->SendPetAIReaction(guid1); + } + + if (unit_target && !GetPlayer()->IsFriendlyTo(unit_target) && !pet->isPossessed() && !pet->IsVehicle()) + { + // This is true if pet has no target or has target but targets differs. + if (pet->getVictim() != unit_target) + { + if (pet->getVictim()) + pet->AttackStop(); + pet->GetMotionMaster()->Clear(); + if (pet->ToCreature()->IsAIEnabled) + pet->ToCreature()->AI()->AttackStart(unit_target); + } + } + + spell->prepare(&(spell->m_targets)); + } + else + { + if (pet->isPossessed() || pet->IsVehicle()) + Spell::SendCastResult(GetPlayer(), spellInfo, 0, result); + else + pet->SendPetCastFail(spellid, result); + + if (!pet->ToCreature()->HasSpellCooldown(spellid)) + GetPlayer()->SendClearCooldown(spellid, pet); + + spell->finish(false); + delete spell; + + // reset specific flags in case of spell fail. AI will reset other flags + if (pet->GetCharmInfo()) + pet->GetCharmInfo()->SetIsCommandAttack(false); + } + break; + } + default: + sLog->outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid); + } +} + +void WorldSession::HandlePetNameQuery(WorldPacket & recv_data) +{ + sLog->outDetail("HandlePetNameQuery. CMSG_PET_NAME_QUERY"); + + uint32 petnumber; + uint64 petguid; + + recv_data >> petnumber; + recv_data >> petguid; + + SendPetNameQuery(petguid, petnumber); +} + +void WorldSession::SendPetNameQuery(uint64 petguid, uint32 petnumber) +{ + Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, petguid); + if (!pet) + { + WorldPacket data(SMSG_PET_NAME_QUERY_RESPONSE, (4+1+4+1)); + data << uint32(petnumber); + data << uint8(0); + data << uint32(0); + data << uint8(0); + _player->GetSession()->SendPacket(&data); + return; + } + + std::string name = pet->GetName(); + + WorldPacket data(SMSG_PET_NAME_QUERY_RESPONSE, (4+4+name.size()+1)); + data << uint32(petnumber); + data << name.c_str(); + data << uint32(pet->GetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP)); + + if (pet->isPet() && ((Pet*)pet)->GetDeclinedNames()) + { + data << uint8(1); + for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) + data << ((Pet*)pet)->GetDeclinedNames()->name[i]; + } + else + data << uint8(0); + + _player->GetSession()->SendPacket(&data); +} + +bool WorldSession::CheckStableMaster(uint64 guid) +{ + // spell case or GM + if (guid == GetPlayer()->GetGUID()) + { + if (!GetPlayer()->isGameMaster() && !GetPlayer()->HasAuraType(SPELL_AURA_OPEN_STABLE)) + { + sLog->outStaticDebug("Player (GUID:%u) attempt open stable in cheating way.", GUID_LOPART(guid)); + return false; + } + } + // stable master case + else + { + if (!GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_STABLEMASTER)) + { + sLog->outStaticDebug("Stablemaster (GUID:%u) not found or you can't interact with him.", GUID_LOPART(guid)); + return false; + } + } + return true; +} + +void WorldSession::HandlePetSetAction(WorldPacket & recv_data) +{ + sLog->outDetail("HandlePetSetAction. CMSG_PET_SET_ACTION"); + + uint64 petguid; + uint8 count; + + recv_data >> petguid; + + Unit* pet = ObjectAccessor::GetUnit(*_player, petguid); + + if (!pet || pet != _player->GetFirstControlled()) + { + sLog->outError("HandlePetSetAction: Unknown pet (GUID: %u) or pet owner (GUID: %u)", GUID_LOPART(petguid), _player->GetGUIDLow()); + return; + } + + CharmInfo* charmInfo = pet->GetCharmInfo(); + if (!charmInfo) + { + sLog->outError("WorldSession::HandlePetSetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId()); + return; + } + + count = (recv_data.size() == 24) ? 2 : 1; + + uint32 position[2]; + uint32 data[2]; + bool move_command = false; + + for (uint8 i = 0; i < count; ++i) + { + recv_data >> position[i]; + recv_data >> data[i]; + + uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data[i]); + + //ignore invalid position + if (position[i] >= MAX_UNIT_ACTION_BAR_INDEX) + return; + + // in the normal case, command and reaction buttons can only be moved, not removed + // at moving count == 2, at removing count == 1 + // ignore attempt to remove command|reaction buttons (not possible at normal case) + if (act_state == ACT_COMMAND || act_state == ACT_REACTION) + { + if (count == 1) + return; + + move_command = true; + } + } + + // check swap (at command->spell swap client remove spell first in another packet, so check only command move correctness) + if (move_command) + { + uint8 act_state_0 = UNIT_ACTION_BUTTON_TYPE(data[0]); + if (act_state_0 == ACT_COMMAND || act_state_0 == ACT_REACTION) + { + uint32 spell_id_0 = UNIT_ACTION_BUTTON_ACTION(data[0]); + UnitActionBarEntry const* actionEntry_1 = charmInfo->GetActionBarEntry(position[1]); + if (!actionEntry_1 || spell_id_0 != actionEntry_1->GetAction() || + act_state_0 != actionEntry_1->GetType()) + return; + } + + uint8 act_state_1 = UNIT_ACTION_BUTTON_TYPE(data[1]); + if (act_state_1 == ACT_COMMAND || act_state_1 == ACT_REACTION) + { + uint32 spell_id_1 = UNIT_ACTION_BUTTON_ACTION(data[1]); + UnitActionBarEntry const* actionEntry_0 = charmInfo->GetActionBarEntry(position[0]); + if (!actionEntry_0 || spell_id_1 != actionEntry_0->GetAction() || + act_state_1 != actionEntry_0->GetType()) + return; + } + } + + for (uint8 i = 0; i < count; ++i) + { + uint32 spell_id = UNIT_ACTION_BUTTON_ACTION(data[i]); + uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data[i]); + + sLog->outDetail("Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), position[i], spell_id, uint32(act_state)); + + //if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add + if (!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_PASSIVE) && spell_id && !pet->HasSpell(spell_id))) + { + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id)) + { + //sign for autocast + if (act_state == ACT_ENABLED) + { + if (pet->GetTypeId() == TYPEID_UNIT && pet->ToCreature()->isPet()) + ((Pet*)pet)->ToggleAutocast(spellInfo, true); + else + for (Unit::ControlList::iterator itr = GetPlayer()->m_Controlled.begin(); itr != GetPlayer()->m_Controlled.end(); ++itr) + if ((*itr)->GetEntry() == pet->GetEntry()) + (*itr)->GetCharmInfo()->ToggleCreatureAutocast(spellInfo, true); + } + //sign for no/turn off autocast + else if (act_state == ACT_DISABLED) + { + if (pet->GetTypeId() == TYPEID_UNIT && pet->ToCreature()->isPet()) + ((Pet*)pet)->ToggleAutocast(spellInfo, false); + else + for (Unit::ControlList::iterator itr = GetPlayer()->m_Controlled.begin(); itr != GetPlayer()->m_Controlled.end(); ++itr) + if ((*itr)->GetEntry() == pet->GetEntry()) + (*itr)->GetCharmInfo()->ToggleCreatureAutocast(spellInfo, false); + } + } + + charmInfo->SetActionBar(position[i], spell_id, ActiveStates(act_state)); + } + } +} + +void WorldSession::HandlePetRename(WorldPacket & recv_data) +{ + sLog->outDetail("HandlePetRename. CMSG_PET_RENAME"); + + uint64 petguid; + uint8 isdeclined; + + std::string name; + DeclinedName declinedname; + + recv_data >> petguid; + recv_data >> name; + recv_data >> isdeclined; + + Pet* pet = ObjectAccessor::FindPet(petguid); + // check it! + if (!pet || !pet->isPet() || ((Pet*)pet)->getPetType()!= HUNTER_PET || + !pet->HasByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED) || + pet->GetOwnerGUID() != _player->GetGUID() || !pet->GetCharmInfo()) + return; + + PetNameInvalidReason res = ObjectMgr::CheckPetName(name); + if (res != PET_NAME_SUCCESS) + { + SendPetNameInvalid(res, name, NULL); + return; + } + + if (sObjectMgr->IsReservedName(name)) + { + SendPetNameInvalid(PET_NAME_RESERVED, name, NULL); + return; + } + + pet->SetName(name); + + Unit* owner = pet->GetOwner(); + if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup()) + owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_NAME); + + pet->RemoveByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED); + + if (isdeclined) + { + for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) + { + recv_data >> declinedname.name[i]; + } + + std::wstring wname; + Utf8toWStr(name, wname); + if (!ObjectMgr::CheckDeclinedNames(wname, declinedname)) + { + SendPetNameInvalid(PET_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME, name, &declinedname); + return; + } + } + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + if (isdeclined) + { + for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) + CharacterDatabase.EscapeString(declinedname.name[i]); + trans->PAppend("DELETE FROM character_pet_declinedname WHERE owner = '%u' AND id = '%u'", _player->GetGUIDLow(), pet->GetCharmInfo()->GetPetNumber()); + trans->PAppend("INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES ('%u', '%u', '%s', '%s', '%s', '%s', '%s')", + pet->GetCharmInfo()->GetPetNumber(), _player->GetGUIDLow(), declinedname.name[0].c_str(), declinedname.name[1].c_str(), declinedname.name[2].c_str(), declinedname.name[3].c_str(), declinedname.name[4].c_str()); + } + + CharacterDatabase.EscapeString(name); + trans->PAppend("UPDATE character_pet SET name = '%s', renamed = '1' WHERE owner = '%u' AND id = '%u'", name.c_str(), _player->GetGUIDLow(), pet->GetCharmInfo()->GetPetNumber()); + CharacterDatabase.CommitTransaction(trans); + + pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(NULL))); // cast can't be helped +} + +void WorldSession::HandlePetAbandon(WorldPacket & recv_data) +{ + uint64 guid; + recv_data >> guid; //pet guid + sLog->outDetail("HandlePetAbandon. CMSG_PET_ABANDON pet guid is %u", GUID_LOPART(guid)); + + if (!_player->IsInWorld()) + return; + + // pet/charmed + Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); + if (pet) + { + if (pet->isPet()) + { + if (pet->GetGUID() == _player->GetPetGUID()) + { + uint32 feelty = pet->GetPower(POWER_HAPPINESS); + pet->SetPower(POWER_HAPPINESS, feelty > 50000 ? (feelty-50000) : 0); + } + + _player->RemovePet((Pet*)pet, PET_SAVE_AS_DELETED); + } + else if (pet->GetGUID() == _player->GetCharmGUID()) + _player->StopCastingCharm(); + } +} + +void WorldSession::HandlePetSpellAutocastOpcode(WorldPacket& recvPacket) +{ + sLog->outDetail("CMSG_PET_SPELL_AUTOCAST"); + uint64 guid; + uint32 spellid; + uint8 state; //1 for on, 0 for off + recvPacket >> guid >> spellid >> state; + + if (!_player->GetGuardianPet() && !_player->GetCharm()) + return; + + if (ObjectAccessor::FindPlayer(guid)) + return; + + Creature* pet=ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); + + if (!pet || (pet != _player->GetGuardianPet() && pet != _player->GetCharm())) + { + sLog->outError("HandlePetSpellAutocastOpcode.Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)), GetPlayer()->GetName()); + return; + } + + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid); + // do not add not learned spells/ passive spells + if (!pet->HasSpell(spellid) || spellInfo->IsAutocastable()) + return; + + CharmInfo* charmInfo = pet->GetCharmInfo(); + if (!charmInfo) + { + sLog->outError("WorldSession::HandlePetSpellAutocastOpcod: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId()); + return; + } + + if (pet->isPet()) + ((Pet*)pet)->ToggleAutocast(spellInfo, state); + else + pet->GetCharmInfo()->ToggleCreatureAutocast(spellInfo, state); + + charmInfo->SetSpellAutocast(spellInfo, state); +} + +void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket) +{ + sLog->outDetail("WORLD: CMSG_PET_CAST_SPELL"); + + uint64 guid; + uint8 castCount; + uint32 spellId; + uint8 castFlags; + + recvPacket >> guid >> castCount >> spellId >> castFlags; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_PET_CAST_SPELL, guid: " UI64FMTD ", castCount: %u, spellId %u, castFlags %u", guid, castCount, spellId, castFlags); + + // This opcode is also sent from charmed and possessed units (players and creatures) + if (!_player->GetGuardianPet() && !_player->GetCharm()) + return; + + Unit* caster = ObjectAccessor::GetUnit(*_player, guid); + + if (!caster || (caster != _player->GetGuardianPet() && caster != _player->GetCharm())) + { + sLog->outError("HandlePetCastSpellOpcode: Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)), GetPlayer()->GetName()); + return; + } + + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + if (!spellInfo) + { + sLog->outError("WORLD: unknown PET spell id %i", spellId); + return; + } + + if (spellInfo->StartRecoveryCategory > 0) // Check if spell is affected by GCD + if (caster->GetTypeId() == TYPEID_UNIT && caster->GetCharmInfo() && caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) + { + caster->SendPetCastFail(spellId, SPELL_FAILED_NOT_READY); + return; + } + + // do not cast not learned spells + if (!caster->HasSpell(spellId) || spellInfo->IsPassive()) + return; + + SpellCastTargets targets; + targets.Read(recvPacket, caster); + HandleClientCastFlags(recvPacket, castFlags, targets); + + caster->ClearUnitState(UNIT_STAT_FOLLOW); + + Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE); + spell->m_cast_count = castCount; // probably pending spell cast + spell->m_targets = targets; + + // TODO: need to check victim? + SpellCastResult result; + if (caster->m_movedPlayer) + result = spell->CheckPetCast(caster->m_movedPlayer->GetSelectedUnit()); + else + result = spell->CheckPetCast(NULL); + if (result == SPELL_CAST_OK) + { + if (caster->GetTypeId() == TYPEID_UNIT) + { + Creature* pet = caster->ToCreature(); + pet->AddCreatureSpellCooldown(spellId); + if (pet->isPet()) + { + Pet* p = (Pet*)pet; + // 10% chance to play special pet attack talk, else growl + // actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell + if (p->getPetType() == SUMMON_PET && (urand(0, 100) < 10)) + pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL); + else + pet->SendPetAIReaction(guid); + } + } + + spell->prepare(&(spell->m_targets)); + } + else + { + caster->SendPetCastFail(spellId, result); + if (caster->GetTypeId() == TYPEID_PLAYER) + { + if (!caster->ToPlayer()->HasSpellCooldown(spellId)) + GetPlayer()->SendClearCooldown(spellId, caster); + } + else + { + if (!caster->ToCreature()->HasSpellCooldown(spellId)) + GetPlayer()->SendClearCooldown(spellId, caster); + } + + spell->finish(false); + delete spell; + } +} + +void WorldSession::SendPetNameInvalid(uint32 error, const std::string& name, DeclinedName *declinedName) +{ + WorldPacket data(SMSG_PET_NAME_INVALID, 4 + name.size() + 1 + 1); + data << uint32(error); + data << name; + if (declinedName) + { + data << uint8(1); + for (uint32 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) + data << declinedName->name[i]; + } + else + data << uint8(0); + SendPacket(&data); +} + +void WorldSession::HandlePetLearnTalent(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_PET_LEARN_TALENT"); + + uint64 guid; + uint32 talent_id, requested_rank; + recv_data >> guid >> talent_id >> requested_rank; + + _player->LearnPetTalent(guid, talent_id, requested_rank); + _player->SendTalentsInfoData(true); +} + +void WorldSession::HandleLearnPreviewTalentsPet(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LEARN_PREVIEW_TALENTS_PET"); + + uint64 guid; + recv_data >> guid; + + uint32 talentsCount; + recv_data >> talentsCount; + + uint32 talentId, talentRank; + + for (uint32 i = 0; i < talentsCount; ++i) + { + recv_data >> talentId >> talentRank; + + _player->LearnPetTalent(guid, talentId, talentRank); + } + + _player->SendTalentsInfoData(true); +} diff --git a/src/server/game/Handlers/PetitionsHandler.cpp b/src/server/game/Handlers/PetitionsHandler.cpp new file mode 100755 index 00000000000..26185d3376d --- /dev/null +++ b/src/server/game/Handlers/PetitionsHandler.cpp @@ -0,0 +1,937 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "Language.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "World.h" +#include "ObjectMgr.h" +#include "ArenaTeamMgr.h" +#include "GuildMgr.h" +#include "Log.h" +#include "Opcodes.h" +#include "Guild.h" +#include "ArenaTeam.h" +#include "GossipDef.h" +#include "SocialMgr.h" + +#define CHARTER_DISPLAY_ID 16161 + +/*enum PetitionType // dbc data +{ + PETITION_TYPE_GUILD = 1, + PETITION_TYPE_ARENA_TEAM = 3 +};*/ + +// Charters ID in item_template +enum CharterItemIDs +{ + GUILD_CHARTER = 5863, + ARENA_TEAM_CHARTER_2v2 = 23560, + ARENA_TEAM_CHARTER_3v3 = 23561, + ARENA_TEAM_CHARTER_5v5 = 23562 +}; + +enum CharterCosts +{ + GUILD_CHARTER_COST = 1000, + ARENA_TEAM_CHARTER_2v2_COST = 800000, + ARENA_TEAM_CHARTER_3v3_COST = 1200000, + ARENA_TEAM_CHARTER_5v5_COST = 2000000 +}; + +void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode CMSG_PETITION_BUY"); + + uint64 guidNPC; + uint32 clientIndex; // 1 for guild and arenaslot+1 for arenas in client + std::string name; + + recv_data >> guidNPC; // NPC GUID + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + recv_data >> name; // name + recv_data.read_skip(); // some string + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + recv_data.read_skip(); // 0 + + for (int i = 0; i < 10; ++i) + recv_data.read_skip(); + + recv_data >> clientIndex; // index + recv_data.read_skip(); // 0 + + sLog->outDebug(LOG_FILTER_NETWORKIO, "Petitioner with GUID %u tried sell petition: name %s", GUID_LOPART(guidNPC), name.c_str()); + + // prevent cheating + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guidNPC, UNIT_NPC_FLAG_PETITIONER); + if (!creature) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandlePetitionBuyOpcode - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(guidNPC)); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + uint32 charterid = 0; + uint32 cost = 0; + uint32 type = 0; + if (creature->isTabardDesigner()) + { + // if tabard designer, then trying to buy a guild charter. + // do not let if already in guild. + if (_player->GetGuildId()) + return; + + charterid = GUILD_CHARTER; + cost = GUILD_CHARTER_COST; + type = GUILD_CHARTER_TYPE; + } + else + { + // TODO: find correct opcode + if (_player->getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + SendNotification(LANG_ARENA_ONE_TOOLOW, sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)); + return; + } + + switch (clientIndex) // arenaSlot+1 as received from client (1 from 3 case) + { + case 1: + charterid = ARENA_TEAM_CHARTER_2v2; + cost = ARENA_TEAM_CHARTER_2v2_COST; + type = ARENA_TEAM_CHARTER_2v2_TYPE; + break; + case 2: + charterid = ARENA_TEAM_CHARTER_3v3; + cost = ARENA_TEAM_CHARTER_3v3_COST; + type = ARENA_TEAM_CHARTER_3v3_TYPE; + break; + case 3: + charterid = ARENA_TEAM_CHARTER_5v5; + cost = ARENA_TEAM_CHARTER_5v5_COST; + type = ARENA_TEAM_CHARTER_5v5_TYPE; + break; + default: + sLog->outDebug(LOG_FILTER_NETWORKIO, "unknown selection at buy arena petition: %u", clientIndex); + return; + } + + if (_player->GetArenaTeamId(clientIndex - 1)) // arenaSlot+1 as received from client + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM); + return; + } + } + + if (type == GUILD_CHARTER_TYPE) + { + if (sGuildMgr->GetGuildByName(name)) + { + Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NAME_EXISTS_S, name); + return; + } + if (sObjectMgr->IsReservedName(name) || !ObjectMgr::IsValidCharterName(name)) + { + Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NAME_INVALID, name); + return; + } + } + else + { + if (sArenaTeamMgr->GetArenaTeamByName(name)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S); + return; + } + if (sObjectMgr->IsReservedName(name) || !ObjectMgr::IsValidCharterName(name)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_INVALID); + return; + } + } + + ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(charterid); + if (!pProto) + { + _player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, NULL, charterid, 0); + return; + } + + if (!_player->HasEnoughMoney(cost)) + { //player hasn't got enough money + _player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, creature, charterid, 0); + return; + } + + ItemPosCountVec dest; + InventoryResult msg = _player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, charterid, pProto->BuyCount); + if (msg != EQUIP_ERR_OK) + { + _player->SendEquipError(msg, NULL, NULL, charterid); + return; + } + + _player->ModifyMoney(-(int32)cost); + Item* charter = _player->StoreNewItem(dest, charterid, true); + if (!charter) + return; + + charter->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1, charter->GetGUIDLow()); + // ITEM_FIELD_ENCHANTMENT_1_1 is guild/arenateam id + // ITEM_FIELD_ENCHANTMENT_1_1+1 is current signatures count (showed on item) + charter->SetState(ITEM_CHANGED, _player); + _player->SendNewItem(charter, 1, true, false); + + // a petition is invalid, if both the owner and the type matches + // we checked above, if this player is in an arenateam, so this must be + // datacorruption + QueryResult result = CharacterDatabase.PQuery("SELECT petitionguid FROM petition WHERE ownerguid = '%u' AND type = '%u'", _player->GetGUIDLow(), type); + + std::ostringstream ssInvalidPetitionGUIDs; + + if (result) + { + do + { + Field* fields = result->Fetch(); + ssInvalidPetitionGUIDs << '\'' << fields[0].GetUInt32() << "', "; + } while (result->NextRow()); + } + + // delete petitions with the same guid as this one + ssInvalidPetitionGUIDs << '\'' << charter->GetGUIDLow() << '\''; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "Invalid petition GUIDs: %s", ssInvalidPetitionGUIDs.str().c_str()); + CharacterDatabase.EscapeString(name); + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + trans->PAppend("DELETE FROM petition WHERE petitionguid IN (%s)", ssInvalidPetitionGUIDs.str().c_str()); + trans->PAppend("DELETE FROM petition_sign WHERE petitionguid IN (%s)", ssInvalidPetitionGUIDs.str().c_str()); + trans->PAppend("INSERT INTO petition (ownerguid, petitionguid, name, type) VALUES ('%u', '%u', '%s', '%u')", + _player->GetGUIDLow(), charter->GetGUIDLow(), name.c_str(), type); + CharacterDatabase.CommitTransaction(trans); +} + +void WorldSession::HandlePetitionShowSignOpcode(WorldPacket & recv_data) +{ + // ok + sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode CMSG_PETITION_SHOW_SIGNATURES"); + + uint8 signs = 0; + uint64 petitionguid; + recv_data >> petitionguid; // petition guid + + // solve (possible) some strange compile problems with explicit use GUID_LOPART(petitionguid) at some GCC versions (wrong code optimization in compiler?) + uint32 petitionguid_low = GUID_LOPART(petitionguid); + + QueryResult result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", petitionguid_low); + if (!result) + { + sLog->outError("Petition %u is not found for player %u %s", GUID_LOPART(petitionguid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName()); + return; + } + Field* fields = result->Fetch(); + uint32 type = fields[0].GetUInt8(); + + // if guild petition and has guild => error, return; + if (type == GUILD_CHARTER_TYPE && _player->GetGuildId()) + return; + + result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", petitionguid_low); + + // result == NULL also correct in case no sign yet + if (result) + signs = uint8(result->GetRowCount()); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_PETITION_SHOW_SIGNATURES petition entry: '%u'", petitionguid_low); + + WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (8+8+4+1+signs*12)); + data << uint64(petitionguid); // petition guid + data << uint64(_player->GetGUID()); // owner guid + data << uint32(petitionguid_low); // guild guid + data << uint8(signs); // sign's count + + for (uint8 i = 1; i <= signs; ++i) + { + Field* fields2 = result->Fetch(); + uint64 plguid = fields2[0].GetUInt64(); + + data << uint64(plguid); // Player GUID + data << uint32(0); // there 0 ... + + result->NextRow(); + } + SendPacket(&data); +} + +void WorldSession::HandlePetitionQueryOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode CMSG_PETITION_QUERY"); // ok + + uint32 guildguid; + uint64 petitionguid; + recv_data >> guildguid; // in Trinity always same as GUID_LOPART(petitionguid) + recv_data >> petitionguid; // petition guid + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_PETITION_QUERY Petition GUID %u Guild GUID %u", GUID_LOPART(petitionguid), guildguid); + + SendPetitionQueryOpcode(petitionguid); +} + +void WorldSession::SendPetitionQueryOpcode(uint64 petitionguid) +{ + uint64 ownerguid = 0; + uint32 type; + std::string name = "NO_NAME_FOR_GUID"; + + // TODO: Use CHAR_LOAD_PETITION PS + QueryResult result = CharacterDatabase.PQuery("SELECT ownerguid, name, type " + "FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); + + if (result) + { + Field* fields = result->Fetch(); + ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); + name = fields[1].GetString(); + type = fields[2].GetUInt32(); + } + else + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid)); + return; + } + + WorldPacket data(SMSG_PETITION_QUERY_RESPONSE, (4+8+name.size()+1+1+4*12+2+10)); + data << uint32(GUID_LOPART(petitionguid)); // guild/team guid (in Trinity always same as GUID_LOPART(petition guid) + data << uint64(ownerguid); // charter owner guid + data << name; // name (guild/arena team) + data << uint8(0); // some string + if (type == GUILD_CHARTER_TYPE) + { + data << uint32(9); + data << uint32(9); + data << uint32(0); // bypass client - side limitation, a different value is needed here for each petition + } + else + { + data << uint32(type-1); + data << uint32(type-1); + data << uint32(type); // bypass client - side limitation, a different value is needed here for each petition + } + data << uint32(0); // 5 + data << uint32(0); // 6 + data << uint32(0); // 7 + data << uint32(0); // 8 + data << uint16(0); // 9 2 bytes field + data << uint32(0); // 10 + data << uint32(0); // 11 + data << uint32(0); // 13 count of next strings? + + for (int i = 0; i < 10; ++i) + data << uint8(0); // some string + + data << uint32(0); // 14 + + if (type == GUILD_CHARTER_TYPE) + data << uint32(0); // 15 0 - guild, 1 - arena team + else + data << uint32(1); + + SendPacket(&data); +} + +void WorldSession::HandlePetitionRenameOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode MSG_PETITION_RENAME"); // ok + + uint64 petitionGuid; + uint32 type; + std::string newName; + + recv_data >> petitionGuid; // guid + recv_data >> newName; // new name + + Item* item = _player->GetItemByGuid(petitionGuid); + if (!item) + return; + + QueryResult result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionGuid)); + + if (result) + { + Field* fields = result->Fetch(); + type = fields[0].GetUInt8(); + } + else + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionGuid)); + return; + } + + if (type == GUILD_CHARTER_TYPE) + { + if (sGuildMgr->GetGuildByName(newName)) + { + Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NAME_EXISTS_S, newName); + return; + } + if (sObjectMgr->IsReservedName(newName) || !ObjectMgr::IsValidCharterName(newName)) + { + Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NAME_INVALID, newName); + return; + } + } + else + { + if (sArenaTeamMgr->GetArenaTeamByName(newName)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newName, "", ERR_ARENA_TEAM_NAME_EXISTS_S); + return; + } + if (sObjectMgr->IsReservedName(newName) || !ObjectMgr::IsValidCharterName(newName)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newName, "", ERR_ARENA_TEAM_NAME_INVALID); + return; + } + } + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PETITION_NAME); + + stmt->setString(0, newName); + stmt->setUInt32(1, GUID_LOPART(petitionGuid)); + + CharacterDatabase.Execute(stmt); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "Petition (GUID: %u) renamed to '%s'", GUID_LOPART(petitionGuid), newName.c_str()); + WorldPacket data(MSG_PETITION_RENAME, (8+newName.size()+1)); + data << uint64(petitionGuid); + data << newName; + SendPacket(&data); +} + +void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode CMSG_PETITION_SIGN"); // ok + + Field* fields; + uint64 petitionGuid; + uint8 unk; + recv_data >> petitionGuid; // petition guid + recv_data >> unk; + + QueryResult result = CharacterDatabase.PQuery( + "SELECT ownerguid, " + " (SELECT COUNT(playerguid) FROM petition_sign WHERE petition_sign.petitionguid = '%u') AS signs, " + " type " + "FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionGuid), GUID_LOPART(petitionGuid)); + + if (!result) + { + sLog->outError("Petition %u is not found for player %u %s", GUID_LOPART(petitionGuid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName()); + return; + } + + fields = result->Fetch(); + uint64 ownerGuid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); + uint8 signs = fields[1].GetUInt8(); + uint32 type = fields[2].GetUInt32(); + + uint32 playerGuid = _player->GetGUIDLow(); + if (GUID_LOPART(ownerGuid) == playerGuid) + return; + + // not let enemies sign guild charter + if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != sObjectMgr->GetPlayerTeamByGUID(ownerGuid)) + { + if (type != GUILD_CHARTER_TYPE) + SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); + else + Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NOT_ALLIED); + return; + } + + if (type != GUILD_CHARTER_TYPE) + { + if (_player->getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", _player->GetName(), ERR_ARENA_TEAM_TARGET_TOO_LOW_S); + return; + } + + uint8 slot = ArenaTeam::GetSlotByType(type); + if (slot >= MAX_ARENA_SLOT) + return; + + if (_player->GetArenaTeamId(slot)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_IN_ARENA_TEAM_S); + return; + } + + if (_player->GetArenaTeamIdInvited()) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S); + return; + } + } + else + { + if (_player->GetGuildId()) + { + Guild::SendCommandResult(this, GUILD_INVITE_S, ERR_ALREADY_IN_GUILD_S, _player->GetName()); + return; + } + if (_player->GetGuildIdInvited()) + { + Guild::SendCommandResult(this, GUILD_INVITE_S, ERR_ALREADY_INVITED_TO_GUILD_S, _player->GetName()); + return; + } + } + + if (++signs > type) // client signs maximum + return; + + //client doesn't allow to sign petition two times by one character, but not check sign by another character from same account + //not allow sign another player from already sign player account + result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE player_account = '%u' AND petitionguid = '%u'", GetAccountId(), GUID_LOPART(petitionGuid)); + + if (result) + { + WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4)); + data << uint64(petitionGuid); + data << uint64(_player->GetGUID()); + data << (uint32)PETITION_SIGN_ALREADY_SIGNED; + + // close at signer side + SendPacket(&data); + + // update for owner if online + if (Player* owner = ObjectAccessor::FindPlayer(ownerGuid)) + owner->GetSession()->SendPacket(&data); + return; + } + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PETITION_SIGNATURE); + + stmt->setUInt32(0, GUID_LOPART(ownerGuid)); + stmt->setUInt32(1, GUID_LOPART(petitionGuid)); + stmt->setUInt32(2, playerGuid); + stmt->setUInt32(3, GetAccountId()); + + CharacterDatabase.Execute(stmt); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "PETITION SIGN: GUID %u by player: %s (GUID: %u Account: %u)", GUID_LOPART(petitionGuid), _player->GetName(), playerGuid, GetAccountId()); + + WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4)); + data << uint64(petitionGuid); + data << uint64(_player->GetGUID()); + data << uint32(PETITION_SIGN_OK); + + // close at signer side + SendPacket(&data); + + // update signs count on charter, required testing... + //Item* item = _player->GetItemByGuid(petitionguid)); + //if (item) + // item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1+1, signs); + + // update for owner if online + if (Player* owner = ObjectAccessor::FindPlayer(ownerGuid)) + owner->GetSession()->SendPacket(&data); +} + +void WorldSession::HandlePetitionDeclineOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode MSG_PETITION_DECLINE"); // ok + + uint64 petitionguid; + uint64 ownerguid; + recv_data >> petitionguid; // petition guid + sLog->outDebug(LOG_FILTER_NETWORKIO, "Petition %u declined by %u", GUID_LOPART(petitionguid), _player->GetGUIDLow()); + + QueryResult result = CharacterDatabase.PQuery("SELECT ownerguid FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); + if (!result) + return; + + Field* fields = result->Fetch(); + ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); + + Player* owner = ObjectAccessor::FindPlayer(ownerguid); + if (owner) // petition owner online + { + WorldPacket data(MSG_PETITION_DECLINE, 8); + data << uint64(_player->GetGUID()); + owner->GetSession()->SendPacket(&data); + } +} + +void WorldSession::HandleOfferPetitionOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode CMSG_OFFER_PETITION"); // ok + + uint8 signs = 0; + uint64 petitionguid, plguid; + uint32 type, junk; + Player* player; + recv_data >> junk; // this is not petition type! + recv_data >> petitionguid; // petition guid + recv_data >> plguid; // player guid + + player = ObjectAccessor::FindPlayer(plguid); + if (!player) + return; + + QueryResult result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); + if (!result) + return; + + Field* fields = result->Fetch(); + type = fields[0].GetUInt8(); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "OFFER PETITION: type %u, GUID1 %u, to player id: %u", type, GUID_LOPART(petitionguid), GUID_LOPART(plguid)); + + if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != player->GetTeam()) + { + if (type != GUILD_CHARTER_TYPE) + SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); + else + Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NOT_ALLIED); + return; + } + + if (type != GUILD_CHARTER_TYPE) + { + if (player->getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + // player is too low level to join an arena team + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, player->GetName(), "", ERR_ARENA_TEAM_TARGET_TOO_LOW_S); + return; + } + + uint8 slot = ArenaTeam::GetSlotByType(type); + if (slot >= MAX_ARENA_SLOT) + return; + + if (player->GetArenaTeamId(slot)) + { + // player is already in an arena team + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, player->GetName(), "", ERR_ALREADY_IN_ARENA_TEAM_S); + return; + } + + if (player->GetArenaTeamIdInvited()) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S); + return; + } + } + else + { + if (player->GetGuildId()) + { + Guild::SendCommandResult(this, GUILD_INVITE_S, ERR_ALREADY_IN_GUILD_S, _player->GetName()); + return; + } + + if (player->GetGuildIdInvited()) + { + Guild::SendCommandResult(this, GUILD_INVITE_S, ERR_ALREADY_INVITED_TO_GUILD_S, _player->GetName()); + return; + } + } + + result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); + // result == NULL also correct charter without signs + if (result) + signs = uint8(result->GetRowCount()); + + WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (8+8+4+signs+signs*12)); + data << uint64(petitionguid); // petition guid + data << uint64(_player->GetGUID()); // owner guid + data << uint32(GUID_LOPART(petitionguid)); // guild guid + data << uint8(signs); // sign's count + + for (uint8 i = 1; i <= signs; ++i) + { + Field* fields2 = result->Fetch(); + plguid = fields2[0].GetUInt64(); + + data << uint64(plguid); // Player GUID + data << uint32(0); // there 0 ... + + result->NextRow(); + } + + player->GetSession()->SendPacket(&data); +} + +void WorldSession::HandleTurnInPetitionOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode CMSG_TURN_IN_PETITION"); + + // Get petition guid from packet + WorldPacket data; + uint64 petitionGuid; + + recv_data >> petitionGuid; + + // Check if player really has the required petition charter + Item* item = _player->GetItemByGuid(petitionGuid); + if (!item) + return; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "Petition %u turned in by %u", GUID_LOPART(petitionGuid), _player->GetGUIDLow()); + + // Get petition data from db + uint32 ownerguidlo; + uint32 type; + std::string name; + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION); + stmt->setUInt32(0, GUID_LOPART(petitionGuid)); + PreparedQueryResult result = CharacterDatabase.Query(stmt); + + if (result) + { + Field* fields = result->Fetch(); + ownerguidlo = fields[0].GetUInt32(); + name = fields[1].GetString(); + type = fields[2].GetUInt8(); + } + else + { + sLog->outError("Player %s (guid: %u) tried to turn in petition (guid: %u) that is not present in the database", _player->GetName(), _player->GetGUIDLow(), GUID_LOPART(petitionGuid)); + return; + } + + // Only the petition owner can turn in the petition + if (_player->GetGUIDLow() != ownerguidlo) + return; + + // Petition type (guild/arena) specific checks + if (type == GUILD_CHARTER_TYPE) + { + // Check if player is already in a guild + if (_player->GetGuildId()) + { + data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); + data << (uint32)PETITION_TURN_ALREADY_IN_GUILD; + _player->GetSession()->SendPacket(&data); + return; + } + + // Check if guild name is already taken + if (sGuildMgr->GetGuildByName(name)) + { + Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NAME_EXISTS_S, name); + return; + } + } + else + { + // Check for valid arena bracket (2v2, 3v3, 5v5) + uint8 slot = ArenaTeam::GetSlotByType(type); + if (slot >= MAX_ARENA_SLOT) + return; + + // Check if player is already in an arena team + if (_player->GetArenaTeamId(slot)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM); + return; + } + + // Check if arena team name is already taken + if (sArenaTeamMgr->GetArenaTeamByName(name)) + { + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S); + return; + } + } + + // Get petition signatures from db + uint8 signatures; + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_SIGNATURE); + stmt->setUInt32(0, GUID_LOPART(petitionGuid)); + result = CharacterDatabase.Query(stmt); + + if (result) + signatures = uint8(result->GetRowCount()); + else + signatures = 0; + + uint32 requiredSignatures; + if (type == GUILD_CHARTER_TYPE) + requiredSignatures = sWorld->getIntConfig(CONFIG_MIN_PETITION_SIGNS); + else + requiredSignatures = type-1; + + // Notify player if signatures are missing + if (signatures < requiredSignatures) + { + data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); + data << (uint32)PETITION_TURN_NEED_MORE_SIGNATURES; + SendPacket(&data); + return; + } + + // Proceed with guild/arena team creation + + // Delete charter item + _player->DestroyItem(item->GetBagSlot(), item->GetSlot(), true); + + if (type == GUILD_CHARTER_TYPE) + { + // Create guild + Guild* guild = new Guild; + + if (!guild->Create(_player, name)) + { + delete guild; + return; + } + + // Register guild and add guild master + sGuildMgr->AddGuild(guild); + + // Add members from signatures + for (uint8 i = 0; i < signatures; ++i) + { + Field* fields = result->Fetch(); + guild->AddMember(MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER)); + result->NextRow(); + } + } + else + { + // Receive the rest of the packet in arena team creation case + uint32 background, icon, iconcolor, border, bordercolor; + recv_data >> background >> icon >> iconcolor >> border >> bordercolor; + + // Create arena team + ArenaTeam* arenaTeam = new ArenaTeam(); + + if (!arenaTeam->Create(_player->GetGUID(), type, name, background, icon, iconcolor, border, bordercolor)) + { + delete arenaTeam; + return; + } + + // Register arena team + sArenaTeamMgr->AddArenaTeam(arenaTeam); + sLog->outDebug(LOG_FILTER_NETWORKIO, "PetitonsHandler: Arena team (guid: %u) added to ObjectMgr", arenaTeam->GetId()); + + // Add members + for (uint8 i = 0; i < signatures; ++i) + { + Field* fields = result->Fetch(); + uint32 memberGUID = fields[0].GetUInt32(); + sLog->outDebug(LOG_FILTER_NETWORKIO, "PetitionsHandler: Adding arena team (guid: %u) member %u", arenaTeam->GetId(), memberGUID); + arenaTeam->AddMember(MAKE_NEW_GUID(memberGUID, 0, HIGHGUID_PLAYER)); + result->NextRow(); + } + } + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + trans->PAppend("DELETE FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionGuid)); + trans->PAppend("DELETE FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionGuid)); + CharacterDatabase.CommitTransaction(trans); + + // created + sLog->outDebug(LOG_FILTER_NETWORKIO, "TURN IN PETITION GUID %u", GUID_LOPART(petitionGuid)); + + data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); + data << (uint32)PETITION_TURN_OK; + SendPacket(&data); +} + +void WorldSession::HandlePetitionShowListOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "Received CMSG_PETITION_SHOWLIST"); + + uint64 guid; + recv_data >> guid; + + SendPetitionShowList(guid); +} + +void WorldSession::SendPetitionShowList(uint64 guid) +{ + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_PETITIONER); + if (!creature) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandlePetitionShowListOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + WorldPacket data(SMSG_PETITION_SHOWLIST, 8+1+4*6); + data << guid; // npc guid + + if (creature->isTabardDesigner()) + { + data << uint8(1); // count + data << uint32(1); // index + data << uint32(GUILD_CHARTER); // charter entry + data << uint32(CHARTER_DISPLAY_ID); // charter display id + data << uint32(GUILD_CHARTER_COST); // charter cost + data << uint32(0); // unknown + data << uint32(9); // required signs? + } + else + { + data << uint8(3); // count + // 2v2 + data << uint32(1); // index + data << uint32(ARENA_TEAM_CHARTER_2v2); // charter entry + data << uint32(CHARTER_DISPLAY_ID); // charter display id + data << uint32(ARENA_TEAM_CHARTER_2v2_COST); // charter cost + data << uint32(2); // unknown + data << uint32(2); // required signs? + // 3v3 + data << uint32(2); // index + data << uint32(ARENA_TEAM_CHARTER_3v3); // charter entry + data << uint32(CHARTER_DISPLAY_ID); // charter display id + data << uint32(ARENA_TEAM_CHARTER_3v3_COST); // charter cost + data << uint32(3); // unknown + data << uint32(3); // required signs? + // 5v5 + data << uint32(3); // index + data << uint32(ARENA_TEAM_CHARTER_5v5); // charter entry + data << uint32(CHARTER_DISPLAY_ID); // charter display id + data << uint32(ARENA_TEAM_CHARTER_5v5_COST); // charter cost + data << uint32(5); // unknown + data << uint32(5); // required signs? + } + + SendPacket(&data); + sLog->outDebug(LOG_FILTER_NETWORKIO, "Sent SMSG_PETITION_SHOWLIST"); +} diff --git a/src/server/game/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp new file mode 100755 index 00000000000..5702eefffec --- /dev/null +++ b/src/server/game/Handlers/QueryHandler.cpp @@ -0,0 +1,477 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "Language.h" +#include "DatabaseEnv.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Opcodes.h" +#include "Log.h" +#include "World.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "UpdateMask.h" +#include "NPCHandler.h" +#include "Pet.h" +#include "MapManager.h" + +void WorldSession::SendNameQueryOpcode(uint64 guid) +{ + Player* player = NULL; + const CharacterNameData* nameData = sWorld->GetCharacterNameData(GUID_LOPART(guid)); + if (nameData) + player = ObjectAccessor::FindPlayer(guid); + + // guess size + WorldPacket data(SMSG_NAME_QUERY_RESPONSE, (8+1+1+1+1+1+10)); + data.appendPackGUID(guid); + data << uint8(0); // added in 3.1 + if (nameData) + { + data << nameData->m_name; // played name + data << uint8(0); // realm name for cross realm BG usage + data << uint8(nameData->m_race); + data << uint8(nameData->m_gender); + data << uint8(nameData->m_class); + } + else + { + data << std::string(GetTrinityString(LANG_NON_EXIST_CHARACTER)); + data << uint32(0); + } + + if (player) + { + if (DeclinedName const* names = player->GetDeclinedNames()) + { + data << uint8(1); // is declined + for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i) + data << names->name[i]; + } + else + data << uint8(0); // is not declined + } + else //TODO: decline names may also need to be stored in char name data + data << uint8(0); + + SendPacket(&data); +} + +void WorldSession::HandleNameQueryOpcode(WorldPacket& recv_data) +{ + uint64 guid; + + recv_data >> guid; + + // This is disable by default to prevent lots of console spam + // sLog->outString("HandleNameQueryOpcode %u", guid); + + SendNameQueryOpcode(guid); +} + +void WorldSession::HandleQueryTimeOpcode(WorldPacket & /*recv_data*/) +{ + SendQueryTimeResponse(); +} + +void WorldSession::SendQueryTimeResponse() +{ + WorldPacket data(SMSG_QUERY_TIME_RESPONSE, 4+4); + data << uint32(time(NULL)); + data << uint32(sWorld->GetNextDailyQuestsResetTime() - time(NULL)); + SendPacket(&data); +} + +/// Only _static_ data is sent in this packet !!! +void WorldSession::HandleCreatureQueryOpcode(WorldPacket & recv_data) +{ + uint32 entry; + recv_data >> entry; + uint64 guid; + recv_data >> guid; + + CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(entry); + if (ci) + { + + std::string Name, SubName; + Name = ci->Name; + SubName = ci->SubName; + + int loc_idx = GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + if (CreatureLocale const* cl = sObjectMgr->GetCreatureLocale(entry)) + { + ObjectMgr::GetLocaleString(cl->Name, loc_idx, Name); + ObjectMgr::GetLocaleString(cl->SubName, loc_idx, SubName); + } + } + sLog->outDetail("WORLD: CMSG_CREATURE_QUERY '%s' - Entry: %u.", ci->Name.c_str(), entry); + // guess size + WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 100); + data << uint32(entry); // creature entry + data << Name; + data << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4, always empty + data << SubName; + data << ci->IconName; // "Directions" for guard, string for Icons 2.3.0 + data << uint32(ci->type_flags); // flags + data << uint32(ci->type); // CreatureType.dbc + data << uint32(ci->family); // CreatureFamily.dbc + data << uint32(ci->rank); // Creature Rank (elite, boss, etc) + data << uint32(ci->KillCredit[0]); // new in 3.1, kill credit + data << uint32(ci->KillCredit[1]); // new in 3.1, kill credit + data << uint32(ci->Modelid1); // Modelid1 + data << uint32(ci->Modelid2); // Modelid2 + data << uint32(ci->Modelid3); // Modelid3 + data << uint32(ci->Modelid4); // Modelid4 + data << float(ci->ModHealth); // dmg/hp modifier + data << float(ci->ModMana); // dmg/mana modifier + data << uint8(ci->RacialLeader); + for (uint32 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i) + data << uint32(ci->questItems[i]); // itemId[6], quest drop + data << uint32(ci->movementId); // CreatureMovementInfo.dbc + SendPacket(&data); + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE"); + } + else + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CREATURE_QUERY - NO CREATURE INFO! (GUID: %u, ENTRY: %u)", + GUID_LOPART(guid), entry); + WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 4); + data << uint32(entry | 0x80000000); + SendPacket(&data); + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE"); + } +} + +/// Only _static_ data is sent in this packet !!! +void WorldSession::HandleGameObjectQueryOpcode(WorldPacket & recv_data) +{ + uint32 entry; + recv_data >> entry; + uint64 guid; + recv_data >> guid; + + const GameObjectTemplate* info = sObjectMgr->GetGameObjectTemplate(entry); + if (info) + { + std::string Name; + std::string IconName; + std::string CastBarCaption; + + Name = info->name; + IconName = info->IconName; + CastBarCaption = info->castBarCaption; + + int loc_idx = GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + if (GameObjectLocale const* gl = sObjectMgr->GetGameObjectLocale(entry)) + { + ObjectMgr::GetLocaleString(gl->Name, loc_idx, Name); + ObjectMgr::GetLocaleString(gl->CastBarCaption, loc_idx, CastBarCaption); + } + } + sLog->outDetail("WORLD: CMSG_GAMEOBJECT_QUERY '%s' - Entry: %u. ", info->name.c_str(), entry); + WorldPacket data (SMSG_GAMEOBJECT_QUERY_RESPONSE, 150); + data << uint32(entry); + data << uint32(info->type); + data << uint32(info->displayId); + data << Name; + data << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4 + data << IconName; // 2.0.3, string. Icon name to use instead of default icon for go's (ex: "Attack" makes sword) + data << CastBarCaption; // 2.0.3, string. Text will appear in Cast Bar when using GO (ex: "Collecting") + data << info->unk1; // 2.0.3, string + data.append(info->raw.data, 24); + data << float(info->size); // go size + for (uint32 i = 0; i < MAX_GAMEOBJECT_QUEST_ITEMS; ++i) + data << uint32(info->questItems[i]); // itemId[6], quest drop + SendPacket(&data); + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE"); + } + else + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_GAMEOBJECT_QUERY - Missing gameobject info for (GUID: %u, ENTRY: %u)", + GUID_LOPART(guid), entry); + WorldPacket data (SMSG_GAMEOBJECT_QUERY_RESPONSE, 4); + data << uint32(entry | 0x80000000); + SendPacket(&data); + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE"); + } +} + +void WorldSession::HandleCorpseQueryOpcode(WorldPacket & /*recv_data*/) +{ + sLog->outDetail("WORLD: Received MSG_CORPSE_QUERY"); + + Corpse* corpse = GetPlayer()->GetCorpse(); + + if (!corpse) + { + WorldPacket data(MSG_CORPSE_QUERY, 1); + data << uint8(0); // corpse not found + SendPacket(&data); + return; + } + + uint32 mapid = corpse->GetMapId(); + float x = corpse->GetPositionX(); + float y = corpse->GetPositionY(); + float z = corpse->GetPositionZ(); + uint32 corpsemapid = mapid; + + // if corpse at different map + if (mapid != _player->GetMapId()) + { + // search entrance map for proper show entrance + if (MapEntry const* corpseMapEntry = sMapStore.LookupEntry(mapid)) + { + if (corpseMapEntry->IsDungeon() && corpseMapEntry->entrance_map >= 0) + { + // if corpse map have entrance + if (Map const* entranceMap = sMapMgr->CreateBaseMap(corpseMapEntry->entrance_map)) + { + mapid = corpseMapEntry->entrance_map; + x = corpseMapEntry->entrance_x; + y = corpseMapEntry->entrance_y; + z = entranceMap->GetHeight(x, y, MAX_HEIGHT); + } + } + } + } + + WorldPacket data(MSG_CORPSE_QUERY, 1+(6*4)); + data << uint8(1); // corpse found + data << int32(mapid); + data << float(x); + data << float(y); + data << float(z); + data << int32(corpsemapid); + data << uint32(0); // unknown + SendPacket(&data); +} + +void WorldSession::HandleNpcTextQueryOpcode(WorldPacket & recv_data) +{ + uint32 textID; + uint64 guid; + + recv_data >> textID; + sLog->outDetail("WORLD: CMSG_NPC_TEXT_QUERY ID '%u'", textID); + + recv_data >> guid; + GetPlayer()->SetSelection(guid); + + GossipText const* pGossip = sObjectMgr->GetGossipText(textID); + + WorldPacket data(SMSG_NPC_TEXT_UPDATE, 100); // guess size + data << textID; + + if (!pGossip) + { + for (uint32 i = 0; i < MAX_GOSSIP_TEXT_OPTIONS; ++i) + { + data << float(0); + data << "Greetings $N"; + data << "Greetings $N"; + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + } + } + else + { + std::string Text_0[MAX_LOCALES], Text_1[MAX_LOCALES]; + for (int i = 0; i < MAX_GOSSIP_TEXT_OPTIONS; ++i) + { + Text_0[i]=pGossip->Options[i].Text_0; + Text_1[i]=pGossip->Options[i].Text_1; + } + + int loc_idx = GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + { + if (NpcTextLocale const* nl = sObjectMgr->GetNpcTextLocale(textID)) + { + for (int i = 0; i < MAX_LOCALES; ++i) + { + ObjectMgr::GetLocaleString(nl->Text_0[i], loc_idx, Text_0[i]); + ObjectMgr::GetLocaleString(nl->Text_1[i], loc_idx, Text_1[i]); + } + } + } + + for (int i = 0; i < MAX_GOSSIP_TEXT_OPTIONS; ++i) + { + data << pGossip->Options[i].Probability; + + if (Text_0[i].empty()) + data << Text_1[i]; + else + data << Text_0[i]; + + if (Text_1[i].empty()) + data << Text_0[i]; + else + data << Text_1[i]; + + data << pGossip->Options[i].Language; + + for (int j = 0; j < MAX_GOSSIP_TEXT_EMOTES; ++j) + { + data << pGossip->Options[i].Emotes[j]._Delay; + data << pGossip->Options[i].Emotes[j]._Emote; + } + } + } + + SendPacket(&data); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_NPC_TEXT_UPDATE"); +} + +/// Only _static_ data is sent in this packet !!! +void WorldSession::HandlePageTextQueryOpcode(WorldPacket & recv_data) +{ + sLog->outDetail("WORLD: Received CMSG_PAGE_TEXT_QUERY"); + + uint32 pageID; + recv_data >> pageID; + recv_data.read_skip(); // guid + + while (pageID) + { + PageText const* pageText = sObjectMgr->GetPageText(pageID); + // guess size + WorldPacket data(SMSG_PAGE_TEXT_QUERY_RESPONSE, 50); + data << pageID; + + if (!pageText) + { + data << "Item page missing."; + data << uint32(0); + pageID = 0; + } + else + { + std::string Text = pageText->Text; + + int loc_idx = GetSessionDbLocaleIndex(); + if (loc_idx >= 0) + if (PageTextLocale const* player = sObjectMgr->GetPageTextLocale(pageID)) + ObjectMgr::GetLocaleString(player->Text, loc_idx, Text); + + data << Text; + data << uint32(pageText->NextPage); + pageID = pageText->NextPage; + } + SendPacket(&data); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_PAGE_TEXT_QUERY_RESPONSE"); + } +} + +void WorldSession::HandleCorpseMapPositionQuery(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recv CMSG_CORPSE_MAP_POSITION_QUERY"); + + uint32 unk; + recv_data >> unk; + + WorldPacket data(SMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE, 4+4+4+4); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + SendPacket(&data); +} + +void WorldSession::HandleQuestPOIQuery(WorldPacket& recv_data) +{ + uint32 count; + recv_data >> count; // quest count, max=25 + + if (count >= MAX_QUEST_LOG_SIZE) + { + recv_data.rfinish(); + return; + } + + WorldPacket data(SMSG_QUEST_POI_QUERY_RESPONSE, 4+(4+4)*count); + data << uint32(count); // count + + for (uint32 i = 0; i < count; ++i) + { + uint32 questId; + recv_data >> questId; // quest id + + bool questOk = false; + + uint16 questSlot = _player->FindQuestSlot(questId); + + if (questSlot != MAX_QUEST_LOG_SIZE) + questOk =_player->GetQuestSlotQuestId(questSlot) == questId; + + if (questOk) + { + QuestPOIVector const* POI = sObjectMgr->GetQuestPOIVector(questId); + + if (POI) + { + data << uint32(questId); // quest ID + data << uint32(POI->size()); // POI count + + for (QuestPOIVector::const_iterator itr = POI->begin(); itr != POI->end(); ++itr) + { + data << uint32(itr->Id); // POI index + data << int32(itr->ObjectiveIndex); // objective index + data << uint32(itr->MapId); // mapid + data << uint32(itr->AreaId); // areaid + data << uint32(itr->Unk2); // unknown + data << uint32(itr->Unk3); // unknown + data << uint32(itr->Unk4); // unknown + data << uint32(itr->points.size()); // POI points count + + for (std::vector::const_iterator itr2 = itr->points.begin(); itr2 != itr->points.end(); ++itr2) + { + data << int32(itr2->x); // POI point x + data << int32(itr2->y); // POI point y + } + } + } + else + { + data << uint32(questId); // quest ID + data << uint32(0); // POI count + } + } + else + { + data << uint32(questId); // quest ID + data << uint32(0); // POI count + } + } + + SendPacket(&data); +} diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp new file mode 100755 index 00000000000..7e80c780369 --- /dev/null +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -0,0 +1,779 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "Log.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Opcodes.h" +#include "World.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "GossipDef.h" +#include "QuestDef.h" +#include "ObjectAccessor.h" +#include "Group.h" +#include "Battleground.h" +#include "BattlegroundAV.h" +#include "ScriptMgr.h" +#include "GameObjectAI.h" + +void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPacket & recv_data) +{ + uint64 guid; + recv_data >> guid; + uint8 questStatus = DIALOG_STATUS_NONE; + uint8 defstatus = DIALOG_STATUS_NONE; + + Object* questgiver = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); + if (!questgiver) + { + sLog->outDetail("Error in CMSG_QUESTGIVER_STATUS_QUERY, called for not found questgiver (Typeid: %u GUID: %u)", GuidHigh2TypeId(GUID_HIPART(guid)), GUID_LOPART(guid)); + return; + } + + switch (questgiver->GetTypeId()) + { + case TYPEID_UNIT: + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for npc, guid = %u", uint32(GUID_LOPART(guid))); + Creature* cr_questgiver=questgiver->ToCreature(); + if (!cr_questgiver->IsHostileTo(_player)) // not show quest status to enemies + { + questStatus = sScriptMgr->GetDialogStatus(_player, cr_questgiver); + if (questStatus > 6) + questStatus = getDialogStatus(_player, cr_questgiver, defstatus); + } + break; + } + case TYPEID_GAMEOBJECT: + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for GameObject guid = %u", uint32(GUID_LOPART(guid))); + GameObject* go_questgiver=(GameObject*)questgiver; + questStatus = sScriptMgr->GetDialogStatus(_player, go_questgiver); + if (questStatus > 6) + questStatus = getDialogStatus(_player, go_questgiver, defstatus); + break; + } + default: + sLog->outError("QuestGiver called for unexpected type %u", questgiver->GetTypeId()); + break; + } + + //inform client about status of quest + _player->PlayerTalkClass->SendQuestGiverStatus(questStatus, guid); +} + +void WorldSession::HandleQuestgiverHelloOpcode(WorldPacket & recv_data) +{ + uint64 guid; + recv_data >> guid; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_HELLO npc = %u", GUID_LOPART(guid)); + + Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); + if (!creature) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleQuestgiverHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.", + GUID_LOPART(guid)); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + // Stop the npc if moving + creature->StopMoving(); + + if (sScriptMgr->OnGossipHello(_player, creature)) + return; + + _player->PrepareGossipMenu(creature, creature->GetCreatureInfo()->GossipMenuId, true); + _player->SendPreparedGossip(creature); + + creature->AI()->sGossipHello(_player); +} + +void WorldSession::HandleQuestgiverAcceptQuestOpcode(WorldPacket & recv_data) +{ + uint64 guid; + uint32 quest; + uint32 unk1; + recv_data >> guid >> quest >> unk1; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_ACCEPT_QUEST npc = %u, quest = %u, unk1 = %u", uint32(GUID_LOPART(guid)), quest, unk1); + + Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT|TYPEMASK_ITEM|TYPEMASK_PLAYER); + + // no or incorrect quest giver + if (!pObject || (pObject->GetTypeId() != TYPEID_PLAYER && !pObject->hasQuest(quest)) || + (pObject->GetTypeId() == TYPEID_PLAYER && !pObject->ToPlayer()->CanShareQuest(quest))) + { + _player->PlayerTalkClass->SendCloseGossip(); + _player->SetDivider(0); + return; + } + + // some kind of WPE protection + if (!_player->CanInteractWithQuestGiver(pObject)) + return; + + Quest const* qInfo = sObjectMgr->GetQuestTemplate(quest); + if (qInfo) + { + // prevent cheating + if (!GetPlayer()->CanTakeQuest(qInfo, true)) + { + _player->PlayerTalkClass->SendCloseGossip(); + _player->SetDivider(0); + return; + } + + if (_player->GetDivider() != 0) + { + Player* player = ObjectAccessor::FindPlayer(_player->GetDivider()); + if (player) + { + player->SendPushToPartyResponse(_player, QUEST_PARTY_MSG_ACCEPT_QUEST); + _player->SetDivider(0); + } + } + + if (_player->CanAddQuest(qInfo, true)) + { + _player->AddQuest(qInfo, pObject); + + if (qInfo->HasFlag(QUEST_FLAGS_PARTY_ACCEPT)) + { + if (Group* group = _player->GetGroup()) + { + for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* player = itr->getSource(); + + if (!player || player == _player) // not self + continue; + + if (player->CanTakeQuest(qInfo, true)) + { + player->SetDivider(_player->GetGUID()); + + //need confirmation that any gossip window will close + player->PlayerTalkClass->SendCloseGossip(); + + _player->SendQuestConfirmAccept(qInfo, player); + } + } + } + } + + if (_player->CanCompleteQuest(quest)) + _player->CompleteQuest(quest); + + switch (pObject->GetTypeId()) + { + case TYPEID_UNIT: + sScriptMgr->OnQuestAccept(_player, (pObject->ToCreature()), qInfo); + (pObject->ToCreature())->AI()->sQuestAccept(_player, qInfo); + break; + case TYPEID_ITEM: + case TYPEID_CONTAINER: + { + sScriptMgr->OnQuestAccept(_player, ((Item*)pObject), qInfo); + + // destroy not required for quest finish quest starting item + bool destroyItem = true; + for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) + { + if ((qInfo->RequiredItemId[i] == ((Item*)pObject)->GetEntry()) && (((Item*)pObject)->GetTemplate()->MaxCount > 0)) + { + destroyItem = false; + break; + } + } + + if (destroyItem) + _player->DestroyItem(((Item*)pObject)->GetBagSlot(), ((Item*)pObject)->GetSlot(), true); + + break; + } + case TYPEID_GAMEOBJECT: + sScriptMgr->OnQuestAccept(_player, ((GameObject*)pObject), qInfo); + (pObject->ToGameObject())->AI()->QuestAccept(_player, qInfo); + break; + default: + break; + } + _player->PlayerTalkClass->SendCloseGossip(); + + if (qInfo->GetSrcSpell() > 0) + _player->CastSpell(_player, qInfo->GetSrcSpell(), true); + + return; + } + } + + _player->PlayerTalkClass->SendCloseGossip(); +} + +void WorldSession::HandleQuestgiverQueryQuestOpcode(WorldPacket & recv_data) +{ + uint64 guid; + uint32 questId; + uint8 unk1; + recv_data >> guid >> questId >> unk1; + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_QUERY_QUEST npc = %u, quest = %u, unk1 = %u", uint32(GUID_LOPART(guid)), questId, unk1); + + // Verify that the guid is valid and is a questgiver or involved in the requested quest + Object* object = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT | TYPEMASK_ITEM); + if (!object || (!object->hasQuest(questId) && !object->hasInvolvedQuest(questId))) + { + _player->PlayerTalkClass->SendCloseGossip(); + return; + } + + Quest const* quest = sObjectMgr->GetQuestTemplate(questId); + if (quest) + { + // not sure here what should happen to quests with QUEST_FLAGS_AUTOCOMPLETE + // if this breaks them, add && object->GetTypeId() == TYPEID_ITEM to this check + // item-started quests never have that flag + if (!_player->CanTakeQuest(quest, true)) + return; + + if (quest->IsAutoAccept() && _player->CanAddQuest(quest, true)) + { + _player->AddQuest(quest, object); + if (_player->CanCompleteQuest(questId)) + _player->CompleteQuest(questId); + } + + if (quest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE)) + _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, object->GetGUID(), _player->CanCompleteQuest(quest->GetQuestId()), true); + else + _player->PlayerTalkClass->SendQuestGiverQuestDetails(quest, object->GetGUID(), true); + } +} + +void WorldSession::HandleQuestQueryOpcode(WorldPacket & recv_data) +{ + if (!_player) + return; + + uint32 quest; + recv_data >> quest; + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUEST_QUERY quest = %u", quest); + + Quest const* pQuest = sObjectMgr->GetQuestTemplate(quest); + if (pQuest) + { + _player->PlayerTalkClass->SendQuestQueryResponse(pQuest); + } +} + +void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket & recv_data) +{ + uint32 questId, reward; + uint64 guid; + recv_data >> guid >> questId >> reward; + + if (reward >= QUEST_REWARD_CHOICES_COUNT) + { + sLog->outError("Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player %s (guid %d) tried to get invalid reward (%u) (probably packet hacking)", _player->GetName(), _player->GetGUIDLow(), reward); + return; + } + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_CHOOSE_REWARD npc = %u, quest = %u, reward = %u", uint32(GUID_LOPART(guid)), questId, reward); + + Object* object = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); + if (!object || !object->hasInvolvedQuest(questId)) + return; + + // some kind of WPE protection + if (!_player->CanInteractWithQuestGiver(object)) + return; + + if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId)) + { + if ((!_player->CanSeeStartQuest(quest) && _player->GetQuestStatus(questId) == QUEST_STATUS_NONE) || + (_player->GetQuestStatus(questId) != QUEST_STATUS_COMPLETE && !quest->IsAutoComplete())) + { + sLog->outError("HACK ALERT: Player %s (guid: %u) is trying to complete quest (id: %u) but he has no right to do it!", + _player->GetName(), _player->GetGUIDLow(), questId); + return; + } + if (_player->CanRewardQuest(quest, reward, true)) + { + _player->RewardQuest(quest, reward, object); + + switch (object->GetTypeId()) + { + case TYPEID_UNIT: + if (!(sScriptMgr->OnQuestReward(_player, (object->ToCreature()), quest, reward))) + { + // Send next quest + if (Quest const* nextQuest = _player->GetNextQuest(guid, quest)) + { + if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true) && _player->CanTakeQuest(quest, true)) + { + _player->AddQuest(nextQuest, object); + if (_player->CanCompleteQuest(nextQuest->GetQuestId())) + _player->CompleteQuest(nextQuest->GetQuestId()); + } + + _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true); + } + + (object->ToCreature())->AI()->sQuestReward(_player, quest, reward); + } + break; + case TYPEID_GAMEOBJECT: + if (!sScriptMgr->OnQuestReward(_player, ((GameObject*)object), quest, reward)) + { + // Send next quest + if (Quest const* nextQuest = _player->GetNextQuest(guid, quest)) + { + if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true) && _player->CanTakeQuest(quest, true)) + { + _player->AddQuest(nextQuest, object); + if (_player->CanCompleteQuest(nextQuest->GetQuestId())) + _player->CompleteQuest(nextQuest->GetQuestId()); + } + + _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true); + } + + object->ToGameObject()->AI()->QuestReward(_player, quest, reward); + } + break; + default: + break; + } + } + else + _player->PlayerTalkClass->SendQuestGiverOfferReward(quest, guid, true); + } +} + +void WorldSession::HandleQuestgiverRequestRewardOpcode(WorldPacket & recv_data) +{ + uint32 quest; + uint64 guid; + recv_data >> guid >> quest; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_REQUEST_REWARD npc = %u, quest = %u", uint32(GUID_LOPART(guid)), quest); + + Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); + if (!pObject || !pObject->hasInvolvedQuest(quest)) + return; + + // some kind of WPE protection + if (!_player->CanInteractWithQuestGiver(pObject)) + return; + + if (_player->CanCompleteQuest(quest)) + _player->CompleteQuest(quest); + + if (_player->GetQuestStatus(quest) != QUEST_STATUS_COMPLETE) + return; + + if (Quest const* pQuest = sObjectMgr->GetQuestTemplate(quest)) + _player->PlayerTalkClass->SendQuestGiverOfferReward(pQuest, guid, true); +} + +void WorldSession::HandleQuestgiverCancel(WorldPacket& /*recv_data*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_CANCEL"); + + _player->PlayerTalkClass->SendCloseGossip(); +} + +void WorldSession::HandleQuestLogSwapQuest(WorldPacket& recv_data) +{ + uint8 slot1, slot2; + recv_data >> slot1 >> slot2; + + if (slot1 == slot2 || slot1 >= MAX_QUEST_LOG_SIZE || slot2 >= MAX_QUEST_LOG_SIZE) + return; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTLOG_SWAP_QUEST slot 1 = %u, slot 2 = %u", slot1, slot2); + + GetPlayer()->SwapQuestSlot(slot1, slot2); +} + +void WorldSession::HandleQuestLogRemoveQuest(WorldPacket& recv_data) +{ + uint8 slot; + recv_data >> slot; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTLOG_REMOVE_QUEST slot = %u", slot); + + if (slot < MAX_QUEST_LOG_SIZE) + { + if (uint32 quest = _player->GetQuestSlotQuestId(slot)) + { + if (!_player->TakeQuestSourceItem(quest, true)) + return; // can't un-equip some items, reject quest cancel + + if (const Quest *pQuest = sObjectMgr->GetQuestTemplate(quest)) + { + if (pQuest->HasFlag(QUEST_TRINITY_FLAGS_TIMED)) + _player->RemoveTimedQuest(quest); + } + + _player->TakeQuestSourceItem(quest, true); // remove quest src item from player + _player->RemoveActiveQuest(quest); + _player->GetAchievementMgr().RemoveTimedAchievement(ACHIEVEMENT_TIMED_TYPE_QUEST, quest); + + sLog->outDetail("Player %u abandoned quest %u", _player->GetGUIDLow(), quest); + } + + _player->SetQuestSlot(slot, 0); + + _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED, 1); + } +} + +void WorldSession::HandleQuestConfirmAccept(WorldPacket& recv_data) +{ + uint32 quest; + recv_data >> quest; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUEST_CONFIRM_ACCEPT quest = %u", quest); + + if (const Quest* pQuest = sObjectMgr->GetQuestTemplate(quest)) + { + if (!pQuest->HasFlag(QUEST_FLAGS_PARTY_ACCEPT)) + return; + + Player* pOriginalPlayer = ObjectAccessor::FindPlayer(_player->GetDivider()); + + if (!pOriginalPlayer) + return; + + if (pQuest->IsRaidQuest()) + { + if (!_player->IsInSameRaidWith(pOriginalPlayer)) + return; + } + else + { + if (!_player->IsInSameGroupWith(pOriginalPlayer)) + return; + } + + if (_player->CanAddQuest(pQuest, true)) + _player->AddQuest(pQuest, NULL); // NULL, this prevent DB script from duplicate running + + _player->SetDivider(0); + } +} + +void WorldSession::HandleQuestgiverCompleteQuest(WorldPacket& recv_data) +{ + uint32 quest; + uint64 guid; + recv_data >> guid >> quest; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_COMPLETE_QUEST npc = %u, quest = %u", uint32(GUID_LOPART(guid)), quest); + + Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); + if (!pObject || !pObject->hasInvolvedQuest(quest)) + return; + + // some kind of WPE protection + if (!_player->CanInteractWithQuestGiver(pObject)) + return; + + Quest const* pQuest = sObjectMgr->GetQuestTemplate(quest); + if (pQuest) + { + if (!_player->CanSeeStartQuest(pQuest) && _player->GetQuestStatus(quest)==QUEST_STATUS_NONE) + { + sLog->outError("Possible hacking attempt: Player %s [guid: %u] tried to complete quest [entry: %u] without being in possession of the quest!", + _player->GetName(), _player->GetGUIDLow(), quest); + return; + } + // TODO: need a virtual function + if (_player->InBattleground()) + if (Battleground* bg = _player->GetBattleground()) + if (bg->GetTypeID() == BATTLEGROUND_AV) + ((BattlegroundAV*)bg)->HandleQuestComplete(quest, _player); + + if (_player->GetQuestStatus(quest) != QUEST_STATUS_COMPLETE) + { + if (pQuest->IsRepeatable()) + _player->PlayerTalkClass->SendQuestGiverRequestItems(pQuest, guid, _player->CanCompleteRepeatableQuest(pQuest), false); + else + _player->PlayerTalkClass->SendQuestGiverRequestItems(pQuest, guid, _player->CanRewardQuest(pQuest, false), false); + } + else + { + if (pQuest->GetReqItemsCount()) // some items required + _player->PlayerTalkClass->SendQuestGiverRequestItems(pQuest, guid, _player->CanRewardQuest(pQuest, false), false); + else // no items required + _player->PlayerTalkClass->SendQuestGiverOfferReward(pQuest, guid, true); + } + } +} + +void WorldSession::HandleQuestgiverQuestAutoLaunch(WorldPacket& /*recvPacket*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_QUEST_AUTOLAUNCH"); +} + +void WorldSession::HandlePushQuestToParty(WorldPacket& recvPacket) +{ + uint32 questId; + recvPacket >> questId; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_PUSHQUESTTOPARTY quest = %u", questId); + + if (Quest const* pQuest = sObjectMgr->GetQuestTemplate(questId)) + { + if (Group* group = _player->GetGroup()) + { + for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* player = itr->getSource(); + + if (!player || player == _player) // skip self + continue; + + _player->SendPushToPartyResponse(player, QUEST_PARTY_MSG_SHARING_QUEST); + + if (!player->SatisfyQuestStatus(pQuest, false)) + { + _player->SendPushToPartyResponse(player, QUEST_PARTY_MSG_HAVE_QUEST); + continue; + } + + if (player->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE) + { + _player->SendPushToPartyResponse(player, QUEST_PARTY_MSG_FINISH_QUEST); + continue; + } + + if (!player->CanTakeQuest(pQuest, false)) + { + _player->SendPushToPartyResponse(player, QUEST_PARTY_MSG_CANT_TAKE_QUEST); + continue; + } + + if (!player->SatisfyQuestLog(false)) + { + _player->SendPushToPartyResponse(player, QUEST_PARTY_MSG_LOG_FULL); + continue; + } + + if (player->GetDivider() != 0) + { + _player->SendPushToPartyResponse(player, QUEST_PARTY_MSG_BUSY); + continue; + } + + player->PlayerTalkClass->SendQuestGiverQuestDetails(pQuest, _player->GetGUID(), true); + player->SetDivider(_player->GetGUID()); + } + } + } +} + +void WorldSession::HandleQuestPushResult(WorldPacket& recvPacket) +{ + uint64 guid; + uint8 msg; + recvPacket >> guid >> msg; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received MSG_QUEST_PUSH_RESULT"); + + if (_player->GetDivider() != 0) + { + Player* player = ObjectAccessor::FindPlayer(_player->GetDivider()); + if (player) + { + WorldPacket data(MSG_QUEST_PUSH_RESULT, (8+1)); + data << uint64(guid); + data << uint8(msg); // valid values: 0-8 + player->GetSession()->SendPacket(&data); + _player->SetDivider(0); + } + } +} + +uint32 WorldSession::getDialogStatus(Player* player, Object* questgiver, uint32 defstatus) +{ + uint32 result = defstatus; + + QuestRelationBounds qr; + QuestRelationBounds qir; + + switch (questgiver->GetTypeId()) + { + case TYPEID_GAMEOBJECT: + { + qr = sObjectMgr->GetGOQuestRelationBounds(questgiver->GetEntry()); + qir = sObjectMgr->GetGOQuestInvolvedRelationBounds(questgiver->GetEntry()); + break; + } + case TYPEID_UNIT: + { + qr = sObjectMgr->GetCreatureQuestRelationBounds(questgiver->GetEntry()); + qir = sObjectMgr->GetCreatureQuestInvolvedRelationBounds(questgiver->GetEntry()); + break; + } + default: + //its imposible, but check ^) + sLog->outError("Warning: GetDialogStatus called for unexpected type %u", questgiver->GetTypeId()); + return DIALOG_STATUS_NONE; + } + + for (QuestRelations::const_iterator i = qir.first; i != qir.second; ++i) + { + uint32 result2 = 0; + uint32 quest_id = i->second; + Quest const* pQuest = sObjectMgr->GetQuestTemplate(quest_id); + if (!pQuest) continue; + + ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_QUEST_SHOW_MARK, pQuest->GetQuestId()); + if (!sConditionMgr->IsPlayerMeetToConditions(player, conditions)) + continue; + + QuestStatus status = player->GetQuestStatus(quest_id); + if ((status == QUEST_STATUS_COMPLETE && !player->GetQuestRewardStatus(quest_id)) || + (pQuest->IsAutoComplete() && player->CanTakeQuest(pQuest, false))) + { + if (pQuest->IsAutoComplete() && pQuest->IsRepeatable()) + result2 = DIALOG_STATUS_REWARD_REP; + else + result2 = DIALOG_STATUS_REWARD; + } + else if (status == QUEST_STATUS_INCOMPLETE) + result2 = DIALOG_STATUS_INCOMPLETE; + + if (result2 > result) + result = result2; + } + + for (QuestRelations::const_iterator i = qr.first; i != qr.second; ++i) + { + uint32 result2 = 0; + uint32 quest_id = i->second; + Quest const* pQuest = sObjectMgr->GetQuestTemplate(quest_id); + if (!pQuest) + continue; + + ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_QUEST_SHOW_MARK, pQuest->GetQuestId()); + if (!sConditionMgr->IsPlayerMeetToConditions(player, conditions)) + continue; + + QuestStatus status = player->GetQuestStatus(quest_id); + if (status == QUEST_STATUS_NONE) + { + if (player->CanSeeStartQuest(pQuest)) + { + if (player->SatisfyQuestLevel(pQuest, false)) + { + if (pQuest->IsAutoComplete() || (pQuest->IsRepeatable() && player->IsQuestRewarded(quest_id))) + result2 = DIALOG_STATUS_REWARD_REP; + else if (player->getLevel() <= ((player->GetQuestLevel(pQuest) == -1) ? player->getLevel() : player->GetQuestLevel(pQuest) + sWorld->getIntConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF))) + { + if (pQuest->HasFlag(QUEST_FLAGS_DAILY) || pQuest->HasFlag(QUEST_FLAGS_WEEKLY)) + result2 = DIALOG_STATUS_AVAILABLE_REP; + else + result2 = DIALOG_STATUS_AVAILABLE; + } + else + result2 = DIALOG_STATUS_LOW_LEVEL_AVAILABLE; + } + else + result2 = DIALOG_STATUS_UNAVAILABLE; + } + } + + if (result2 > result) + result = result2; + } + + return result; +} + +void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY"); + + uint32 count = 0; + + WorldPacket data(SMSG_QUESTGIVER_STATUS_MULTIPLE, 4); + data << uint32(count); // placeholder + + for (Player::ClientGUIDs::const_iterator itr = _player->m_clientGUIDs.begin(); itr != _player->m_clientGUIDs.end(); ++itr) + { + uint8 questStatus = DIALOG_STATUS_NONE; + uint8 defstatus = DIALOG_STATUS_NONE; + + if (IS_CRE_OR_VEH_OR_PET_GUID(*itr)) + { + // need also pet quests case support + Creature* questgiver = ObjectAccessor::GetCreatureOrPetOrVehicle(*GetPlayer(), *itr); + if (!questgiver || questgiver->IsHostileTo(_player)) + continue; + if (!questgiver->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER)) + continue; + questStatus = sScriptMgr->GetDialogStatus(_player, questgiver); + if (questStatus > 6) + questStatus = getDialogStatus(_player, questgiver, defstatus); + + data << uint64(questgiver->GetGUID()); + data << uint8(questStatus); + ++count; + } + else if (IS_GAMEOBJECT_GUID(*itr)) + { + GameObject* questgiver = GetPlayer()->GetMap()->GetGameObject(*itr); + if (!questgiver) + continue; + if (questgiver->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER) + continue; + questStatus = sScriptMgr->GetDialogStatus(_player, questgiver); + if (questStatus > 6) + questStatus = getDialogStatus(_player, questgiver, defstatus); + + data << uint64(questgiver->GetGUID()); + data << uint8(questStatus); + ++count; + } + } + + data.put(0, count); // write real count + SendPacket(&data); +} + +void WorldSession::HandleQueryQuestsCompleted(WorldPacket & /*recv_data*/) +{ + size_t rew_count = _player->GetRewardedQuestCount(); + + WorldPacket data(SMSG_QUERY_QUESTS_COMPLETED_RESPONSE, 4 + 4 * rew_count); + data << uint32(rew_count); + + const RewardedQuestSet &rewQuests = _player->getRewardedQuests(); + for (RewardedQuestSet::const_iterator itr = rewQuests.begin(); itr != rewQuests.end(); ++itr) + data << uint32(*itr); + + SendPacket(&data); +} diff --git a/src/server/game/Handlers/ReferAFriendHandler.cpp b/src/server/game/Handlers/ReferAFriendHandler.cpp new file mode 100644 index 00000000000..58d425ddf98 --- /dev/null +++ b/src/server/game/Handlers/ReferAFriendHandler.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2011 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "WorldSession.h" +#include "Player.h" +#include "ObjectMgr.h" +#include "Opcodes.h" +#include "Log.h" + +void WorldSession::HandleGrantLevel(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_GRANT_LEVEL"); + + uint64 guid; + recv_data.readPackGUID(guid); + + Player* target = ObjectAccessor::GetObjectInWorld(guid, _player); + + // check cheating + uint8 levels = _player->GetGrantableLevels(); + uint8 error = 0; + if (!target) + error = ERR_REFER_A_FRIEND_NO_TARGET; + else if (levels == 0) + error = ERR_REFER_A_FRIEND_INSUFFICIENT_GRANTABLE_LEVELS; + else if (GetRecruiterId() != target->GetSession()->GetAccountId()) + error = ERR_REFER_A_FRIEND_NOT_REFERRED_BY; + else if (target->GetTeamId() != _player->GetTeamId()) + error = ERR_REFER_A_FRIEND_DIFFERENT_FACTION; + else if (target->getLevel() >= _player->getLevel()) + error = ERR_REFER_A_FRIEND_TARGET_TOO_HIGH; + else if (target->getLevel() >= sWorld->getIntConfig(CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL)) + error = ERR_REFER_A_FRIEND_GRANT_LEVEL_MAX_I; + else if (target->GetGroup() != _player->GetGroup()) + error = ERR_REFER_A_FRIEND_NOT_IN_GROUP; + + if (error) { + WorldPacket data(SMSG_REFER_A_FRIEND_FAILURE, 24); + data << uint32(error); + if (error == ERR_REFER_A_FRIEND_NOT_IN_GROUP) + data << target->GetName(); + + SendPacket(&data); + return; + } + + WorldPacket data2(SMSG_PROPOSE_LEVEL_GRANT, 8); + data2.append(_player->GetPackGUID()); + target->GetSession()->SendPacket(&data2); +} + +void WorldSession::HandleAcceptGrantLevel(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_ACCEPT_LEVEL_GRANT"); + + uint64 guid; + recv_data.readPackGUID(guid); + + Player* other = ObjectAccessor::GetObjectInWorld(guid, _player); + if (!(other && other->GetSession())) + return; + + if (GetAccountId() != other->GetSession()->GetRecruiterId()) + return; + + if (other->GetGrantableLevels()) + other->SetGrantableLevels(other->GetGrantableLevels() - 1); + else + return; + + _player->GiveLevel(_player->getLevel() + 1); +} diff --git a/src/server/game/Handlers/SkillHandler.cpp b/src/server/game/Handlers/SkillHandler.cpp new file mode 100755 index 00000000000..520cd89e7d5 --- /dev/null +++ b/src/server/game/Handlers/SkillHandler.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "DatabaseEnv.h" +#include "Opcodes.h" +#include "Log.h" +#include "Player.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "ObjectAccessor.h" +#include "UpdateMask.h" + +void WorldSession::HandleLearnTalentOpcode(WorldPacket & recv_data) +{ + uint32 talent_id, requested_rank; + recv_data >> talent_id >> requested_rank; + + _player->LearnTalent(talent_id, requested_rank); + _player->SendTalentsInfoData(false); +} + +void WorldSession::HandleLearnPreviewTalents(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LEARN_PREVIEW_TALENTS"); + + uint32 talentsCount; + recvPacket >> talentsCount; + + uint32 talentId, talentRank; + + for (uint32 i = 0; i < talentsCount; ++i) + { + recvPacket >> talentId >> talentRank; + + _player->LearnTalent(talentId, talentRank); + } + + _player->SendTalentsInfoData(false); +} + +void WorldSession::HandleTalentWipeConfirmOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "MSG_TALENT_WIPE_CONFIRM"); + uint64 guid; + recv_data >> guid; + + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER); + if (!unit) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleTalentWipeConfirmOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + if (!(_player->resetTalents())) + { + WorldPacket data(MSG_TALENT_WIPE_CONFIRM, 8+4); //you have not any talent + data << uint64(0); + data << uint32(0); + SendPacket(&data); + return; + } + + _player->SendTalentsInfoData(false); + unit->CastSpell(_player, 14867, true); //spell: "Untalent Visual Effect" +} + +void WorldSession::HandleUnlearnSkillOpcode(WorldPacket & recv_data) +{ + uint32 skill_id; + recv_data >> skill_id; + GetPlayer()->SetSkill(skill_id, 0, 0, 0); +} + diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp new file mode 100755 index 00000000000..b8908d0f9f9 --- /dev/null +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -0,0 +1,686 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "DBCStores.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "ObjectMgr.h" +#include "SpellMgr.h" +#include "Log.h" +#include "Opcodes.h" +#include "Spell.h" +#include "Totem.h" +#include "TemporarySummon.h" +#include "SpellAuras.h" +#include "CreatureAI.h" +#include "ScriptMgr.h" +#include "GameObjectAI.h" +#include "SpellAuraEffects.h" + +void WorldSession::HandleClientCastFlags(WorldPacket& recvPacket, uint8 castFlags, SpellCastTargets& targets) +{ + // some spell cast packet including more data (for projectiles?) + if (castFlags & 0x02) + { + // not sure about these two + float elevation, speed; + recvPacket >> elevation; + recvPacket >> speed; + + targets.SetElevation(elevation); + targets.SetSpeed(speed); + + uint8 hasMovementData; + recvPacket >> hasMovementData; + if (hasMovementData) + { + recvPacket.rfinish(); + // movement packet for caster of the spell + /*recvPacket.read_skip(); // MSG_MOVE_STOP - hardcoded in client + uint64 guid; + recvPacket.readPackGUID(guid); + + MovementInfo movementInfo; + movementInfo.guid = guid; + ReadMovementInfo(recvPacket, &movementInfo);*/ + } + } +} + +void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) +{ + // TODO: add targets.read() check + Player* pUser = _player; + + // ignore for remote control state + if (pUser->m_mover != pUser) + return; + + uint8 bagIndex, slot, castFlags; + uint8 castCount; // next cast if exists (single or not) + uint64 itemGUID; + uint32 glyphIndex; // something to do with glyphs? + uint32 spellId; // casted spell id + + recvPacket >> bagIndex >> slot >> castCount >> spellId >> itemGUID >> glyphIndex >> castFlags; + + if (glyphIndex >= MAX_GLYPH_SLOT_INDEX) + { + pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; + } + + Item* pItem = pUser->GetUseableItemByPos(bagIndex, slot); + if (!pItem) + { + pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; + } + + if (pItem->GetGUID() != itemGUID) + { + pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; + } + + sLog->outDetail("WORLD: CMSG_USE_ITEM packet, bagIndex: %u, slot: %u, castCount: %u, spellId: %u, Item: %u, glyphIndex: %u, data length = %i", bagIndex, slot, castCount, spellId, pItem->GetEntry(), glyphIndex, (uint32)recvPacket.size()); + + ItemTemplate const* proto = pItem->GetTemplate(); + if (!proto) + { + pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL); + return; + } + + // some item classes can be used only in equipped state + if (proto->InventoryType != INVTYPE_NON_EQUIP && !pItem->IsEquipped()) + { + pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL); + return; + } + + InventoryResult msg = pUser->CanUseItem(pItem); + if (msg != EQUIP_ERR_OK) + { + pUser->SendEquipError(msg, pItem, NULL); + return; + } + + // only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB) + if (proto->Class == ITEM_CLASS_CONSUMABLE && !(proto->Flags & ITEM_PROTO_FLAG_USEABLE_IN_ARENA) && pUser->InArena()) + { + pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH, pItem, NULL); + return; + } + + // don't allow items banned in arena + if (proto->Flags & ITEM_PROTO_FLAG_NOT_USEABLE_IN_ARENA && pUser->InArena()) + { + pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH, pItem, NULL); + return; + } + + if (pUser->isInCombat()) + { + for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) + { + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(proto->Spells[i].SpellId)) + { + if (!spellInfo->CanBeUsedInCombat()) + { + pUser->SendEquipError(EQUIP_ERR_NOT_IN_COMBAT, pItem, NULL); + return; + } + } + } + } + + // check also BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory) + if (pItem->GetTemplate()->Bonding == BIND_WHEN_USE || pItem->GetTemplate()->Bonding == BIND_WHEN_PICKED_UP || pItem->GetTemplate()->Bonding == BIND_QUEST_ITEM) + { + if (!pItem->IsSoulBound()) + { + pItem->SetState(ITEM_CHANGED, pUser); + pItem->SetBinding(true); + } + } + + SpellCastTargets targets; + targets.Read(recvPacket, pUser); + HandleClientCastFlags(recvPacket, castFlags, targets); + + if (!pItem->IsTargetValidForItemUse(targets.GetUnitTarget())) + { + // free gray item after use fail + pUser->SendEquipError(EQUIP_ERR_NONE, pItem, NULL); + + // send spell error + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId)) + { + // for implicit area/coord target spells + if (!targets.GetUnitTarget()) + Spell::SendCastResult(_player, spellInfo, castCount, SPELL_FAILED_NO_VALID_TARGETS); + // for explicit target spells + else + Spell::SendCastResult(_player, spellInfo, castCount, SPELL_FAILED_BAD_TARGETS); + } + return; + } + + // Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state. + if (!sScriptMgr->OnItemUse(pUser, pItem, targets)) + { + // no script or script not process request by self + pUser->CastItemUseSpell(pItem, targets, castCount, glyphIndex); + } +} + +#define OPEN_CHEST 11437 +#define OPEN_SAFE 11535 +#define OPEN_CAGE 11792 +#define OPEN_BOOTY_CHEST 5107 +#define OPEN_STRONGBOX 8517 + +void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket) +{ + sLog->outDetail("WORLD: CMSG_OPEN_ITEM packet, data length = %i", (uint32)recvPacket.size()); + + Player* pUser = _player; + + // ignore for remote control state + if (pUser->m_mover != pUser) + return; + + uint8 bagIndex, slot; + + recvPacket >> bagIndex >> slot; + + sLog->outDetail("bagIndex: %u, slot: %u", bagIndex, slot); + + Item* item = pUser->GetItemByPos(bagIndex, slot); + if (!item) + { + pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; + } + + ItemTemplate const* proto = item->GetTemplate(); + if (!proto) + { + pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, item, NULL); + return; + } + + // Verify that the bag is an actual bag or wrapped item that can be used "normally" + if (!(proto->Flags & ITEM_PROTO_FLAG_OPENABLE) && !item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) + { + pUser->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, item, NULL); + sLog->outError("Possible hacking attempt: Player %s [guid: %u] tried to open item [guid: %u, entry: %u] which is not openable!", + pUser->GetName(), pUser->GetGUIDLow(), item->GetGUIDLow(), proto->ItemId); + return; + } + + // locked item + uint32 lockId = proto->LockID; + if (lockId) + { + LockEntry const* lockInfo = sLockStore.LookupEntry(lockId); + + if (!lockInfo) + { + pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, item, NULL); + sLog->outError("WORLD::OpenItem: item [guid = %u] has an unknown lockId: %u!", item->GetGUIDLow(), lockId); + return; + } + + // was not unlocked yet + if (item->IsLocked()) + { + pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, item, NULL); + return; + } + } + + if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED))// wrapped? + { + QueryResult result = CharacterDatabase.PQuery("SELECT entry, flags FROM character_gifts WHERE item_guid = '%u'", item->GetGUIDLow()); + if (result) + { + Field* fields = result->Fetch(); + uint32 entry = fields[0].GetUInt32(); + uint32 flags = fields[1].GetUInt32(); + + item->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, 0); + item->SetEntry(entry); + item->SetUInt32Value(ITEM_FIELD_FLAGS, flags); + item->SetState(ITEM_CHANGED, pUser); + } + else + { + sLog->outError("Wrapped item %u don't have record in character_gifts table and will deleted", item->GetGUIDLow()); + pUser->DestroyItem(item->GetBagSlot(), item->GetSlot(), true); + return; + } + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GIFT); + + stmt->setUInt32(0, item->GetGUIDLow()); + + CharacterDatabase.Execute(stmt); + } + else + pUser->SendLoot(item->GetGUID(), LOOT_CORPSE); +} + +void WorldSession::HandleGameObjectUseOpcode(WorldPacket & recv_data) +{ + uint64 guid; + + recv_data >> guid; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_GAMEOBJ_USE Message [guid=%u]", GUID_LOPART(guid)); + + // ignore for remote control state + if (_player->m_mover != _player) + return; + + if (GameObject* obj = GetPlayer()->GetMap()->GetGameObject(guid)) + obj->Use(_player); +} + +void WorldSession::HandleGameobjectReportUse(WorldPacket& recvPacket) +{ + uint64 guid; + recvPacket >> guid; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_GAMEOBJ_REPORT_USE Message [in game guid: %u]", GUID_LOPART(guid)); + + // ignore for remote control state + if (_player->m_mover != _player) + return; + + GameObject* go = GetPlayer()->GetMap()->GetGameObject(guid); + if (!go) + return; + + if (!go->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) + return; + + go->AI()->GossipHello(_player); + + _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT, go->GetEntry()); +} + +void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) +{ + uint32 spellId; + uint8 castCount, castFlags; + recvPacket >> castCount >> spellId >> castFlags; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: got cast spell packet, castCount: %u, spellId: %u, castFlags: %u, data length = %u", castCount, spellId, castFlags, (uint32)recvPacket.size()); + + // ignore for remote control state (for player case) + Unit* mover = _player->m_mover; + if (mover != _player && mover->GetTypeId() == TYPEID_PLAYER) + { + recvPacket.rfinish(); // prevent spam at ignore packet + return; + } + + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + + if (!spellInfo) + { + sLog->outError("WORLD: unknown spell id %u", spellId); + recvPacket.rfinish(); // prevent spam at ignore packet + return; + } + + if (mover->GetTypeId() == TYPEID_PLAYER) + { + // not have spell in spellbook or spell passive and not casted by client + if (!mover->ToPlayer()->HasActiveSpell (spellId) || spellInfo->IsPassive()) + { + //cheater? kick? ban? + recvPacket.rfinish(); // prevent spam at ignore packet + return; + } + } + else + { + // not have spell in spellbook or spell passive and not casted by client + if ((mover->GetTypeId() == TYPEID_UNIT && !mover->ToCreature()->HasSpell(spellId)) || spellInfo->IsPassive()) + { + //cheater? kick? ban? + recvPacket.rfinish(); // prevent spam at ignore packet + return; + } + } + + // Client is resending autoshot cast opcode when other spell is casted during shoot rotation + // Skip it to prevent "interrupt" message + if (spellInfo->IsAutoRepeatRangedSpell() && _player->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL) + && _player->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL)->m_spellInfo == spellInfo) + { + recvPacket.rfinish(); + return; + } + + // can't use our own spells when we're in possession of another unit, + if (_player->isPossessing()) + { + recvPacket.rfinish(); // prevent spam at ignore packet + return; + } + + // client provided targets + SpellCastTargets targets; + targets.Read(recvPacket, mover); + HandleClientCastFlags(recvPacket, castFlags, targets); + + // auto-selection buff level base at target level (in spellInfo) + if (targets.GetUnitTarget()) + { + SpellInfo const* actualSpellInfo = spellInfo->GetAuraRankForLevel(targets.GetUnitTarget()->getLevel()); + + // if rank not found then function return NULL but in explicit cast case original spell can be casted and later failed with appropriate error message + if (actualSpellInfo) + spellInfo = actualSpellInfo; + } + + Spell* spell = new Spell(mover, spellInfo, TRIGGERED_NONE, 0, false); + spell->m_cast_count = castCount; // set count of casts + spell->prepare(&targets); +} + +void WorldSession::HandleCancelCastOpcode(WorldPacket& recvPacket) +{ + uint32 spellId; + + recvPacket.read_skip(); // counter, increments with every CANCEL packet, don't use for now + recvPacket >> spellId; + + if (_player->IsNonMeleeSpellCasted(false)) + _player->InterruptNonMeleeSpells(false, spellId, false); +} + +void WorldSession::HandleCancelAuraOpcode(WorldPacket& recvPacket) +{ + uint32 spellId; + recvPacket >> spellId; + + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + if (!spellInfo) + return; + + // not allow remove spells with attr SPELL_ATTR0_CANT_CANCEL + if (spellInfo->Attributes & SPELL_ATTR0_CANT_CANCEL) + return; + + // channeled spell case (it currently casted then) + if (spellInfo->IsChanneled()) + { + if (Spell* curSpell = _player->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) + if (curSpell->m_spellInfo->Id == spellId) + _player->InterruptSpell(CURRENT_CHANNELED_SPELL); + return; + } + + // non channeled case: + // don't allow remove non positive spells + // don't allow cancelling passive auras (some of them are visible) + if (!spellInfo->IsPositive() || spellInfo->IsPassive()) + return; + + // maybe should only remove one buff when there are multiple? + _player->RemoveOwnedAura(spellId, 0, 0, AURA_REMOVE_BY_CANCEL); +} + +void WorldSession::HandlePetCancelAuraOpcode(WorldPacket& recvPacket) +{ + uint64 guid; + uint32 spellId; + + recvPacket >> guid; + recvPacket >> spellId; + + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + if (!spellInfo) + { + sLog->outError("WORLD: unknown PET spell id %u", spellId); + return; + } + + Creature* pet=ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); + + if (!pet) + { + sLog->outError("HandlePetCancelAura: Attempt to cancel an aura for non-existant pet %u by player '%s'", uint32(GUID_LOPART(guid)), GetPlayer()->GetName()); + return; + } + + if (pet != GetPlayer()->GetGuardianPet() && pet != GetPlayer()->GetCharm()) + { + sLog->outError("HandlePetCancelAura: Pet %u is not a pet of player '%s'", uint32(GUID_LOPART(guid)), GetPlayer()->GetName()); + return; + } + + if (!pet->isAlive()) + { + pet->SendPetActionFeedback(FEEDBACK_PET_DEAD); + return; + } + + pet->RemoveOwnedAura(spellId, 0, 0, AURA_REMOVE_BY_CANCEL); + + pet->AddCreatureSpellCooldown(spellId); +} + +void WorldSession::HandleCancelGrowthAuraOpcode(WorldPacket& /*recvPacket*/) +{ +} + +void WorldSession::HandleCancelAutoRepeatSpellOpcode(WorldPacket& /*recvPacket*/) +{ + // may be better send SMSG_CANCEL_AUTO_REPEAT? + // cancel and prepare for deleting + _player->InterruptSpell(CURRENT_AUTOREPEAT_SPELL); +} + +void WorldSession::HandleCancelChanneling(WorldPacket & recv_data) +{ + recv_data.read_skip(); // spellid, not used + + // ignore for remote control state (for player case) + Unit* mover = _player->m_mover; + if (mover != _player && mover->GetTypeId() == TYPEID_PLAYER) + return; + + mover->InterruptSpell(CURRENT_CHANNELED_SPELL); +} + +void WorldSession::HandleTotemDestroyed(WorldPacket& recvPacket) +{ + // ignore for remote control state + if (_player->m_mover != _player) + return; + + uint8 slotId; + + recvPacket >> slotId; + + ++slotId; + if (slotId >= MAX_TOTEM_SLOT) + return; + + if (!_player->m_SummonSlot[slotId]) + return; + + Creature* totem = GetPlayer()->GetMap()->GetCreature(_player->m_SummonSlot[slotId]); + // Don't unsummon sentry totem + if (totem && totem->isTotem() && totem->GetEntry() != SENTRY_TOTEM_ENTRY) + totem->ToTotem()->UnSummon(); +} + +void WorldSession::HandleSelfResOpcode(WorldPacket & /*recv_data*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_SELF_RES"); // empty opcode + + if (_player->HasAuraType(SPELL_AURA_PREVENT_RESURRECTION)) + return; // silent return, client should display error by itself and not send this opcode + + if (_player->GetUInt32Value(PLAYER_SELF_RES_SPELL)) + { + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(_player->GetUInt32Value(PLAYER_SELF_RES_SPELL)); + if (spellInfo) + _player->CastSpell(_player, spellInfo, false, 0); + + _player->SetUInt32Value(PLAYER_SELF_RES_SPELL, 0); + } +} + +void WorldSession::HandleSpellClick(WorldPacket& recv_data) +{ + uint64 guid; + recv_data >> guid; + + // this will get something not in world. crash + Creature* unit = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); + + if (!unit) + return; + + // TODO: Unit::SetCharmedBy: 28782 is not in world but 0 is trying to charm it! -> crash + if (!unit->IsInWorld()) + return; + + unit->HandleSpellClick(_player); +} + +void WorldSession::HandleMirrorImageDataRequest(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_GET_MIRRORIMAGE_DATA"); + uint64 guid; + recv_data >> guid; + + // Get unit for which data is needed by client + Unit* unit = ObjectAccessor::GetObjectInWorld(guid, (Unit*)NULL); + if (!unit) + return; + + if (!unit->HasAuraType(SPELL_AURA_CLONE_CASTER)) + return; + + // Get creator of the unit (SPELL_AURA_CLONE_CASTER does not stack) + Unit* creator = unit->GetAuraEffectsByType(SPELL_AURA_CLONE_CASTER).front()->GetCaster(); + if (!creator) + return; + + WorldPacket data(SMSG_MIRRORIMAGE_DATA, 68); + data << uint64(guid); + data << uint32(creator->GetDisplayId()); + data << uint8(creator->getRace()); + data << uint8(creator->getGender()); + data << uint8(creator->getClass()); + + if (creator->GetTypeId() == TYPEID_PLAYER) + { + Player* player = creator->ToPlayer(); + data << uint8(player->GetByteValue(PLAYER_BYTES, 0)); // skin + data << uint8(player->GetByteValue(PLAYER_BYTES, 1)); // face + data << uint8(player->GetByteValue(PLAYER_BYTES, 2)); // hair + data << uint8(player->GetByteValue(PLAYER_BYTES, 3)); // haircolor + data << uint8(player->GetByteValue(PLAYER_BYTES_2, 0)); // facialhair + data << uint32(player->GetGuildId()); // unk + + static EquipmentSlots const itemSlots[] = + { + EQUIPMENT_SLOT_HEAD, + EQUIPMENT_SLOT_SHOULDERS, + EQUIPMENT_SLOT_BODY, + EQUIPMENT_SLOT_CHEST, + EQUIPMENT_SLOT_WAIST, + EQUIPMENT_SLOT_LEGS, + EQUIPMENT_SLOT_FEET, + EQUIPMENT_SLOT_WRISTS, + EQUIPMENT_SLOT_HANDS, + EQUIPMENT_SLOT_BACK, + EQUIPMENT_SLOT_TABARD, + EQUIPMENT_SLOT_END + }; + + // Display items in visible slots + for (EquipmentSlots const* itr = &itemSlots[0]; *itr != EQUIPMENT_SLOT_END; ++itr) + { + if (*itr == EQUIPMENT_SLOT_HEAD && player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM)) + data << uint32(0); + else if (*itr == EQUIPMENT_SLOT_BACK && player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK)) + data << uint32(0); + else if (Item const* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, *itr)) + data << uint32(item->GetTemplate()->DisplayInfoID); + else + data << uint32(0); + } + } + else + { + // Skip player data for creatures + data << uint8(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + } + + SendPacket(&data); +} + +void WorldSession::HandleUpdateProjectilePosition(WorldPacket& recvPacket) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_UPDATE_PROJECTILE_POSITION"); + + uint64 casterGuid; + uint32 spellId; + uint8 castCount; + float x, y, z; // Position of missile hit + + recvPacket.readPackGUID(casterGuid); + recvPacket >> spellId; + recvPacket >> castCount; + recvPacket >> x; + recvPacket >> y; + recvPacket >> z; + + WorldPacket data(SMSG_SET_PROJECTILE_POSITION, 21); + data << uint64(casterGuid); + data << uint8(castCount); + data << float(x); + data << float(y); + data << float(z); + SendPacket(&data); +} diff --git a/src/server/game/Handlers/TaxiHandler.cpp b/src/server/game/Handlers/TaxiHandler.cpp new file mode 100755 index 00000000000..3533b153bd8 --- /dev/null +++ b/src/server/game/Handlers/TaxiHandler.cpp @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "DatabaseEnv.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Opcodes.h" +#include "Log.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "UpdateMask.h" +#include "Path.h" +#include "WaypointMovementGenerator.h" + +void WorldSession::HandleTaxiNodeStatusQueryOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_TAXINODE_STATUS_QUERY"); + + uint64 guid; + + recv_data >> guid; + SendTaxiStatus(guid); +} + +void WorldSession::SendTaxiStatus(uint64 guid) +{ + // cheating checks + Creature* unit = GetPlayer()->GetMap()->GetCreature(guid); + if (!unit) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WorldSession::SendTaxiStatus - Unit (GUID: %u) not found.", uint32(GUID_LOPART(guid))); + return; + } + + uint32 curloc = sObjectMgr->GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), GetPlayer()->GetTeam()); + + // not found nearest + if (curloc == 0) + return; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: current location %u ", curloc); + + WorldPacket data(SMSG_TAXINODE_STATUS, 9); + data << guid; + data << uint8(GetPlayer()->m_taxi.IsTaximaskNodeKnown(curloc) ? 1 : 0); + SendPacket(&data); + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_TAXINODE_STATUS"); +} + +void WorldSession::HandleTaxiQueryAvailableNodes(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_TAXIQUERYAVAILABLENODES"); + + uint64 guid; + recv_data >> guid; + + // cheating checks + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER); + if (!unit) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleTaxiQueryAvailableNodes - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + return; + } + + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + // unknown taxi node case + if (SendLearnNewTaxiNode(unit)) + return; + + // known taxi node case + SendTaxiMenu(unit); +} + +void WorldSession::SendTaxiMenu(Creature* unit) +{ + // find current node + uint32 curloc = sObjectMgr->GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), GetPlayer()->GetTeam()); + + if (curloc == 0) + return; + + bool lastTaxiCheaterState = GetPlayer()->isTaxiCheater(); + if (unit->GetEntry() == 29480) GetPlayer()->SetTaxiCheater(true); // Grimwing in Ebon Hold, special case. NOTE: Not perfect, Zul'Aman should not be included according to WoWhead, and I think taxicheat includes it. + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_TAXINODE_STATUS_QUERY %u ", curloc); + + WorldPacket data(SMSG_SHOWTAXINODES, (4+8+4+8*4)); + data << uint32(1); + data << uint64(unit->GetGUID()); + data << uint32(curloc); + GetPlayer()->m_taxi.AppendTaximaskTo(data, GetPlayer()->isTaxiCheater()); + SendPacket(&data); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_SHOWTAXINODES"); + + GetPlayer()->SetTaxiCheater(lastTaxiCheaterState); +} + +void WorldSession::SendDoFlight(uint32 mountDisplayId, uint32 path, uint32 pathNode) +{ + // remove fake death + if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + + while (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) + GetPlayer()->GetMotionMaster()->MovementExpired(false); + + if (mountDisplayId) + GetPlayer()->Mount(mountDisplayId); + + GetPlayer()->GetMotionMaster()->MoveTaxiFlight(path, pathNode); +} + +bool WorldSession::SendLearnNewTaxiNode(Creature* unit) +{ + // find current node + uint32 curloc = sObjectMgr->GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), GetPlayer()->GetTeam()); + + if (curloc == 0) + return true; // `true` send to avoid WorldSession::SendTaxiMenu call with one more curlock seartch with same false result. + + if (GetPlayer()->m_taxi.SetTaximaskNode(curloc)) + { + WorldPacket msg(SMSG_NEW_TAXI_PATH, 0); + SendPacket(&msg); + + WorldPacket update(SMSG_TAXINODE_STATUS, 9); + update << uint64(unit->GetGUID()); + update << uint8(1); + SendPacket(&update); + + return true; + } + else + return false; +} + +void WorldSession::SendDiscoverNewTaxiNode(uint32 nodeid) +{ + if (GetPlayer()->m_taxi.SetTaximaskNode(nodeid)) + { + WorldPacket msg(SMSG_NEW_TAXI_PATH, 0); + SendPacket(&msg); + } +} + +void WorldSession::HandleActivateTaxiExpressOpcode (WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_ACTIVATETAXIEXPRESS"); + + uint64 guid; + uint32 node_count; + + recv_data >> guid >> node_count; + + Creature* npc = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER); + if (!npc) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleActivateTaxiExpressOpcode - Unit (GUID: %u) not found or you can't interact with it.", uint32(GUID_LOPART(guid))); + return; + } + std::vector nodes; + + for (uint32 i = 0; i < node_count; ++i) + { + uint32 node; + recv_data >> node; + nodes.push_back(node); + } + + if (nodes.empty()) + return; + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_ACTIVATETAXIEXPRESS from %d to %d", nodes.front(), nodes.back()); + + GetPlayer()->ActivateTaxiPathTo(nodes, npc); +} + +void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_MOVE_SPLINE_DONE"); + + uint64 guid; // used only for proper packet read + recv_data.readPackGUID(guid); + + MovementInfo movementInfo; // used only for proper packet read + ReadMovementInfo(recv_data, &movementInfo); + + recv_data.read_skip(); // unk + + // in taxi flight packet received in 2 case: + // 1) end taxi path in far (multi-node) flight + // 2) switch from one map to other in case multim-map taxi path + // we need process only (1) + + uint32 curDest = GetPlayer()->m_taxi.GetTaxiDestination(); + if (!curDest) + return; + + TaxiNodesEntry const* curDestNode = sTaxiNodesStore.LookupEntry(curDest); + + // far teleport case + if (curDestNode && curDestNode->map_id != GetPlayer()->GetMapId()) + { + if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) + { + // short preparations to continue flight + FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top()); + + flight->SetCurrentNodeAfterTeleport(); + TaxiPathNodeEntry const& node = flight->GetPath()[flight->GetCurrentNode()]; + flight->SkipCurrentNode(); + + GetPlayer()->TeleportTo(curDestNode->map_id, node.x, node.y, node.z, GetPlayer()->GetOrientation()); + } + return; + } + + uint32 destinationnode = GetPlayer()->m_taxi.NextTaxiDestination(); + if (destinationnode > 0) // if more destinations to go + { + // current source node for next destination + uint32 sourcenode = GetPlayer()->m_taxi.GetTaxiSource(); + + // Add to taximask middle hubs in taxicheat mode (to prevent having player with disabled taxicheat and not having back flight path) + if (GetPlayer()->isTaxiCheater()) + { + if (GetPlayer()->m_taxi.SetTaximaskNode(sourcenode)) + { + WorldPacket data(SMSG_NEW_TAXI_PATH, 0); + _player->GetSession()->SendPacket(&data); + } + } + + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Taxi has to go from %u to %u", sourcenode, destinationnode); + + uint32 mountDisplayId = sObjectMgr->GetTaxiMountDisplayId(sourcenode, GetPlayer()->GetTeam()); + + uint32 path, cost; + sObjectMgr->GetTaxiPath(sourcenode, destinationnode, path, cost); + + if (path && mountDisplayId) + SendDoFlight(mountDisplayId, path, 1); // skip start fly node + else + GetPlayer()->m_taxi.ClearTaxiDestinations(); // clear problematic path and next + return; + } + else + GetPlayer()->m_taxi.ClearTaxiDestinations(); // not destinations, clear source node + + GetPlayer()->CleanupAfterTaxiFlight(); + GetPlayer()->SetFallInformation(0, GetPlayer()->GetPositionZ()); + if (GetPlayer()->pvpInfo.inHostileArea) + GetPlayer()->CastSpell(GetPlayer(), 2479, true); +} + +void WorldSession::HandleActivateTaxiOpcode(WorldPacket & recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_ACTIVATETAXI"); + + uint64 guid; + std::vector nodes; + nodes.resize(2); + + recv_data >> guid >> nodes[0] >> nodes[1]; + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_ACTIVATETAXI from %d to %d", nodes[0], nodes[1]); + Creature* npc = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER); + if (!npc) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleActivateTaxiOpcode - Unit (GUID: %u) not found or you can't interact with it.", uint32(GUID_LOPART(guid))); + return; + } + + GetPlayer()->ActivateTaxiPathTo(nodes, npc); +} diff --git a/src/server/game/Handlers/TicketHandler.cpp b/src/server/game/Handlers/TicketHandler.cpp new file mode 100755 index 00000000000..a270d42b000 --- /dev/null +++ b/src/server/game/Handlers/TicketHandler.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Language.h" +#include "WorldPacket.h" +#include "Common.h" +#include "ObjectMgr.h" +#include "TicketMgr.h" +#include "Player.h" +#include "World.h" +#include "WorldSession.h" +#include "Util.h" + +void WorldSession::HandleGMTicketCreateOpcode(WorldPacket & recv_data) +{ + // Don't accept tickets if the ticket queue is disabled. (Ticket UI is greyed out but not fully dependable) + if (sTicketMgr->GetStatus() == GMTICKET_QUEUE_STATUS_DISABLED) + return; + + if (GetPlayer()->getLevel() < sWorld->getIntConfig(CONFIG_TICKET_LEVEL_REQ)) + { + SendNotification(GetTrinityString(LANG_TICKET_REQ), sWorld->getIntConfig(CONFIG_TICKET_LEVEL_REQ)); + return; + } + + GMTicketResponse response = GMTICKET_RESPONSE_FAILURE; + // Player must not have ticket + if (!sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID())) + { + GmTicket* ticket = new GmTicket(GetPlayer(), recv_data); + sTicketMgr->AddTicket(ticket); + sTicketMgr->UpdateLastChange(); + + sWorld->SendGMText(LANG_COMMAND_TICKETNEW, GetPlayer()->GetName(), ticket->GetId()); + + response = GMTICKET_RESPONSE_SUCCESS; + } + + WorldPacket data(SMSG_GMTICKET_CREATE, 4); + data << uint32(response); + SendPacket(&data); +} + +void WorldSession::HandleGMTicketUpdateOpcode(WorldPacket & recv_data) +{ + std::string message; + recv_data >> message; + + GMTicketResponse response = GMTICKET_RESPONSE_FAILURE; + if (GmTicket *ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID())) + { + SQLTransaction trans = SQLTransaction(NULL); + ticket->SetMessage(message); + ticket->SaveToDB(trans); + + sWorld->SendGMText(LANG_COMMAND_TICKETUPDATED, GetPlayer()->GetName(), ticket->GetId()); + + response = GMTICKET_RESPONSE_SUCCESS; + } + + WorldPacket data(SMSG_GMTICKET_UPDATETEXT, 4); + data << uint32(response); + SendPacket(&data); +} + +void WorldSession::HandleGMTicketDeleteOpcode(WorldPacket & /*recv_data*/) +{ + if (GmTicket* ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID())) + { + WorldPacket data(SMSG_GMTICKET_DELETETICKET, 4); + data << uint32(GMTICKET_RESPONSE_TICKET_DELETED); + SendPacket(&data); + + sWorld->SendGMText(LANG_COMMAND_TICKETPLAYERABANDON, GetPlayer()->GetName(), ticket->GetId()); + + sTicketMgr->CloseTicket(ticket->GetId(), GetPlayer()->GetGUID()); + sTicketMgr->SendTicket(this, NULL); + } +} + +void WorldSession::HandleGMTicketGetTicketOpcode(WorldPacket & /*recv_data*/) +{ + SendQueryTimeResponse(); + + if (GmTicket* ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID())) + { + if (ticket->IsCompleted()) + ticket->SendResponse(this); + else + sTicketMgr->SendTicket(this, ticket); + } + else + sTicketMgr->SendTicket(this, NULL); +} + +void WorldSession::HandleGMTicketSystemStatusOpcode(WorldPacket & /*recv_data*/) +{ + // Note: This only disables the ticket UI at client side and is not fully reliable + // are we sure this is a uint32? Should ask Zor + WorldPacket data(SMSG_GMTICKET_SYSTEMSTATUS, 4); + data << uint32(sTicketMgr->GetStatus() ? GMTICKET_QUEUE_STATUS_ENABLED : GMTICKET_QUEUE_STATUS_DISABLED); + SendPacket(&data); +} + +void WorldSession::HandleGMSurveySubmit(WorldPacket& recv_data) +{ + uint32 nextSurveyID = sTicketMgr->GetNextSurveyID(); + // just put the survey into the database + uint32 mainSurvey; // GMSurveyCurrentSurvey.dbc, column 1 (all 9) ref to GMSurveySurveys.dbc + recv_data >> mainSurvey; + + // sub_survey1, r1, comment1, sub_survey2, r2, comment2, sub_survey3, r3, comment3, sub_survey4, r4, comment4, sub_survey5, r5, comment5, sub_survey6, r6, comment6, sub_survey7, r7, comment7, sub_survey8, r8, comment8, sub_survey9, r9, comment9, sub_survey10, r10, comment10, + for (uint8 i = 0; i < 10; i++) + { + uint32 subSurveyId; // ref to i'th GMSurveySurveys.dbc field (all fields in that dbc point to fields in GMSurveyQuestions.dbc) + recv_data >> subSurveyId; + if (!subSurveyId) + break; + + uint8 rank; // probably some sort of ref to GMSurveyAnswers.dbc + recv_data >> rank; + std::string comment; // comment ("Usage: GMSurveyAnswerSubmit(question, rank, comment)") + recv_data >> comment; + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GM_SUBSURVEY); + stmt->setUInt32(0, nextSurveyID); + stmt->setUInt32(1, subSurveyId); + stmt->setUInt32(2, rank); + stmt->setString(3, comment); + CharacterDatabase.Execute(stmt); + } + + std::string comment; // just a guess + recv_data >> comment; + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GM_SURVEY); + stmt->setUInt32(0, GUID_LOPART(GetPlayer()->GetGUID())); + stmt->setUInt32(1, nextSurveyID); + stmt->setUInt32(2, mainSurvey); + stmt->setString(3, comment); + + CharacterDatabase.Execute(stmt); +} + +void WorldSession::HandleReportLag(WorldPacket& recv_data) +{ + // just put the lag report into the database... + // can't think of anything else to do with it + uint32 lagType, mapId; + recv_data >> lagType; + recv_data >> mapId; + float x, y, z; + recv_data >> x; + recv_data >> y; + recv_data >> z; + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_LAG_REPORT); + stmt->setUInt32(0, GUID_LOPART(GetPlayer()->GetGUID())); + stmt->setUInt8 (1, lagType); + stmt->setUInt16(2, mapId); + stmt->setFloat (3, x); + stmt->setFloat (4, y); + stmt->setFloat (5, z); + CharacterDatabase.Execute(stmt); +} + +void WorldSession::HandleGMResponseResolve(WorldPacket& /*recvPacket*/) +{ + // empty packet + if (GmTicket* ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID())) + { + uint8 getSurvey = 0; + if (float(rand_chance()) < sWorld->getFloatConfig(CONFIG_CHANCE_OF_GM_SURVEY)) + getSurvey = 1; + + WorldPacket data(SMSG_GMRESPONSE_STATUS_UPDATE, 4); + data << uint8(getSurvey); + SendPacket(&data); + + WorldPacket data2(SMSG_GMTICKET_DELETETICKET, 4); + data2 << uint32(GMTICKET_RESPONSE_TICKET_DELETED); + SendPacket(&data2); + + sTicketMgr->CloseTicket(ticket->GetId(), GetPlayer()->GetGUID()); + sTicketMgr->SendTicket(this, NULL); + } +} diff --git a/src/server/game/Handlers/TradeHandler.cpp b/src/server/game/Handlers/TradeHandler.cpp new file mode 100755 index 00000000000..ebe54eb17eb --- /dev/null +++ b/src/server/game/Handlers/TradeHandler.cpp @@ -0,0 +1,731 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "World.h" +#include "ObjectAccessor.h" +#include "Log.h" +#include "Opcodes.h" +#include "Player.h" +#include "Item.h" +#include "Spell.h" +#include "SocialMgr.h" +#include "Language.h" +#include "AccountMgr.h" + +void WorldSession::SendTradeStatus(TradeStatus status) +{ + WorldPacket data; + + switch (status) + { + case TRADE_STATUS_BEGIN_TRADE: + data.Initialize(SMSG_TRADE_STATUS, 4+8); + data << uint32(status); + data << uint64(0); + break; + case TRADE_STATUS_OPEN_WINDOW: + data.Initialize(SMSG_TRADE_STATUS, 4+4); + data << uint32(status); + data << uint32(0); // added in 2.4.0 + break; + case TRADE_STATUS_CLOSE_WINDOW: + data.Initialize(SMSG_TRADE_STATUS, 4+4+1+4); + data << uint32(status); + data << uint32(0); + data << uint8(0); + data << uint32(0); + break; + case TRADE_STATUS_ONLY_CONJURED: + case TRADE_STATUS_NOT_ELIGIBLE: + data.Initialize(SMSG_TRADE_STATUS, 4+1); + data << uint32(status); + data << uint8(0); + break; + default: + data.Initialize(SMSG_TRADE_STATUS, 4); + data << uint32(status); + break; + } + + SendPacket(&data); +} + +void WorldSession::HandleIgnoreTradeOpcode(WorldPacket& /*recvPacket*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Ignore Trade %u", _player->GetGUIDLow()); + // recvPacket.print_storage(); +} + +void WorldSession::HandleBusyTradeOpcode(WorldPacket& /*recvPacket*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Busy Trade %u", _player->GetGUIDLow()); + // recvPacket.print_storage(); +} + +void WorldSession::SendUpdateTrade(bool trader_data /*= true*/) +{ + TradeData* view_trade = trader_data ? _player->GetTradeData()->GetTraderData() : _player->GetTradeData(); + + WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, 1+4+4+4+4+4+7*(1+4+4+4+4+8+4+4+4+4+8+4+4+4+4+4+4)); + data << uint8(trader_data); // 1 means traders data, 0 means own + data << uint32(0); // added in 2.4.0, this value must be equal to value from TRADE_STATUS_OPEN_WINDOW status packet (different value for different players to block multiple trades?) + data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = next field in most cases + data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = prev field in most cases + data << uint32(view_trade->GetMoney()); // trader gold + data << uint32(view_trade->GetSpell()); // spell casted on lowest slot item + + for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) + { + data << uint8(i); // trade slot number, if not specified, then end of packet + + if (Item* item = view_trade->GetItem(TradeSlots(i))) + { + data << uint32(item->GetTemplate()->ItemId); // entry + data << uint32(item->GetTemplate()->DisplayInfoID);// display id + data << uint32(item->GetCount()); // stack count + // wrapped: hide stats but show giftcreator name + data << uint32(item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED) ? 1 : 0); + data << uint64(item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR)); + // perm. enchantment and gems + data << uint32(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)); + for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot) + data << uint32(item->GetEnchantmentId(EnchantmentSlot(enchant_slot))); + // creator + data << uint64(item->GetUInt64Value(ITEM_FIELD_CREATOR)); + data << uint32(item->GetSpellCharges()); // charges + data << uint32(item->GetItemSuffixFactor()); // SuffixFactor + data << uint32(item->GetItemRandomPropertyId());// random properties id + data << uint32(item->GetTemplate()->LockID); // lock id + // max durability + data << uint32(item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)); + // durability + data << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY)); + } + else + { + for (uint8 j = 0; j < 18; ++j) + data << uint32(0); + } + } + SendPacket(&data); +} + +//============================================================== +// transfer the items to the players + +void WorldSession::moveItems(Item* myItems[], Item* hisItems[]) +{ + Player* trader = _player->GetTrader(); + if (!trader) + return; + + for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) + { + ItemPosCountVec traderDst; + ItemPosCountVec playerDst; + bool traderCanTrade = (myItems[i] == NULL || trader->CanStoreItem(NULL_BAG, NULL_SLOT, traderDst, myItems[i], false) == EQUIP_ERR_OK); + bool playerCanTrade = (hisItems[i] == NULL || _player->CanStoreItem(NULL_BAG, NULL_SLOT, playerDst, hisItems[i], false) == EQUIP_ERR_OK); + if (traderCanTrade && playerCanTrade) + { + // Ok, if trade item exists and can be stored + // If we trade in both directions we had to check, if the trade will work before we actually do it + // A roll back is not possible after we stored it + if (myItems[i]) + { + // logging + sLog->outDebug(LOG_FILTER_NETWORKIO, "partner storing: %u", myItems[i]->GetGUIDLow()); + if (!AccountMgr::IsPlayerAccount(_player->GetSession()->GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) + { + sLog->outCommand(_player->GetSession()->GetAccountId(), "GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)", + _player->GetName(), _player->GetSession()->GetAccountId(), + myItems[i]->GetTemplate()->Name1.c_str(), myItems[i]->GetEntry(), myItems[i]->GetCount(), + trader->GetName(), trader->GetSession()->GetAccountId()); + } + + // adjust time (depends on /played) + if (myItems[i]->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE)) + myItems[i]->SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, trader->GetTotalPlayedTime()-(_player->GetTotalPlayedTime()-myItems[i]->GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME))); + // store + trader->MoveItemToInventory(traderDst, myItems[i], true, true); + } + if (hisItems[i]) + { + // logging + sLog->outDebug(LOG_FILTER_NETWORKIO, "player storing: %u", hisItems[i]->GetGUIDLow()); + if (!AccountMgr::IsPlayerAccount(trader->GetSession()->GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) + { + sLog->outCommand(trader->GetSession()->GetAccountId(), "GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)", + trader->GetName(), trader->GetSession()->GetAccountId(), + hisItems[i]->GetTemplate()->Name1.c_str(), hisItems[i]->GetEntry(), hisItems[i]->GetCount(), + _player->GetName(), _player->GetSession()->GetAccountId()); + } + + // adjust time (depends on /played) + if (hisItems[i]->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE)) + hisItems[i]->SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, _player->GetTotalPlayedTime()-(trader->GetTotalPlayedTime()-hisItems[i]->GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME))); + // store + _player->MoveItemToInventory(playerDst, hisItems[i], true, true); + } + } + else + { + // in case of fatal error log error message + // return the already removed items to the original owner + if (myItems[i]) + { + if (!traderCanTrade) + sLog->outError("trader can't store item: %u", myItems[i]->GetGUIDLow()); + if (_player->CanStoreItem(NULL_BAG, NULL_SLOT, playerDst, myItems[i], false) == EQUIP_ERR_OK) + _player->MoveItemToInventory(playerDst, myItems[i], true, true); + else + sLog->outError("player can't take item back: %u", myItems[i]->GetGUIDLow()); + } + // return the already removed items to the original owner + if (hisItems[i]) + { + if (!playerCanTrade) + sLog->outError("player can't store item: %u", hisItems[i]->GetGUIDLow()); + if (trader->CanStoreItem(NULL_BAG, NULL_SLOT, traderDst, hisItems[i], false) == EQUIP_ERR_OK) + trader->MoveItemToInventory(traderDst, hisItems[i], true, true); + else + sLog->outError("trader can't take item back: %u", hisItems[i]->GetGUIDLow()); + } + } + } +} + +//============================================================== + +static void setAcceptTradeMode(TradeData* myTrade, TradeData* hisTrade, Item* *myItems, Item* *hisItems) +{ + myTrade->SetInAcceptProcess(true); + hisTrade->SetInAcceptProcess(true); + + // store items in local list and set 'in-trade' flag + for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) + { + if (Item* item = myTrade->GetItem(TradeSlots(i))) + { + sLog->outStaticDebug("player trade item %u bag: %u slot: %u", item->GetGUIDLow(), item->GetBagSlot(), item->GetSlot()); + //Can return NULL + myItems[i] = item; + myItems[i]->SetInTrade(); + } + + if (Item* item = hisTrade->GetItem(TradeSlots(i))) + { + sLog->outStaticDebug("partner trade item %u bag: %u slot: %u", item->GetGUIDLow(), item->GetBagSlot(), item->GetSlot()); + hisItems[i] = item; + hisItems[i]->SetInTrade(); + } + } +} + +static void clearAcceptTradeMode(TradeData* myTrade, TradeData* hisTrade) +{ + myTrade->SetInAcceptProcess(false); + hisTrade->SetInAcceptProcess(false); +} + +static void clearAcceptTradeMode(Item* *myItems, Item* *hisItems) +{ + // clear 'in-trade' flag + for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) + { + if (myItems[i]) + myItems[i]->SetInTrade(false); + if (hisItems[i]) + hisItems[i]->SetInTrade(false); + } +} + +void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) +{ + TradeData* my_trade = _player->m_trade; + if (!my_trade) + return; + + Player* trader = my_trade->GetTrader(); + + TradeData* his_trade = trader->m_trade; + if (!his_trade) + return; + + Item* myItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL }; + Item* hisItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL }; + bool myCanCompleteTrade = true, hisCanCompleteTrade = true; + + // set before checks for propertly undo at problems (it already set in to client) + my_trade->SetAccepted(true); + + // not accept case incorrect money amount + if (!_player->HasEnoughMoney(my_trade->GetMoney())) + { + SendNotification(LANG_NOT_ENOUGH_GOLD); + my_trade->SetAccepted(false, true); + return; + } + + // not accept case incorrect money amount + if (!trader->HasEnoughMoney(his_trade->GetMoney())) + { + trader->GetSession()->SendNotification(LANG_NOT_ENOUGH_GOLD); + his_trade->SetAccepted(false, true); + return; + } + + // not accept if some items now can't be trade (cheating) + for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) + { + if (Item* item = my_trade->GetItem(TradeSlots(i))) + { + if (!item->CanBeTraded(false, true)) + { + SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); + return; + } + if (item->IsBindedNotWith(trader)) + { + SendTradeStatus(TRADE_STATUS_NOT_ELIGIBLE); + SendTradeStatus(TRADE_STATUS_CLOSE_WINDOW/*TRADE_STATUS_TRADE_CANCELED*/); + return; + } + } + + if (Item* item = his_trade->GetItem(TradeSlots(i))) + { + if (!item->CanBeTraded(false, true)) + { + SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); + return; + } + //if (item->IsBindedNotWith(_player)) // dont mark as invalid when his item isnt good (not exploitable because if item is invalid trade will fail anyway later on the same check) + //{ + // SendTradeStatus(TRADE_STATUS_NOT_ELIGIBLE); + // his_trade->SetAccepted(false, true); + // return; + //} + } + } + + if (his_trade->IsAccepted()) + { + setAcceptTradeMode(my_trade, his_trade, myItems, hisItems); + + Spell* my_spell = NULL; + SpellCastTargets my_targets; + + Spell* his_spell = NULL; + SpellCastTargets his_targets; + + // not accept if spell can't be casted now (cheating) + if (uint32 my_spell_id = my_trade->GetSpell()) + { + SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(my_spell_id); + Item* castItem = my_trade->GetSpellCastItem(); + + if (!spellEntry || !his_trade->GetItem(TRADE_SLOT_NONTRADED) || + (my_trade->HasSpellCastItem() && !castItem)) + { + clearAcceptTradeMode(my_trade, his_trade); + clearAcceptTradeMode(myItems, hisItems); + + my_trade->SetSpell(0); + return; + } + + my_spell = new Spell(_player, spellEntry, TRIGGERED_FULL_MASK); + my_spell->m_CastItem = castItem; + my_targets.SetTradeItemTarget(_player); + my_spell->m_targets = my_targets; + + SpellCastResult res = my_spell->CheckCast(true); + if (res != SPELL_CAST_OK) + { + my_spell->SendCastResult(res); + + clearAcceptTradeMode(my_trade, his_trade); + clearAcceptTradeMode(myItems, hisItems); + + delete my_spell; + my_trade->SetSpell(0); + return; + } + } + + // not accept if spell can't be casted now (cheating) + if (uint32 his_spell_id = his_trade->GetSpell()) + { + SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(his_spell_id); + Item* castItem = his_trade->GetSpellCastItem(); + + if (!spellEntry || !my_trade->GetItem(TRADE_SLOT_NONTRADED) || (his_trade->HasSpellCastItem() && !castItem)) + { + delete my_spell; + his_trade->SetSpell(0); + + clearAcceptTradeMode(my_trade, his_trade); + clearAcceptTradeMode(myItems, hisItems); + return; + } + + his_spell = new Spell(trader, spellEntry, TRIGGERED_FULL_MASK); + his_spell->m_CastItem = castItem; + his_targets.SetTradeItemTarget(trader); + his_spell->m_targets = his_targets; + + SpellCastResult res = his_spell->CheckCast(true); + if (res != SPELL_CAST_OK) + { + his_spell->SendCastResult(res); + + clearAcceptTradeMode(my_trade, his_trade); + clearAcceptTradeMode(myItems, hisItems); + + delete my_spell; + delete his_spell; + + his_trade->SetSpell(0); + return; + } + } + + // inform partner client + trader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); + + // test if item will fit in each inventory + hisCanCompleteTrade = (trader->CanStoreItems(myItems, TRADE_SLOT_TRADED_COUNT) == EQUIP_ERR_OK); + myCanCompleteTrade = (_player->CanStoreItems(hisItems, TRADE_SLOT_TRADED_COUNT) == EQUIP_ERR_OK); + + clearAcceptTradeMode(myItems, hisItems); + + // in case of missing space report error + if (!myCanCompleteTrade) + { + clearAcceptTradeMode(my_trade, his_trade); + + SendNotification(LANG_NOT_FREE_TRADE_SLOTS); + trader->GetSession()->SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS); + my_trade->SetAccepted(false); + his_trade->SetAccepted(false); + return; + } + else if (!hisCanCompleteTrade) + { + clearAcceptTradeMode(my_trade, his_trade); + + SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS); + trader->GetSession()->SendNotification(LANG_NOT_FREE_TRADE_SLOTS); + my_trade->SetAccepted(false); + his_trade->SetAccepted(false); + return; + } + + // execute trade: 1. remove + for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) + { + if (myItems[i]) + { + myItems[i]->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, _player->GetGUID()); + _player->MoveItemFromInventory(myItems[i]->GetBagSlot(), myItems[i]->GetSlot(), true); + } + if (hisItems[i]) + { + hisItems[i]->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, trader->GetGUID()); + trader->MoveItemFromInventory(hisItems[i]->GetBagSlot(), hisItems[i]->GetSlot(), true); + } + } + + // execute trade: 2. store + moveItems(myItems, hisItems); + + // logging money + if (sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) + { + if (!AccountMgr::IsPlayerAccount(_player->GetSession()->GetSecurity()) && my_trade->GetMoney() > 0) + { + sLog->outCommand(_player->GetSession()->GetAccountId(), "GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", + _player->GetName(), _player->GetSession()->GetAccountId(), + my_trade->GetMoney(), + trader->GetName(), trader->GetSession()->GetAccountId()); + } + if (!AccountMgr::IsPlayerAccount(trader->GetSession()->GetSecurity()) && his_trade->GetMoney() > 0) + { + sLog->outCommand(trader->GetSession()->GetAccountId(), "GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", + trader->GetName(), trader->GetSession()->GetAccountId(), + his_trade->GetMoney(), + _player->GetName(), _player->GetSession()->GetAccountId()); + } + } + + // update money + _player->ModifyMoney(-int32(my_trade->GetMoney())); + _player->ModifyMoney(his_trade->GetMoney()); + trader->ModifyMoney(-int32(his_trade->GetMoney())); + trader->ModifyMoney(my_trade->GetMoney()); + + if (my_spell) + my_spell->prepare(&my_targets); + + if (his_spell) + his_spell->prepare(&his_targets); + + // cleanup + clearAcceptTradeMode(my_trade, his_trade); + delete _player->m_trade; + _player->m_trade = NULL; + delete trader->m_trade; + trader->m_trade = NULL; + + // desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards) + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + _player->SaveInventoryAndGoldToDB(trans); + trader->SaveInventoryAndGoldToDB(trans); + CharacterDatabase.CommitTransaction(trans); + + trader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE); + SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE); + } + else + { + trader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); + } +} + +void WorldSession::HandleUnacceptTradeOpcode(WorldPacket& /*recvPacket*/) +{ + TradeData* my_trade = _player->GetTradeData(); + if (!my_trade) + return; + + my_trade->SetAccepted(false, true); +} + +void WorldSession::HandleBeginTradeOpcode(WorldPacket& /*recvPacket*/) +{ + TradeData* my_trade = _player->m_trade; + if (!my_trade) + return; + + my_trade->GetTrader()->GetSession()->SendTradeStatus(TRADE_STATUS_OPEN_WINDOW); + SendTradeStatus(TRADE_STATUS_OPEN_WINDOW); +} + +void WorldSession::SendCancelTrade() +{ + if (m_playerRecentlyLogout) + return; + + SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); +} + +void WorldSession::HandleCancelTradeOpcode(WorldPacket& /*recvPacket*/) +{ + // sended also after LOGOUT COMPLETE + if (_player) // needed because STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT + _player->TradeCancel(true); +} + +void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket) +{ + if (GetPlayer()->m_trade) + { + recvPacket.rfinish(); + return; + } + + uint64 ID; + recvPacket >> ID; + + if (!GetPlayer()->isAlive()) + { + SendTradeStatus(TRADE_STATUS_YOU_DEAD); + return; + } + + if (GetPlayer()->HasUnitState(UNIT_STAT_STUNNED)) + { + SendTradeStatus(TRADE_STATUS_YOU_STUNNED); + return; + } + + if (isLogingOut()) + { + SendTradeStatus(TRADE_STATUS_YOU_LOGOUT); + return; + } + + if (GetPlayer()->isInFlight()) + { + SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); + return; + } + + if (GetPlayer()->getLevel() < sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)) + { + SendNotification(GetTrinityString(LANG_TRADE_REQ), sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)); + return; + } + + Player* pOther = ObjectAccessor::FindPlayer(ID); + + if (!pOther) + { + SendTradeStatus(TRADE_STATUS_NO_TARGET); + return; + } + + if (pOther == GetPlayer() || pOther->m_trade) + { + SendTradeStatus(TRADE_STATUS_BUSY); + return; + } + + if (!pOther->isAlive()) + { + SendTradeStatus(TRADE_STATUS_TARGET_DEAD); + return; + } + + if (pOther->isInFlight()) + { + SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); + return; + } + + if (pOther->HasUnitState(UNIT_STAT_STUNNED)) + { + SendTradeStatus(TRADE_STATUS_TARGET_STUNNED); + return; + } + + if (pOther->GetSession()->isLogingOut()) + { + SendTradeStatus(TRADE_STATUS_TARGET_LOGOUT); + return; + } + + if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) + { + SendTradeStatus(TRADE_STATUS_IGNORE_YOU); + return; + } + + if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) && pOther->GetTeam() !=_player->GetTeam()) + { + SendTradeStatus(TRADE_STATUS_WRONG_FACTION); + return; + } + + if (!pOther->IsWithinDistInMap(_player, 10.0f, false)) + { + SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); + return; + } + + if (pOther->getLevel() < sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)) + { + SendNotification(GetTrinityString(LANG_TRADE_OTHER_REQ), sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)); + return; + } + + // OK start trade + _player->m_trade = new TradeData(_player, pOther); + pOther->m_trade = new TradeData(pOther, _player); + + WorldPacket data(SMSG_TRADE_STATUS, 12); + data << uint32(TRADE_STATUS_BEGIN_TRADE); + data << uint64(_player->GetGUID()); + pOther->GetSession()->SendPacket(&data); +} + +void WorldSession::HandleSetTradeGoldOpcode(WorldPacket& recvPacket) +{ + uint32 gold; + recvPacket >> gold; + + TradeData* my_trade = _player->GetTradeData(); + if (!my_trade) + return; + + // gold can be incorrect, but this is checked at trade finished. + my_trade->SetMoney(gold); +} + +void WorldSession::HandleSetTradeItemOpcode(WorldPacket& recvPacket) +{ + // send update + uint8 tradeSlot; + uint8 bag; + uint8 slot; + + recvPacket >> tradeSlot; + recvPacket >> bag; + recvPacket >> slot; + + TradeData* my_trade = _player->GetTradeData(); + if (!my_trade) + return; + + // invalid slot number + if (tradeSlot >= TRADE_SLOT_COUNT) + { + SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); + return; + } + + // check cheating, can't fail with correct client operations + Item* item = _player->GetItemByPos(bag, slot); + if (!item || (tradeSlot != TRADE_SLOT_NONTRADED && !item->CanBeTraded(false, true))) + { + SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); + return; + } + + uint64 iGUID = item->GetGUID(); + + // prevent place single item into many trade slots using cheating and client bugs + if (my_trade->HasItem(iGUID)) + { + // cheating attempt + SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); + return; + } + + my_trade->SetItem(TradeSlots(tradeSlot), item); +} + +void WorldSession::HandleClearTradeItemOpcode(WorldPacket& recvPacket) +{ + uint8 tradeSlot; + recvPacket >> tradeSlot; + + TradeData* my_trade = _player->m_trade; + if (!my_trade) + return; + + // invalid slot number + if (tradeSlot >= TRADE_SLOT_COUNT) + return; + + my_trade->SetItem(TradeSlots(tradeSlot), NULL); +} + diff --git a/src/server/game/Handlers/VehicleHandler.cpp b/src/server/game/Handlers/VehicleHandler.cpp new file mode 100644 index 00000000000..ce4f6ccb8fe --- /dev/null +++ b/src/server/game/Handlers/VehicleHandler.cpp @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Opcodes.h" +#include "Vehicle.h" +#include "Player.h" +#include "Log.h" +#include "ObjectAccessor.h" + +void WorldSession::HandleDismissControlledVehicle(WorldPacket &recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_DISMISS_CONTROLLED_VEHICLE"); + + uint64 vehicleGUID = _player->GetCharmGUID(); + + if (!vehicleGUID) // something wrong here... + { + recv_data.rfinish(); // prevent warnings spam + return; + } + + uint64 guid; + + recv_data.readPackGUID(guid); + + MovementInfo mi; + mi.guid = guid; + ReadMovementInfo(recv_data, &mi); + + _player->m_movementInfo = mi; + + _player->ExitVehicle(); +} + +void WorldSession::HandleChangeSeatsOnControlledVehicle(WorldPacket &recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE"); + + Unit* vehicle_base = GetPlayer()->GetVehicleBase(); + if (!vehicle_base) + { + recv_data.rfinish(); // prevent warnings spam + return; + } + + VehicleSeatEntry const* seat = GetPlayer()->GetVehicle()->GetSeatForPassenger(GetPlayer()); + if (!seat->CanSwitchFromSeat()) + { + recv_data.rfinish(); // prevent warnings spam + sLog->outError("HandleChangeSeatsOnControlledVehicle, Opcode: %u, Player %u tried to switch seats but current seatflags %u don't permit that.", + recv_data.GetOpcode(), GetPlayer()->GetGUIDLow(), seat->m_flags); + return; + } + + switch (recv_data.GetOpcode()) + { + case CMSG_REQUEST_VEHICLE_PREV_SEAT: + GetPlayer()->ChangeSeat(-1, false); + break; + case CMSG_REQUEST_VEHICLE_NEXT_SEAT: + GetPlayer()->ChangeSeat(-1, true); + break; + case CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE: + { + uint64 guid; // current vehicle guid + recv_data.readPackGUID(guid); + + ReadMovementInfo(recv_data, &vehicle_base->m_movementInfo); + + uint64 accessory; // accessory guid + recv_data.readPackGUID(accessory); + + int8 seatId; + recv_data >> seatId; + + if (vehicle_base->GetGUID() != guid) + return; + + if (!accessory) + GetPlayer()->ChangeSeat(-1, seatId > 0); // prev/next + else if (Unit* vehUnit = Unit::GetUnit(*GetPlayer(), accessory)) + { + if (Vehicle* vehicle = vehUnit->GetVehicleKit()) + if (vehicle->HasEmptySeat(seatId)) + vehUnit->HandleSpellClick(GetPlayer(), seatId); + } + break; + } + case CMSG_REQUEST_VEHICLE_SWITCH_SEAT: + { + uint64 guid; // current vehicle guid + recv_data.readPackGUID(guid); + + int8 seatId; + recv_data >> seatId; + + if (vehicle_base->GetGUID() == guid) + GetPlayer()->ChangeSeat(seatId); + else if (Unit* vehUnit = Unit::GetUnit(*GetPlayer(), guid)) + if (Vehicle* vehicle = vehUnit->GetVehicleKit()) + if (vehicle->HasEmptySeat(seatId)) + vehUnit->HandleSpellClick(GetPlayer(), seatId); + break; + } + default: + break; + } +} + +void WorldSession::HandleEnterPlayerVehicle(WorldPacket &data) +{ + // Read guid + uint64 guid; + data >> guid; + + if (Player* player = ObjectAccessor::FindPlayer(guid)) + { + if (!player->GetVehicleKit()) + return; + if (!player->IsInRaidWith(_player)) + return; + if (!player->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) + return; + + _player->EnterVehicle(player); + } +} + +void WorldSession::HandleEjectPassenger(WorldPacket &data) +{ + Vehicle* vehicle = _player->GetVehicleKit(); + if (!vehicle) + { + data.rfinish(); // prevent warnings spam + sLog->outError("HandleEjectPassenger: Player %u is not in a vehicle!", GetPlayer()->GetGUIDLow()); + return; + } + + uint64 guid; + data >> guid; + + if (IS_PLAYER_GUID(guid)) + { + Player* player = ObjectAccessor::FindPlayer(guid); + if (!player) + { + sLog->outError("Player %u tried to eject player %u from vehicle, but the latter was not found in world!", GetPlayer()->GetGUIDLow(), GUID_LOPART(guid)); + return; + } + + if (!player->IsOnVehicle(vehicle->GetBase())) + { + sLog->outError("Player %u tried to eject player %u, but they are not in the same vehicle", GetPlayer()->GetGUIDLow(), GUID_LOPART(guid)); + return; + } + + VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(player); + ASSERT(seat); + if (seat->IsEjectable()) + player->ExitVehicle(); + else + sLog->outError("Player %u attempted to eject player %u from non-ejectable seat.", GetPlayer()->GetGUIDLow(), GUID_LOPART(guid)); + } + + else if (IS_CREATURE_GUID(guid)) + { + Unit* unit = ObjectAccessor::GetUnit(*_player, guid); + if (!unit) // creatures can be ejected too from player mounts + { + sLog->outError("Player %u tried to eject creature guid %u from vehicle, but the latter was not found in world!", GetPlayer()->GetGUIDLow(), GUID_LOPART(guid)); + return; + } + + if (!unit->IsOnVehicle(vehicle->GetBase())) + { + sLog->outError("Player %u tried to eject unit %u, but they are not in the same vehicle", GetPlayer()->GetGUIDLow(), GUID_LOPART(guid)); + return; + } + + VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(unit); + ASSERT(seat); + if (seat->IsEjectable()) + { + ASSERT(GetPlayer() == vehicle->GetBase()); + unit->ExitVehicle(); + } + else + sLog->outError("Player %u attempted to eject creature GUID %u from non-ejectable seat.", GetPlayer()->GetGUIDLow(), GUID_LOPART(guid)); + } + else + sLog->outError("HandleEjectPassenger: Player %u tried to eject invalid GUID "UI64FMTD, GetPlayer()->GetGUIDLow(), guid); +} + +void WorldSession::HandleRequestVehicleExit(WorldPacket& /*recv_data*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_REQUEST_VEHICLE_EXIT"); + + if (Vehicle* vehicle = GetPlayer()->GetVehicle()) + { + if (VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(GetPlayer())) + { + if (seat->CanEnterOrExit()) + GetPlayer()->ExitVehicle(); + else + sLog->outError("Player %u tried to exit vehicle, but seatflags %u (ID: %u) don't permit that.", + GetPlayer()->GetGUIDLow(), seat->m_ID, seat->m_flags); + } + } +} diff --git a/src/server/game/Handlers/VoiceChatHandler.cpp b/src/server/game/Handlers/VoiceChatHandler.cpp new file mode 100755 index 00000000000..34ad5ac3eae --- /dev/null +++ b/src/server/game/Handlers/VoiceChatHandler.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008-2012 TrinityCore + * Copyright (C) 2005-2009 MaNGOS + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Common.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Opcodes.h" +#include "Log.h" + +void WorldSession::HandleVoiceSessionEnableOpcode(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_VOICE_SESSION_ENABLE"); + // uint8 isVoiceEnabled, uint8 isMicrophoneEnabled + recv_data.read_skip(); + recv_data.read_skip(); +} + +void WorldSession::HandleChannelVoiceOnOpcode(WorldPacket& /*recv_data*/) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CHANNEL_VOICE_ON"); + // Enable Voice button in channel context menu +} + +void WorldSession::HandleSetActiveVoiceChannel(WorldPacket& recv_data) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_SET_ACTIVE_VOICE_CHANNEL"); + recv_data.read_skip(); + recv_data.read_skip(); +} + diff --git a/src/server/game/Server/Protocol/Handlers/AddonHandler.cpp b/src/server/game/Server/Protocol/Handlers/AddonHandler.cpp deleted file mode 100755 index ef537cb6198..00000000000 --- a/src/server/game/Server/Protocol/Handlers/AddonHandler.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "zlib.h" -#include "AddonHandler.h" -#include "DatabaseEnv.h" -#include "Opcodes.h" -#include "Log.h" - -AddonHandler::AddonHandler() -{ -} - -AddonHandler::~AddonHandler() -{ -} - -bool AddonHandler::BuildAddonPacket(WorldPacket* Source, WorldPacket* Target) -{ - ByteBuffer AddOnPacked; - uLongf AddonRealSize; - uint32 CurrentPosition; - uint32 TempValue; - - unsigned char tdata[256] = - { - 0xC3, 0x5B, 0x50, 0x84, 0xB9, 0x3E, 0x32, 0x42, 0x8C, 0xD0, 0xC7, 0x48, 0xFA, 0x0E, 0x5D, 0x54, - 0x5A, 0xA3, 0x0E, 0x14, 0xBA, 0x9E, 0x0D, 0xB9, 0x5D, 0x8B, 0xEE, 0xB6, 0x84, 0x93, 0x45, 0x75, - 0xFF, 0x31, 0xFE, 0x2F, 0x64, 0x3F, 0x3D, 0x6D, 0x07, 0xD9, 0x44, 0x9B, 0x40, 0x85, 0x59, 0x34, - 0x4E, 0x10, 0xE1, 0xE7, 0x43, 0x69, 0xEF, 0x7C, 0x16, 0xFC, 0xB4, 0xED, 0x1B, 0x95, 0x28, 0xA8, - 0x23, 0x76, 0x51, 0x31, 0x57, 0x30, 0x2B, 0x79, 0x08, 0x50, 0x10, 0x1C, 0x4A, 0x1A, 0x2C, 0xC8, - 0x8B, 0x8F, 0x05, 0x2D, 0x22, 0x3D, 0xDB, 0x5A, 0x24, 0x7A, 0x0F, 0x13, 0x50, 0x37, 0x8F, 0x5A, - 0xCC, 0x9E, 0x04, 0x44, 0x0E, 0x87, 0x01, 0xD4, 0xA3, 0x15, 0x94, 0x16, 0x34, 0xC6, 0xC2, 0xC3, - 0xFB, 0x49, 0xFE, 0xE1, 0xF9, 0xDA, 0x8C, 0x50, 0x3C, 0xBE, 0x2C, 0xBB, 0x57, 0xED, 0x46, 0xB9, - 0xAD, 0x8B, 0xC6, 0xDF, 0x0E, 0xD6, 0x0F, 0xBE, 0x80, 0xB3, 0x8B, 0x1E, 0x77, 0xCF, 0xAD, 0x22, - 0xCF, 0xB7, 0x4B, 0xCF, 0xFB, 0xF0, 0x6B, 0x11, 0x45, 0x2D, 0x7A, 0x81, 0x18, 0xF2, 0x92, 0x7E, - 0x98, 0x56, 0x5D, 0x5E, 0x69, 0x72, 0x0A, 0x0D, 0x03, 0x0A, 0x85, 0xA2, 0x85, 0x9C, 0xCB, 0xFB, - 0x56, 0x6E, 0x8F, 0x44, 0xBB, 0x8F, 0x02, 0x22, 0x68, 0x63, 0x97, 0xBC, 0x85, 0xBA, 0xA8, 0xF7, - 0xB5, 0x40, 0x68, 0x3C, 0x77, 0x86, 0x6F, 0x4B, 0xD7, 0x88, 0xCA, 0x8A, 0xD7, 0xCE, 0x36, 0xF0, - 0x45, 0x6E, 0xD5, 0x64, 0x79, 0x0F, 0x17, 0xFC, 0x64, 0xDD, 0x10, 0x6F, 0xF3, 0xF5, 0xE0, 0xA6, - 0xC3, 0xFB, 0x1B, 0x8C, 0x29, 0xEF, 0x8E, 0xE5, 0x34, 0xCB, 0xD1, 0x2A, 0xCE, 0x79, 0xC3, 0x9A, - 0x0D, 0x36, 0xEA, 0x01, 0xE0, 0xAA, 0x91, 0x20, 0x54, 0xF0, 0x72, 0xD8, 0x1E, 0xC7, 0x89, 0xD2 - }; - - // broken addon packet, can't be received from real client - if (Source->rpos() + 4 > Source->size()) - return false; - - *Source >> TempValue; // get real size of the packed structure - - // empty addon packet, nothing process, can't be received from real client - if (!TempValue) - return false; - - AddonRealSize = TempValue; // temp value because ZLIB only excepts uLongf - - CurrentPosition = Source->rpos(); // get the position of the pointer in the structure - - AddOnPacked.resize(AddonRealSize); // resize target for zlib action - - if (!uncompress(const_cast(AddOnPacked.contents()), &AddonRealSize, const_cast((*Source).contents() + CurrentPosition), (*Source).size() - CurrentPosition)!= Z_OK) - { - Target->Initialize(SMSG_ADDON_INFO); - - uint32 addonsCount; - AddOnPacked >> addonsCount; // addons count? - - for (uint32 i = 0; i < addonsCount; ++i) - { - std::string addonName; - uint8 enabled; - uint32 crc, unk2; - - // check next addon data format correctness - if (AddOnPacked.rpos()+1 > AddOnPacked.size()) - return false; - - AddOnPacked >> addonName; - - // recheck next addon data format correctness - if (AddOnPacked.rpos()+1+4+4 > AddOnPacked.size()) - return false; - - AddOnPacked >> enabled >> crc >> unk2; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "ADDON: Name: %s, Enabled: 0x%x, CRC: 0x%x, Unknown2: 0x%x", addonName.c_str(), enabled, crc, unk2); - - uint8 state = (enabled ? 2 : 1); - *Target << uint8(state); - - uint8 unk1 = (enabled ? 1 : 0); - *Target << uint8(unk1); - if (unk1) - { - uint8 unk = (crc != 0x4c1c776d); // If addon is Standard addon CRC - *Target << uint8(unk); - if (unk) - Target->append(tdata, sizeof(tdata)); - - *Target << uint32(0); - } - - uint8 unk3 = (enabled ? 0 : 1); - *Target << uint8(unk3); - if (unk3) - { - // String, 256 (null terminated?) - *Target << uint8(0); - } - } - - uint32 unk4; - AddOnPacked >> unk4; - - uint32 count = 0; - *Target << uint32(count); - - if (AddOnPacked.rpos() != AddOnPacked.size()) - sLog->outDebug(LOG_FILTER_NETWORKIO, "packet under read!"); - } - else - { - sLog->outError("Addon packet uncompress error :("); - return false; - } - return true; -} diff --git a/src/server/game/Server/Protocol/Handlers/AddonHandler.h b/src/server/game/Server/Protocol/Handlers/AddonHandler.h deleted file mode 100755 index 36cb19e5698..00000000000 --- a/src/server/game/Server/Protocol/Handlers/AddonHandler.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef __ADDONHANDLER_H -#define __ADDONHANDLER_H - -#include "Common.h" -#include "Config.h" -#include -#include "WorldPacket.h" - -class AddonHandler -{ - /* Construction */ - friend class ACE_Singleton; - AddonHandler(); - - public: - ~AddonHandler(); - //build addon packet - bool BuildAddonPacket(WorldPacket* Source, WorldPacket* Target); -}; -#define sAddOnHandler ACE_Singleton::instance() -#endif - diff --git a/src/server/game/Server/Protocol/Handlers/ArenaTeamHandler.cpp b/src/server/game/Server/Protocol/Handlers/ArenaTeamHandler.cpp deleted file mode 100755 index 8fb820713ce..00000000000 --- a/src/server/game/Server/Protocol/Handlers/ArenaTeamHandler.cpp +++ /dev/null @@ -1,408 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Player.h" -#include "World.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "DatabaseEnv.h" - -#include "ArenaTeam.h" -#include "Log.h" -#include "ObjectMgr.h" -#include "SocialMgr.h" -#include "ArenaTeamMgr.h" - -void WorldSession::HandleInspectArenaTeamsOpcode(WorldPacket & recvData) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "MSG_INSPECT_ARENA_TEAMS"); - - uint64 guid; - recvData >> guid; - sLog->outDebug(LOG_FILTER_NETWORKIO, "Inspect Arena stats (GUID: %u TypeId: %u)", GUID_LOPART(guid), GuidHigh2TypeId(GUID_HIPART(guid))); - - if (Player* player = ObjectAccessor::FindPlayer(guid)) - { - for (uint8 i = 0; i < MAX_ARENA_SLOT; ++i) - { - if (uint32 a_id = player->GetArenaTeamId(i)) - { - if (ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(a_id)) - arenaTeam->Inspect(this, player->GetGUID()); - } - } - } -} - -void WorldSession::HandleArenaTeamQueryOpcode(WorldPacket & recvData) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_ARENA_TEAM_QUERY"); - - uint32 arenaTeamId; - recvData >> arenaTeamId; - - if (ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId)) - { - arenaTeam->Query(this); - arenaTeam->SendStats(this); - } -} - -void WorldSession::HandleArenaTeamRosterOpcode(WorldPacket & recvData) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_ARENA_TEAM_ROSTER"); - - uint32 arenaTeamId; // arena team id - recvData >> arenaTeamId; - - if (ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId)) - arenaTeam->Roster(this); -} - -void WorldSession::HandleArenaTeamInviteOpcode(WorldPacket & recvData) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_ARENA_TEAM_INVITE"); - - uint32 arenaTeamId; // arena team id - std::string invitedName; - - Player* player = NULL; - - recvData >> arenaTeamId >> invitedName; - - if (!invitedName.empty()) - { - if (!normalizePlayerName(invitedName)) - return; - - player = sObjectAccessor->FindPlayerByName(invitedName.c_str()); - } - - if (!player) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", invitedName, ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S); - return; - } - - if (player->getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", player->GetName(), ERR_ARENA_TEAM_TARGET_TOO_LOW_S); - return; - } - - ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId); - if (!arenaTeam) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM); - return; - } - - // OK result but don't send invite - if (player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) - return; - - if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && player->GetTeam() != GetPlayer()->GetTeam()) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); - return; - } - - if (player->GetArenaTeamId(arenaTeam->GetSlot())) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", player->GetName(), ERR_ALREADY_IN_ARENA_TEAM_S); - return; - } - - if (player->GetArenaTeamIdInvited()) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S); - return; - } - - if (arenaTeam->GetMembersSize() >= arenaTeam->GetType() * 2) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, arenaTeam->GetName(), "", ERR_ARENA_TEAM_TOO_MANY_MEMBERS_S); - return; - } - - sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Player %s Invited %s to Join his ArenaTeam", GetPlayer()->GetName(), invitedName.c_str()); - - player->SetArenaTeamIdInvited(arenaTeam->GetId()); - - WorldPacket data(SMSG_ARENA_TEAM_INVITE, (8+10)); - data << GetPlayer()->GetName(); - data << arenaTeam->GetName(); - player->GetSession()->SendPacket(&data); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_ARENA_TEAM_INVITE"); -} - -void WorldSession::HandleArenaTeamAcceptOpcode(WorldPacket & /*recv_data*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_ARENA_TEAM_ACCEPT"); // empty opcode - - ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(_player->GetArenaTeamIdInvited()); - if (!arenaTeam) - return; - - // Check if player is already in another team of the same size - if (_player->GetArenaTeamId(arenaTeam->GetSlot())) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ALREADY_IN_ARENA_TEAM); - return; - } - - // Only allow members of the other faction to join the team if cross faction interaction is enabled - if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && _player->GetTeam() != sObjectMgr->GetPlayerTeamByGUID(arenaTeam->GetCaptain())) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_NOT_ALLIED); - return; - } - - // Add player to team - if (!arenaTeam->AddMember(_player->GetGUID())) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_INTERNAL); - return; - } - - // Broadcast event - arenaTeam->BroadcastEvent(ERR_ARENA_TEAM_JOIN_SS, _player->GetGUID(), 2, _player->GetName(), arenaTeam->GetName(), ""); -} - -void WorldSession::HandleArenaTeamDeclineOpcode(WorldPacket & /*recv_data*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_ARENA_TEAM_DECLINE"); // empty opcode - - // Remove invite from player - _player->SetArenaTeamIdInvited(0); -} - -void WorldSession::HandleArenaTeamLeaveOpcode(WorldPacket & recvData) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_ARENA_TEAM_LEAVE"); - - uint32 arenaTeamId; - recvData >> arenaTeamId; - - ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId); - if (!arenaTeam) - return; - - // Disallow leave team while in arena - if (_player->InArena()) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, "", "", ERR_ARENA_TEAM_INTERNAL); - return; - } - - // Team captain can't leave the team if other members are still present - if (_player->GetGUID() == arenaTeam->GetCaptain() && arenaTeam->GetMembersSize() > 1) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, "", "", ERR_ARENA_TEAM_LEADER_LEAVE_S); - return; - } - - // If team consists only of the captain, disband the team - if (_player->GetGUID() == arenaTeam->GetCaptain()) - { - arenaTeam->Disband(this); - delete arenaTeam; - return; - } - else - arenaTeam->DelMember(_player->GetGUID(), true); - - // Broadcast event - arenaTeam->BroadcastEvent(ERR_ARENA_TEAM_LEAVE_SS, _player->GetGUID(), 2, _player->GetName(), arenaTeam->GetName(), ""); - - // Inform player who left - SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, arenaTeam->GetName(), "", 0); -} - -void WorldSession::HandleArenaTeamDisbandOpcode(WorldPacket & recvData) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_ARENA_TEAM_DISBAND"); - - uint32 arenaTeamId; - recvData >> arenaTeamId; - - if (ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId)) - { - // Only captain can disband the team - if (arenaTeam->GetCaptain() != _player->GetGUID()) - return; - - // Teams cannot be disbanded during fights - if (arenaTeam->IsFighting()) - return; - - arenaTeam->Disband(this); - delete arenaTeam; - } -} - -void WorldSession::HandleArenaTeamRemoveOpcode(WorldPacket & recvData) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_ARENA_TEAM_REMOVE"); - - uint32 arenaTeamId; - std::string name; - - recvData >> arenaTeamId; - recvData >> name; - - // Check for valid arena team - ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId); - if (!arenaTeam) - return; - - // Only captain can remove members - if (arenaTeam->GetCaptain() != _player->GetGUID()) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS); - return; - } - - if (!normalizePlayerName(name)) - return; - - // Check if team member exists - ArenaTeamMember* member = arenaTeam->GetMember(name); - if (!member) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", name, ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S); - return; - } - - // Captain cannot be removed - if (arenaTeam->GetCaptain() == member->Guid) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, "", "", ERR_ARENA_TEAM_LEADER_LEAVE_S); - return; - } - - arenaTeam->DelMember(member->Guid, true); - - // Broadcast event - arenaTeam->BroadcastEvent(ERR_ARENA_TEAM_REMOVE_SSS, 0, 3, name, arenaTeam->GetName(), _player->GetName()); -} - -void WorldSession::HandleArenaTeamLeaderOpcode(WorldPacket & recvData) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_ARENA_TEAM_LEADER"); - - uint32 arenaTeamId; - std::string name; - - recvData >> arenaTeamId; - recvData >> name; - - // Check for valid arena team - ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId); - if (!arenaTeam) - return; - - // Only captain can pass leadership - if (arenaTeam->GetCaptain() != _player->GetGUID()) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS); - return; - } - - if (!normalizePlayerName(name)) - return; - - // Check if team member exists - ArenaTeamMember* member = arenaTeam->GetMember(name); - if (!member) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", name, ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S); - return; - } - - // Check if the target is already team captain - if (arenaTeam->GetCaptain() == member->Guid) - return; - - arenaTeam->SetCaptain(member->Guid); - - // Broadcast event - arenaTeam->BroadcastEvent(ERR_ARENA_TEAM_LEADER_CHANGED_SSS, 0, 3, _player->GetName(), name, arenaTeam->GetName()); -} - -void WorldSession::SendArenaTeamCommandResult(uint32 teamAction, const std::string& team, const std::string& player, uint32 errorId) -{ - WorldPacket data(SMSG_ARENA_TEAM_COMMAND_RESULT, 4+team.length()+1+player.length()+1+4); - data << uint32(teamAction); - data << team; - data << player; - data << uint32(errorId); - SendPacket(&data); -} - -void WorldSession::SendNotInArenaTeamPacket(uint8 type) -{ - WorldPacket data(SMSG_ARENA_ERROR, 4+1); // 886 - You are not in a %uv%u arena team - uint32 unk = 0; - data << uint32(unk); // unk(0) - if (!unk) - data << uint8(type); // team type (2=2v2, 3=3v3, 5=5v5), can be used for custom types... - SendPacket(&data); -} - -/* -+ERR_ARENA_NO_TEAM_II "You are not in a %dv%d arena team" - -+ERR_ARENA_TEAM_CREATE_S "%s created. To disband, use /teamdisband [2v2, 3v3, 5v5]." -+ERR_ARENA_TEAM_INVITE_SS "You have invited %s to join %s" -+ERR_ARENA_TEAM_QUIT_S "You are no longer a member of %s" -ERR_ARENA_TEAM_FOUNDER_S "Congratulations, you are a founding member of %s! To leave, use /teamquit [2v2, 3v3, 5v5]." - -+ERR_ARENA_TEAM_INTERNAL "Internal arena team error" -+ERR_ALREADY_IN_ARENA_TEAM "You are already in an arena team of that size" -+ERR_ALREADY_IN_ARENA_TEAM_S "%s is already in an arena team of that size" -+ERR_INVITED_TO_ARENA_TEAM "You have already been invited into an arena team" -+ERR_ALREADY_INVITED_TO_ARENA_TEAM_S "%s has already been invited to an arena team" -+ERR_ARENA_TEAM_NAME_INVALID "That name contains invalid characters, please enter a new name" -+ERR_ARENA_TEAM_NAME_EXISTS_S "There is already an arena team named \"%s\"" -+ERR_ARENA_TEAM_LEADER_LEAVE_S "You must promote a new team captain using /teamcaptain before leaving the team" -+ERR_ARENA_TEAM_PERMISSIONS "You don't have permission to do that" -+ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM "You are not in an arena team of that size" -+ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM_SS "%s is not in %s" -+ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S "\"%s\" not found" -+ERR_ARENA_TEAM_NOT_ALLIED "You cannot invite players from the opposing alliance" - -+ERR_ARENA_TEAM_JOIN_SS "%s has joined %s" -+ERR_ARENA_TEAM_YOU_JOIN_S "You have joined %s. To leave, use /teamquit [2v2, 3v3, 5v5]." - -+ERR_ARENA_TEAM_LEAVE_SS "%s has left %s" - -+ERR_ARENA_TEAM_LEADER_IS_SS "%s is the captain of %s" -+ERR_ARENA_TEAM_LEADER_CHANGED_SSS "%s has made %s the new captain of %s" - -+ERR_ARENA_TEAM_REMOVE_SSS "%s has been kicked out of %s by %s" - -+ERR_ARENA_TEAM_DISBANDED_S "%s has disbanded %s" - -ERR_ARENA_TEAM_TARGET_TOO_LOW_S "%s is not high enough level to join your team" - -ERR_ARENA_TEAM_TOO_MANY_MEMBERS_S "%s is full" - -ERR_ARENA_TEAM_LEVEL_TOO_LOW_I "You must be level %d to form an arena team" -*/ diff --git a/src/server/game/Server/Protocol/Handlers/AuctionHouseHandler.cpp b/src/server/game/Server/Protocol/Handlers/AuctionHouseHandler.cpp deleted file mode 100755 index 59eefb9fa77..00000000000 --- a/src/server/game/Server/Protocol/Handlers/AuctionHouseHandler.cpp +++ /dev/null @@ -1,639 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "ObjectMgr.h" -#include "Player.h" -#include "World.h" -#include "WorldPacket.h" -#include "WorldSession.h" - -#include "AuctionHouseMgr.h" -#include "Log.h" -#include "Opcodes.h" -#include "UpdateMask.h" -#include "Util.h" -#include "AccountMgr.h" - -//please DO NOT use iterator++, because it is slower than ++iterator!!! -//post-incrementation is always slower than pre-incrementation ! - -//void called when player click on auctioneer npc -void WorldSession::HandleAuctionHelloOpcode(WorldPacket & recv_data) -{ - uint64 guid; //NPC guid - recv_data >> guid; - - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_AUCTIONEER); - if (!unit) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - SendAuctionHello(guid, unit); -} - -//this void causes that auction window is opened -void WorldSession::SendAuctionHello(uint64 guid, Creature* unit) -{ - if (GetPlayer()->getLevel() < sWorld->getIntConfig(CONFIG_AUCTION_LEVEL_REQ)) - { - SendNotification(GetTrinityString(LANG_AUCTION_REQ), sWorld->getIntConfig(CONFIG_AUCTION_LEVEL_REQ)); - return; - } - - AuctionHouseEntry const* ahEntry = AuctionHouseMgr::GetAuctionHouseEntry(unit->getFaction()); - if (!ahEntry) - return; - - WorldPacket data(MSG_AUCTION_HELLO, 12); - data << uint64(guid); - data << uint32(ahEntry->houseId); - data << uint8(1); // 3.3.3: 1 - AH enabled, 0 - AH disabled - SendPacket(&data); -} - -//call this method when player bids, creates, or deletes auction -void WorldSession::SendAuctionCommandResult(uint32 auctionId, uint32 Action, uint32 ErrorCode, uint32 bidError) -{ - WorldPacket data(SMSG_AUCTION_COMMAND_RESULT, 16); - data << auctionId; - data << Action; - data << ErrorCode; - if (!ErrorCode && Action) - data << bidError; //when bid, then send 0, once... - SendPacket(&data); -} - -//this function sends notification, if bidder is online -void WorldSession::SendAuctionBidderNotification(uint32 location, uint32 auctionId, uint64 bidder, uint32 bidSum, uint32 diff, uint32 item_template) -{ - WorldPacket data(SMSG_AUCTION_BIDDER_NOTIFICATION, (8*4)); - data << uint32(location); - data << uint32(auctionId); - data << uint64(bidder); - data << uint32(bidSum); - data << uint32(diff); - data << uint32(item_template); - data << uint32(0); - SendPacket(&data); -} - -//this void causes on client to display: "Your auction sold" -void WorldSession::SendAuctionOwnerNotification(AuctionEntry* auction) -{ - WorldPacket data(SMSG_AUCTION_OWNER_NOTIFICATION, (8*4)); - data << uint32(auction->Id); - data << uint32(auction->bid); - data << uint32(0); //unk - data << uint64(0); //unk (bidder guid?) - data << uint32(auction->item_template); - data << uint32(0); //unk - data << float(0); //unk (time?) - SendPacket(&data); -} - -//this void creates new auction and adds auction to some auctionhouse -void WorldSession::HandleAuctionSellItem(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_SELL_ITEM"); - - uint64 auctioneer, item; - uint32 etime, bid, buyout, count; - recv_data >> auctioneer; - recv_data.read_skip(); // const 1? - recv_data >> item; - recv_data >> count; // 3.2.2, number of items being auctioned - recv_data >> bid; - recv_data >> buyout; - recv_data >> etime; - - Player* player = GetPlayer(); - - if (!item || !bid || !etime) - return; //check for cheaters - - Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); - if (!creature) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionSellItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); - return; - } - - AuctionHouseEntry const* auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(creature->getFaction()); - if (!auctionHouseEntry) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionSellItem - Unit (GUID: %u) has wrong faction.", uint32(GUID_LOPART(auctioneer))); - return; - } - - // client send time in minutes, convert to common used sec time - etime *= MINUTE; - - // client understand only 3 auction time - switch (etime) - { - case 1*MIN_AUCTION_TIME: - case 2*MIN_AUCTION_TIME: - case 4*MIN_AUCTION_TIME: - break; - default: - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - Item* it = player->GetItemByGuid(item); - //do not allow to sell already auctioned items - if (sAuctionMgr->GetAItem(GUID_LOPART(item))) - { - sLog->outError("AuctionError, player %s is sending item id: %u, but item is already in another auction", player->GetName(), GUID_LOPART(item)); - SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); - return; - } - // prevent sending bag with items (cheat: can be placed in bag after adding equiped empty bag to auction) - if (!it) - { - SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_ITEM_NOT_FOUND); - return; - } - - if (!it->CanBeTraded()) - { - SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); - return; - } - - if (it->GetTemplate()->Flags & ITEM_PROTO_FLAG_CONJURED || it->GetUInt32Value(ITEM_FIELD_DURATION)) - { - SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); - return; - } - - if (it->IsNotEmptyBag()) - { - SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR); - return; - } - - AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); - - //we have to take deposit : - uint32 deposit = sAuctionMgr->GetAuctionDeposit(auctionHouseEntry, etime, it, count); - if (!player->HasEnoughMoney(deposit)) - { - SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_NOT_ENOUGHT_MONEY); - return; - } - - if (AccountMgr::IsGMAccount(GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) - { - sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", - GetPlayerName(), GetAccountId(), it->GetTemplate()->Name1.c_str(), it->GetEntry(), count); - } - - player->ModifyMoney(-int32(deposit)); - - uint32 auction_time = uint32(etime * sWorld->getRate(RATE_AUCTION_TIME)); - - AuctionEntry* AH = new AuctionEntry; - AH->Id = sObjectMgr->GenerateAuctionID(); - if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) - AH->auctioneer = 23442; - else - AH->auctioneer = GUID_LOPART(auctioneer); - AH->item_guidlow = GUID_LOPART(item); - AH->item_template = it->GetEntry(); - AH->owner = player->GetGUIDLow(); - AH->startbid = bid; - AH->bidder = 0; - AH->bid = 0; - AH->buyout = buyout; - AH->expire_time = time(NULL) + auction_time; - AH->deposit = deposit; - AH->auctionHouseEntry = auctionHouseEntry; - - sLog->outDetail("selling item %u to auctioneer %u with initial bid %u with buyout %u and with time %u (in sec) in auctionhouse %u", GUID_LOPART(item), AH->auctioneer, bid, buyout, auction_time, AH->GetHouseId()); - sAuctionMgr->AddAItem(it); - auctionHouse->AddAuction(AH); - - player->MoveItemFromInventory(it->GetBagSlot(), it->GetSlot(), true); - - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - it->DeleteFromInventoryDB(trans); - it->SaveToDB(trans); // recursive and not have transaction guard into self, not in inventiory and can be save standalone - AH->SaveToDB(trans); - player->SaveInventoryAndGoldToDB(trans); - CharacterDatabase.CommitTransaction(trans); - - SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, AUCTION_OK); - - GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION, 1); -} - -//this function is called when client bids or buys out auction -void WorldSession::HandleAuctionPlaceBid(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_PLACE_BID"); - - uint64 auctioneer; - uint32 auctionId; - uint32 price; - recv_data >> auctioneer; - recv_data >> auctionId >> price; - - if (!auctionId || !price) - return; //check for cheaters - - Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); - if (!creature) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionPlaceBid - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); - - AuctionEntry* auction = auctionHouse->GetAuction(auctionId); - Player* player = GetPlayer(); - - if (!auction || auction->owner == player->GetGUIDLow()) - { - //you cannot bid your own auction: - SendAuctionCommandResult(0, AUCTION_PLACE_BID, CANNOT_BID_YOUR_AUCTION_ERROR); - return; - } - - // impossible have online own another character (use this for speedup check in case online owner) - Player* auction_owner = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)); - if (!auction_owner && sObjectMgr->GetPlayerAccountIdByGUID(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)) == player->GetSession()->GetAccountId()) - { - //you cannot bid your another character auction: - SendAuctionCommandResult(0, AUCTION_PLACE_BID, CANNOT_BID_YOUR_AUCTION_ERROR); - return; - } - - // cheating - if (price <= auction->bid || price < auction->startbid) - return; - - // price too low for next bid if not buyout - if ((price < auction->buyout || auction->buyout == 0) && - price < auction->bid + auction->GetAuctionOutBid()) - { - //auction has already higher bid, client tests it! - return; - } - - if (!player->HasEnoughMoney(price)) - { - //you don't have enought money!, client tests! - //SendAuctionCommandResult(auction->auctionId, AUCTION_PLACE_BID, ???); - return; - } - - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - - if (price < auction->buyout || auction->buyout == 0) - { - if (auction->bidder > 0) - { - if (auction->bidder == player->GetGUIDLow()) - player->ModifyMoney(-int32(price - auction->bid)); - else - { - // mail to last bidder and return money - sAuctionMgr->SendAuctionOutbiddedMail(auction, price, GetPlayer(), trans); - player->ModifyMoney(-int32(price)); - } - } - else - player->ModifyMoney(-int32(price)); - - auction->bidder = player->GetGUIDLow(); - auction->bid = price; - GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, price); - - trans->PAppend("UPDATE auctionhouse SET buyguid = '%u', lastbid = '%u' WHERE id = '%u'", auction->bidder, auction->bid, auction->Id); - - SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, AUCTION_OK, 0); - } - else - { - //buyout: - if (player->GetGUIDLow() == auction->bidder) - player->ModifyMoney(-int32(auction->buyout - auction->bid)); - else - { - player->ModifyMoney(-int32(auction->buyout)); - if (auction->bidder) //buyout for bidded auction .. - sAuctionMgr->SendAuctionOutbiddedMail(auction, auction->buyout, GetPlayer(), trans); - } - auction->bidder = player->GetGUIDLow(); - auction->bid = auction->buyout; - GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, auction->buyout); - - //- Mails must be under transaction control too to prevent data loss - sAuctionMgr->SendAuctionSalePendingMail(auction, trans); - sAuctionMgr->SendAuctionSuccessfulMail(auction, trans); - sAuctionMgr->SendAuctionWonMail(auction, trans); - - SendAuctionCommandResult(auction->Id, AUCTION_PLACE_BID, AUCTION_OK); - - auction->DeleteFromDB(trans); - - uint32 item_template = auction->item_template; - sAuctionMgr->RemoveAItem(auction->item_guidlow); - auctionHouse->RemoveAuction(auction, item_template); - } - player->SaveInventoryAndGoldToDB(trans); - CharacterDatabase.CommitTransaction(trans); -} - -//this void is called when auction_owner cancels his auction -void WorldSession::HandleAuctionRemoveItem(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_REMOVE_ITEM"); - - uint64 auctioneer; - uint32 auctionId; - recv_data >> auctioneer; - recv_data >> auctionId; - //sLog->outDebug("Cancel AUCTION AuctionID: %u", auctionId); - - Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); - if (!creature) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionRemoveItem - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); - - AuctionEntry* auction = auctionHouse->GetAuction(auctionId); - Player* player = GetPlayer(); - - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - if (auction && auction->owner == player->GetGUIDLow()) - { - Item* pItem = sAuctionMgr->GetAItem(auction->item_guidlow); - if (pItem) - { - if (auction->bidder > 0) // If we have a bidder, we have to send him the money he paid - { - uint32 auctionCut = auction->GetAuctionCut(); - if (!player->HasEnoughMoney(auctionCut)) //player doesn't have enough money, maybe message needed - return; - //some auctionBidderNotification would be needed, but don't know that parts.. - sAuctionMgr->SendAuctionCancelledToBidderMail(auction, trans); - player->ModifyMoney(-int32(auctionCut)); - } - // Return the item by mail - std::ostringstream msgAuctionCanceledOwner; - msgAuctionCanceledOwner << auction->item_template << ":0:" << AUCTION_CANCELED << ":0:0"; - - // item will deleted or added to received mail list - MailDraft(msgAuctionCanceledOwner.str(), "") // TODO: fix body - .AddItem(pItem) - .SendMailTo(trans, player, auction, MAIL_CHECK_MASK_COPIED); - } - else - { - sLog->outError("Auction id: %u has non-existed item (item guid : %u)!!!", auction->Id, auction->item_guidlow); - SendAuctionCommandResult(0, AUCTION_CANCEL, AUCTION_INTERNAL_ERROR); - return; - } - } - else - { - SendAuctionCommandResult(0, AUCTION_CANCEL, AUCTION_INTERNAL_ERROR); - //this code isn't possible ... maybe there should be assert - sLog->outError("CHEATER : %u, he tried to cancel auction (id: %u) of another player, or auction is NULL", player->GetGUIDLow(), auctionId); - return; - } - - //inform player, that auction is removed - SendAuctionCommandResult(auction->Id, AUCTION_CANCEL, AUCTION_OK); - - // Now remove the auction - - player->SaveInventoryAndGoldToDB(trans); - auction->DeleteFromDB(trans); - CharacterDatabase.CommitTransaction(trans); - - uint32 item_template = auction->item_template; - sAuctionMgr->RemoveAItem(auction->item_guidlow); - auctionHouse->RemoveAuction(auction, item_template); -} - -//called when player lists his bids -void WorldSession::HandleAuctionListBidderItems(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_LIST_BIDDER_ITEMS"); - - uint64 guid; //NPC guid - uint32 listfrom; //page of auctions - uint32 outbiddedCount; //count of outbidded auctions - - recv_data >> guid; - recv_data >> listfrom; // not used in fact (this list not have page control in client) - recv_data >> outbiddedCount; - if (recv_data.size() != (16 + outbiddedCount * 4)) - { - sLog->outError("Client sent bad opcode!!! with count: %u and size : %lu (must be: %u)", outbiddedCount, (unsigned long)recv_data.size(), (16 + outbiddedCount * 4)); - outbiddedCount = 0; - } - - Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_AUCTIONEER); - if (!creature) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionListBidderItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); - recv_data.rfinish(); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); - - WorldPacket data(SMSG_AUCTION_BIDDER_LIST_RESULT, (4+4+4)); - Player* player = GetPlayer(); - data << (uint32) 0; //add 0 as count - uint32 count = 0; - uint32 totalcount = 0; - while (outbiddedCount > 0) //add all data, which client requires - { - --outbiddedCount; - uint32 outbiddedAuctionId; - recv_data >> outbiddedAuctionId; - AuctionEntry* auction = auctionHouse->GetAuction(outbiddedAuctionId); - if (auction && auction->BuildAuctionInfo(data)) - { - ++totalcount; - ++count; - } - } - - auctionHouse->BuildListBidderItems(data, player, count, totalcount); - data.put(0, count); // add count to placeholder - data << totalcount; - data << (uint32)300; //unk 2.3.0 - SendPacket(&data); -} - -//this void sends player info about his auctions -void WorldSession::HandleAuctionListOwnerItems(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_LIST_OWNER_ITEMS"); - - uint32 listfrom; - uint64 guid; - - recv_data >> guid; - recv_data >> listfrom; // not used in fact (this list not have page control in client) - - Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_AUCTIONEER); - if (!creature) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionListOwnerItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); - - WorldPacket data(SMSG_AUCTION_OWNER_LIST_RESULT, (4+4+4)); - data << (uint32) 0; // amount place holder - - uint32 count = 0; - uint32 totalcount = 0; - - auctionHouse->BuildListOwnerItems(data, _player, count, totalcount); - data.put(0, count); - data << (uint32) totalcount; - data << (uint32) 0; - SendPacket(&data); -} - -//this void is called when player clicks on search button -void WorldSession::HandleAuctionListItems(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_LIST_ITEMS"); - - std::string searchedname; - uint8 levelmin, levelmax, usable; - uint32 listfrom, auctionSlotID, auctionMainCategory, auctionSubCategory, quality; - uint64 guid; - - recv_data >> guid; - recv_data >> listfrom; // start, used for page control listing by 50 elements - recv_data >> searchedname; - - recv_data >> levelmin >> levelmax; - recv_data >> auctionSlotID >> auctionMainCategory >> auctionSubCategory; - recv_data >> quality >> usable; - - recv_data.read_skip(); // unk - - // this block looks like it uses some lame byte packing or similar... - uint8 unkCnt; - recv_data >> unkCnt; - for (uint8 i = 0; i < unkCnt; i++) - { - recv_data.read_skip(); - recv_data.read_skip(); - } - - Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_AUCTIONEER); - if (!creature) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionListItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); - - //sLog->outDebug("Auctionhouse search (GUID: %u TypeId: %u)",, list from: %u, searchedname: %s, levelmin: %u, levelmax: %u, auctionSlotID: %u, auctionMainCategory: %u, auctionSubCategory: %u, quality: %u, usable: %u", - // GUID_LOPART(guid), GuidHigh2TypeId(GUID_HIPART(guid)), listfrom, searchedname.c_str(), levelmin, levelmax, auctionSlotID, auctionMainCategory, auctionSubCategory, quality, usable); - - WorldPacket data(SMSG_AUCTION_LIST_RESULT, (4+4+4)); - uint32 count = 0; - uint32 totalcount = 0; - data << (uint32) 0; - - // converting string that we try to find to lower case - std::wstring wsearchedname; - if (!Utf8toWStr(searchedname, wsearchedname)) - return; - - wstrToLower(wsearchedname); - - auctionHouse->BuildListAuctionItems(data, _player, - wsearchedname, listfrom, levelmin, levelmax, usable, - auctionSlotID, auctionMainCategory, auctionSubCategory, quality, - count, totalcount); - - data.put(0, count); - data << (uint32) totalcount; - data << (uint32) 300; // unk 2.3.0 const? - SendPacket(&data); -} - -void WorldSession::HandleAuctionListPendingSales(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_LIST_PENDING_SALES"); - - recv_data.read_skip(); - - uint32 count = 0; - - WorldPacket data(SMSG_AUCTION_LIST_PENDING_SALES, 4); - data << uint32(count); // count - /*for (uint32 i = 0; i < count; ++i) - { - data << ""; // string - data << ""; // string - data << uint32(0); - data << uint32(0); - data << float(0); - }*/ - SendPacket(&data); -} diff --git a/src/server/game/Server/Protocol/Handlers/AuthHandler.cpp b/src/server/game/Server/Protocol/Handlers/AuthHandler.cpp deleted file mode 100755 index 9a3e756dda3..00000000000 --- a/src/server/game/Server/Protocol/Handlers/AuthHandler.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Opcodes.h" -#include "WorldSession.h" -#include "WorldPacket.h" - -void WorldSession::SendAuthResponse(uint8 code, bool shortForm, uint32 queuePos) -{ - WorldPacket packet(SMSG_AUTH_RESPONSE, 1 + 4 + 1 + 4 + 1 + (shortForm ? 0 : (4 + 1))); - packet << uint8(code); - packet << uint32(0); // BillingTimeRemaining - packet << uint8(0); // BillingPlanFlags - packet << uint32(0); // BillingTimeRested - packet << uint8(Expansion()); // 0 - normal, 1 - TBC, 2 - WOTLK, must be set in database manually for each account - - if (!shortForm) - { - packet << uint32(queuePos); // Queue position - packet << uint8(0); // Unk 3.3.0 - } - - SendPacket(&packet); -} - -void WorldSession::SendClientCacheVersion(uint32 version) -{ - WorldPacket data(SMSG_CLIENTCACHE_VERSION, 4); - data << uint32(version); - SendPacket(&data); -} diff --git a/src/server/game/Server/Protocol/Handlers/BattleGroundHandler.cpp b/src/server/game/Server/Protocol/Handlers/BattleGroundHandler.cpp deleted file mode 100755 index d1aa0021a75..00000000000 --- a/src/server/game/Server/Protocol/Handlers/BattleGroundHandler.cpp +++ /dev/null @@ -1,790 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "ObjectAccessor.h" -#include "ObjectMgr.h" -#include "ArenaTeamMgr.h" -#include "WorldPacket.h" -#include "WorldSession.h" - -#include "ArenaTeam.h" -#include "BattlegroundMgr.h" -#include "Battleground.h" -#include "Chat.h" -#include "Language.h" -#include "Log.h" -#include "Player.h" -#include "Object.h" -#include "Opcodes.h" -#include "DisableMgr.h" -#include "Group.h" - -void WorldSession::HandleBattlemasterHelloOpcode(WorldPacket & recv_data) -{ - uint64 guid; - recv_data >> guid; - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_BATTLEMASTER_HELLO Message from (GUID: %u TypeId:%u)", GUID_LOPART(guid), GuidHigh2TypeId(GUID_HIPART(guid))); - - Creature* unit = GetPlayer()->GetMap()->GetCreature(guid); - if (!unit) - return; - - if (!unit->isBattleMaster()) // it's not battlemaster - return; - - // Stop the npc if moving - unit->StopMoving(); - - BattlegroundTypeId bgTypeId = sBattlegroundMgr->GetBattleMasterBG(unit->GetEntry()); - - if (!_player->GetBGAccessByLevel(bgTypeId)) - { - // temp, must be gossip message... - SendNotification(LANG_YOUR_BG_LEVEL_REQ_ERROR); - return; - } - - SendBattlegGroundList(guid, bgTypeId); -} - -void WorldSession::SendBattlegGroundList(uint64 guid, BattlegroundTypeId bgTypeId) -{ - WorldPacket data; - sBattlegroundMgr->BuildBattlegroundListPacket(&data, guid, _player, bgTypeId, 0); - SendPacket(&data); -} - -void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket & recv_data) -{ - uint64 guid; - uint32 bgTypeId_; - uint32 instanceId; - uint8 joinAsGroup; - bool isPremade = false; - Group* grp = NULL; - - recv_data >> guid; // battlemaster guid - recv_data >> bgTypeId_; // battleground type id (DBC id) - recv_data >> instanceId; // instance id, 0 if First Available selected - recv_data >> joinAsGroup; // join as group - - if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) - { - sLog->outError("Battleground: invalid bgtype (%u) received. possible cheater? player guid %u", bgTypeId_, _player->GetGUIDLow()); - return; - } - - if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeId_, NULL)) - { - ChatHandler(this).PSendSysMessage(LANG_BG_DISABLED); - return; - } - - BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from (GUID: %u TypeId:%u)", GUID_LOPART(guid), GuidHigh2TypeId(GUID_HIPART(guid))); - - // can do this, since it's battleground, not arena - BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, 0); - BattlegroundQueueTypeId bgQueueTypeIdRandom = BattlegroundMgr::BGQueueTypeId(BATTLEGROUND_RB, 0); - - // ignore if player is already in BG - if (_player->InBattleground()) - return; - - // get bg instance or bg template if instance not found - Battleground* bg = NULL; - if (instanceId) - bg = sBattlegroundMgr->GetBattlegroundThroughClientInstance(instanceId, bgTypeId); - - if (!bg) - bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); - if (!bg) - return; - - // expected bracket entry - PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); - if (!bracketEntry) - return; - - GroupJoinBattlegroundResult err; - - // check queue conditions - if (!joinAsGroup) - { - if (GetPlayer()->isUsingLfg()) - { - // player is using dungeon finder or raid finder - WorldPacket data; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_LFG_CANT_USE_BATTLEGROUND); - GetPlayer()->GetSession()->SendPacket(&data); - return; - } - - // check Deserter debuff - if (!_player->CanJoinToBattleground()) - { - WorldPacket data; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); - _player->GetSession()->SendPacket(&data); - return; - } - - if (_player->GetBattlegroundQueueIndex(bgQueueTypeIdRandom) < PLAYER_MAX_BATTLEGROUND_QUEUES) - { - //player is already in random queue - WorldPacket data; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_IN_RANDOM_BG); - _player->GetSession()->SendPacket(&data); - return; - } - - if (_player->InBattlegroundQueue() && bgTypeId == BATTLEGROUND_RB) - { - //player is already in queue, can't start random queue - WorldPacket data; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_IN_NON_RANDOM_BG); - _player->GetSession()->SendPacket(&data); - return; - } - - // check if already in queue - if (_player->GetBattlegroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES) - //player is already in this queue - return; - - // check if has free queue slots - if (!_player->HasFreeBattlegroundQueueId()) - { - WorldPacket data; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_BATTLEGROUND_TOO_MANY_QUEUES); - _player->GetSession()->SendPacket(&data); - return; - } - - BattlegroundQueue& bgQueue = sBattlegroundMgr->m_BattlegroundQueues[bgQueueTypeId]; - - GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0); - uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); - // already checked if queueSlot is valid, now just get it - uint32 queueSlot = _player->AddBattlegroundQueueId(bgQueueTypeId); - - WorldPacket data; - // send status packet (in queue) - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType); - SendPacket(&data); - sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, _player->GetGUIDLow(), _player->GetName()); - } - else - { - grp = _player->GetGroup(); - // no group found, error - if (!grp) - return; - if (grp->GetLeaderGUID() != _player->GetGUID()) - return; - err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0); - isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam()); - - BattlegroundQueue& bgQueue = sBattlegroundMgr->m_BattlegroundQueues[bgQueueTypeId]; - GroupQueueInfo* ginfo = NULL; - uint32 avgTime = 0; - - if (err > 0) - { - sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: the following players are joining as group:"); - ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0); - avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); - } - - for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* member = itr->getSource(); - if (!member) continue; // this should never happen - - WorldPacket data; - - if (err <= 0) - { - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); - member->GetSession()->SendPacket(&data); - continue; - } - - // add to queue - uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId); - - // send status packet (in queue) - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType); - member->GetSession()->SendPacket(&data); - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); - member->GetSession()->SendPacket(&data); - sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, member->GetGUIDLow(), member->GetName()); - } - sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: group end"); - - } - sBattlegroundMgr->ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); -} - -void WorldSession::HandleBattlegroundPlayerPositionsOpcode(WorldPacket & /*recv_data*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd MSG_BATTLEGROUND_PLAYER_POSITIONS Message"); - - Battleground* bg = _player->GetBattleground(); - if (!bg) // can't be received if player not in battleground - return; - - uint32 count = 0; - Player* aplr = NULL; - Player* hplr = NULL; - - if (uint64 guid = bg->GetFlagPickerGUID(BG_TEAM_ALLIANCE)) - { - aplr = ObjectAccessor::FindPlayer(guid); - if (aplr) - ++count; - } - - if (uint64 guid = bg->GetFlagPickerGUID(BG_TEAM_HORDE)) - { - hplr = ObjectAccessor::FindPlayer(guid); - if (hplr) - ++count; - } - - WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, 4 + 4 + 16 * count); - data << 0; - data << count; - if (aplr) - { - data << uint64(aplr->GetGUID()); - data << float(aplr->GetPositionX()); - data << float(aplr->GetPositionY()); - } - - if (hplr) - { - data << uint64(hplr->GetGUID()); - data << float(hplr->GetPositionX()); - data << float(hplr->GetPositionY()); - } - - SendPacket(&data); -} - -void WorldSession::HandlePVPLogDataOpcode(WorldPacket & /*recv_data*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd MSG_PVP_LOG_DATA Message"); - - Battleground* bg = _player->GetBattleground(); - if (!bg) - return; - - // Prevent players from sending BuildPvpLogDataPacket in an arena except for when sent in BattleGround::EndBattleGround. - if (bg->isArena()) - return; - - WorldPacket data; - sBattlegroundMgr->BuildPvpLogDataPacket(&data, bg); - SendPacket(&data); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent MSG_PVP_LOG_DATA Message"); -} - -void WorldSession::HandleBattlefieldListOpcode(WorldPacket &recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message"); - - uint32 bgTypeId; - recv_data >> bgTypeId; // id from DBC - - uint8 fromWhere; - recv_data >> fromWhere; // 0 - battlemaster (lua: ShowBattlefieldList), 1 - UI (lua: RequestBattlegroundInstanceInfo) - - uint8 unk1; - recv_data >> unk1; // Unknown 3.2.2 - - BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId); - if (!bl) - { - sLog->outDebug(LOG_FILTER_BATTLEGROUND, "BattlegroundHandler: invalid bgtype (%u) with player (Name: %s, GUID: %u) received.", bgTypeId, _player->GetName(), _player->GetGUIDLow()); - return; - } - - WorldPacket data; - sBattlegroundMgr->BuildBattlegroundListPacket(&data, 0, _player, BattlegroundTypeId(bgTypeId), fromWhere); - SendPacket(&data); -} - -void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message"); - - uint8 type; // arenatype if arena - uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1 - uint32 bgTypeId_; // type id from dbc - uint16 unk; // 0x1F90 constant? - uint8 action; // enter battle 0x1, leave queue 0x0 - - recv_data >> type >> unk2 >> bgTypeId_ >> unk >> action; - - if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) - { - sLog->outDebug(LOG_FILTER_BATTLEGROUND, "BattlegroundHandler: invalid bgtype (%u) with player (Name: %s, GUID: %u) received.", bgTypeId_, _player->GetName(), _player->GetGUIDLow()); - return; - } - - if (!_player->InBattlegroundQueue()) - { - sLog->outDebug(LOG_FILTER_BATTLEGROUND, "BattlegroundHandler: Invalid CMSG_BATTLEFIELD_PORT received from player (Name: %s, GUID: %u), he is not in bg_queue.", _player->GetName(), _player->GetGUIDLow()); - return; - } - - //get GroupQueueInfo from BattlegroundQueue - BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_); - BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, type); - BattlegroundQueue& bgQueue = sBattlegroundMgr->m_BattlegroundQueues[bgQueueTypeId]; - //we must use temporary variable, because GroupQueueInfo pointer can be deleted in BattlegroundQueue::RemovePlayer() function - GroupQueueInfo ginfo; - if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) - { - sLog->outError("BattlegroundHandler: itrplayerstatus not found."); - return; - } - // if action == 1, then instanceId is required - if (!ginfo.IsInvitedToBGInstanceGUID && action == 1) - { - sLog->outError("BattlegroundHandler: instance not found."); - return; - } - - Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); - - // bg template might and must be used in case of leaving queue, when instance is not created yet - if (!bg && action == 0) - bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); - if (!bg) - { - sLog->outError("BattlegroundHandler: bg_template not found for type id %u.", bgTypeId); - return; - } - - // expected bracket entry - PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); - if (!bracketEntry) - return; - - //some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it - if (action == 1 && ginfo.ArenaType == 0) - { - //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue - if (!_player->CanJoinToBattleground()) - { - //send bg command result to show nice message - WorldPacket data2; - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data2, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); - _player->GetSession()->SendPacket(&data2); - action = 0; - sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); - } - //if player don't match battleground max level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue - if (_player->getLevel() > bg->GetMaxLevel()) - { - sLog->outError("Battleground: Player %s (%u) has level (%u) higher than maxlevel (%u) of battleground (%u)! Do not port him to battleground!", - _player->GetName(), _player->GetGUIDLow(), _player->getLevel(), bg->GetMaxLevel(), bg->GetTypeID()); - action = 0; - } - } - uint32 queueSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId); - WorldPacket data; - switch (action) - { - case 1: // port to battleground - if (!_player->IsInvitedForBattlegroundQueueType(bgQueueTypeId)) - return; // cheating? - - if (!_player->InBattleground()) - _player->SetBattlegroundEntryPoint(); - - // resurrect the player - if (!_player->isAlive()) - { - _player->ResurrectPlayer(1.0f); - _player->SpawnCorpseBones(); - } - // stop taxi flight at port - if (_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->CleanupAfterTaxiFlight(); - } - - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType()); - _player->GetSession()->SendPacket(&data); - // remove battleground queue status from BGmgr - bgQueue.RemovePlayer(_player->GetGUID(), false); - // this is still needed here if battleground "jumping" shouldn't add deserter debuff - // also this is required to prevent stuck at old battleground after SetBattlegroundId set to new - if (Battleground* currentBg = _player->GetBattleground()) - currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true); - - // set the destination instance id - _player->SetBattlegroundId(bg->GetInstanceID(), bgTypeId); - // set the destination team - _player->SetBGTeam(ginfo.Team); - // bg->HandleBeforeTeleportToBattleground(_player); - sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId); - // add only in HandleMoveWorldPortAck() - // bg->AddPlayer(_player, team); - sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetInstanceID(), bg->GetTypeID(), bgQueueTypeId); - break; - case 0: // leave queue - // if player leaves rated arena match before match start, it is counted as he played but he lost - if (ginfo.IsRated && ginfo.IsInvitedToBGInstanceGUID) - { - ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(ginfo.Team); - if (at) - { - sLog->outDebug(LOG_FILTER_BATTLEGROUND, "UPDATING memberLost's personal arena rating for %u by opponents rating: %u, because he has left queue!", GUID_LOPART(_player->GetGUID()), ginfo.OpponentsTeamRating); - at->MemberLost(_player, ginfo.OpponentsMatchmakerRating); - at->SaveToDB(); - } - } - _player->RemoveBattlegroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); - bgQueue.RemovePlayer(_player->GetGUID(), true); - // player left queue, we should update it - do not update Arena Queue - if (!ginfo.ArenaType) - sBattlegroundMgr->ScheduleQueueUpdate(ginfo.ArenaMatchmakerRating, ginfo.ArenaType, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); - SendPacket(&data); - sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player %s (%u) left queue for bgtype %u, queue type %u.", _player->GetName(), _player->GetGUIDLow(), bg->GetTypeID(), bgQueueTypeId); - break; - default: - sLog->outError("Battleground port: unknown action %u", action); - break; - } -} - -void WorldSession::HandleLeaveBattlefieldOpcode(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_LEAVE_BATTLEFIELD Message"); - - recv_data.read_skip(); // unk1 - recv_data.read_skip(); // unk2 - recv_data.read_skip(); // BattlegroundTypeId - recv_data.read_skip(); // unk3 - - // not allow leave battleground in combat - if (_player->isInCombat()) - if (Battleground* bg = _player->GetBattleground()) - if (bg->GetStatus() != STATUS_WAIT_LEAVE) - return; - - _player->LeaveBattleground(); -} - -void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recv_data*/) -{ - // empty opcode - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Battleground status"); - - WorldPacket data; - // we must update all queues here - Battleground* bg = NULL; - for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) - { - BattlegroundQueueTypeId bgQueueTypeId = _player->GetBattlegroundQueueTypeId(i); - if (!bgQueueTypeId) - continue; - BattlegroundTypeId bgTypeId = BattlegroundMgr::BGTemplateId(bgQueueTypeId); - uint8 arenaType = BattlegroundMgr::BGArenaType(bgQueueTypeId); - if (bgTypeId == _player->GetBattlegroundTypeId()) - { - bg = _player->GetBattleground(); - //i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena - //so i must use bg pointer to get that information - if (bg && bg->GetArenaType() == arenaType) - { - // this line is checked, i only don't know if GetStartTime is changing itself after bg end! - // send status in Battleground - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType); - SendPacket(&data); - continue; - } - } - //we are sending update to player about queue - he can be invited there! - //get GroupQueueInfo for queue status - BattlegroundQueue& bgQueue = sBattlegroundMgr->m_BattlegroundQueues[bgQueueTypeId]; - GroupQueueInfo ginfo; - if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) - continue; - if (ginfo.IsInvitedToBGInstanceGUID) - { - bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); - if (!bg) - continue; - uint32 remainingTime = getMSTimeDiff(getMSTime(), ginfo.RemoveInviteTime); - // send status invited to Battleground - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType); - SendPacket(&data); - } - else - { - bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); - if (!bg) - continue; - - // expected bracket entry - PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); - if (!bracketEntry) - continue; - - uint32 avgTime = bgQueue.GetAverageQueueWaitTime(&ginfo, bracketEntry->GetBracketId()); - // send status in Battleground Queue - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(ginfo.JoinTime, getMSTime()), arenaType); - SendPacket(&data); - } - } -} - -void WorldSession::HandleAreaSpiritHealerQueryOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AREA_SPIRIT_HEALER_QUERY"); - - Battleground* bg = _player->GetBattleground(); - - uint64 guid; - recv_data >> guid; - - Creature* unit = GetPlayer()->GetMap()->GetCreature(guid); - if (!unit) - return; - - if (!unit->isSpiritService()) // it's not spirit service - return; - - if (bg) - sBattlegroundMgr->SendAreaSpiritHealerQueryOpcode(_player, bg, guid); -} - -void WorldSession::HandleAreaSpiritHealerQueueOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AREA_SPIRIT_HEALER_QUEUE"); - - Battleground* bg = _player->GetBattleground(); - - uint64 guid; - recv_data >> guid; - - Creature* unit = GetPlayer()->GetMap()->GetCreature(guid); - if (!unit) - return; - - if (!unit->isSpiritService()) // it's not spirit service - return; - - if (bg) - bg->AddPlayerToResurrectQueue(guid, _player->GetGUID()); -} - -void WorldSession::HandleBattlemasterJoinArena(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_BATTLEMASTER_JOIN_ARENA"); - - uint64 guid; // arena Battlemaster guid - uint8 arenaslot; // 2v2, 3v3 or 5v5 - uint8 asGroup; // asGroup - uint8 isRated; // isRated - Group* grp = NULL; - - recv_data >> guid >> arenaslot >> asGroup >> isRated; - - // ignore if we already in BG or BG queue - if (_player->InBattleground()) - return; - - Creature* unit = GetPlayer()->GetMap()->GetCreature(guid); - if (!unit) - return; - - if (!unit->isBattleMaster()) // it's not battle master - return; - - uint8 arenatype = 0; - uint32 arenaRating = 0; - uint32 matchmakerRating = 0; - - switch (arenaslot) - { - case 0: - arenatype = ARENA_TYPE_2v2; - break; - case 1: - arenatype = ARENA_TYPE_3v3; - break; - case 2: - arenatype = ARENA_TYPE_5v5; - break; - default: - sLog->outError("Unknown arena slot %u at HandleBattlemasterJoinArena()", arenaslot); - return; - } - - //check existance - Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(BATTLEGROUND_AA); - if (!bg) - { - sLog->outError("Battleground: template bg (all arenas) not found"); - return; - } - - if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, BATTLEGROUND_AA, NULL)) - { - ChatHandler(this).PSendSysMessage(LANG_ARENA_DISABLED); - return; - } - - BattlegroundTypeId bgTypeId = bg->GetTypeID(); - BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, arenatype); - PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); - if (!bracketEntry) - return; - - GroupJoinBattlegroundResult err = ERR_GROUP_JOIN_BATTLEGROUND_FAIL; - - if (!asGroup) - { - // check if already in queue - if (_player->GetBattlegroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES) - //player is already in this queue - return; - // check if has free queue slots - if (!_player->HasFreeBattlegroundQueueId()) - return; - } - else - { - grp = _player->GetGroup(); - // no group found, error - if (!grp) - return; - if (grp->GetLeaderGUID() != _player->GetGUID()) - return; - err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, arenatype, arenatype, (bool)isRated, arenaslot); - } - - uint32 ateamId = 0; - - if (isRated) - { - ateamId = _player->GetArenaTeamId(arenaslot); - // check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice) - ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(ateamId); - if (!at) - { - _player->GetSession()->SendNotInArenaTeamPacket(arenatype); - return; - } - // get the team rating for queueing - arenaRating = at->GetRating(); - matchmakerRating = at->GetAverageMMR(grp); - // the arenateam id must match for everyone in the group - - if (arenaRating <= 0) - arenaRating = 1; - } - - BattlegroundQueue &bgQueue = sBattlegroundMgr->m_BattlegroundQueues[bgQueueTypeId]; - if (asGroup) - { - uint32 avgTime = 0; - - if (err > 0) - { - sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: arena join as group start"); - if (isRated) - { - sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: arena team id %u, leader %s queued with matchmaker rating %u for type %u", _player->GetArenaTeamId(arenaslot), _player->GetName(), matchmakerRating, arenatype); - bg->SetRated(true); - } - else - bg->SetRated(false); - - GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, arenatype, isRated, false, arenaRating, matchmakerRating, ateamId); - avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); - } - - for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* member = itr->getSource(); - if (!member) - continue; - - WorldPacket data; - - if (err <= 0) - { - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); - member->GetSession()->SendPacket(&data); - continue; - } - - // add to queue - uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId); - - // send status packet (in queue) - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype); - member->GetSession()->SendPacket(&data); - sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); - member->GetSession()->SendPacket(&data); - sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player joined queue for arena as group bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, member->GetGUIDLow(), member->GetName()); - } - } - else - { - GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, NULL, bgTypeId, bracketEntry, arenatype, isRated, false, arenaRating, matchmakerRating, ateamId); - uint32 avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry->GetBracketId()); - uint32 queueSlot = _player->AddBattlegroundQueueId(bgQueueTypeId); - - WorldPacket data; - // send status packet (in queue) - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype); - SendPacket(&data); - sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player joined queue for arena, skirmish, bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, _player->GetGUIDLow(), _player->GetName()); - } - sBattlegroundMgr->ScheduleQueueUpdate(matchmakerRating, arenatype, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId()); -} - -void WorldSession::HandleReportPvPAFK(WorldPacket & recv_data) -{ - uint64 playerGuid; - recv_data >> playerGuid; - Player* reportedPlayer = ObjectAccessor::FindPlayer(playerGuid); - - if (!reportedPlayer) - { - sLog->outDebug(LOG_FILTER_BATTLEGROUND, "WorldSession::HandleReportPvPAFK: player not found"); - return; - } - - sLog->outDebug(LOG_FILTER_BATTLEGROUND, "WorldSession::HandleReportPvPAFK: %s reported %s", _player->GetName(), reportedPlayer->GetName()); - - reportedPlayer->ReportedAfkBy(_player); -} diff --git a/src/server/game/Server/Protocol/Handlers/CalendarHandler.cpp b/src/server/game/Server/Protocol/Handlers/CalendarHandler.cpp deleted file mode 100755 index be547c84b19..00000000000 --- a/src/server/game/Server/Protocol/Handlers/CalendarHandler.cpp +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "WorldPacket.h" -#include "WorldSession.h" - -#include "InstanceSaveMgr.h" -#include "Log.h" -#include "Opcodes.h" -#include "Player.h" - -void WorldSession::HandleCalendarGetCalendar(WorldPacket& /*recv_data*/) -{ - uint64 guid = _player->GetGUID(); - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_CALENDAR_GET_CALENDAR [" UI64FMTD "]", guid); - - time_t cur_time = time_t(time(NULL)); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_CALENDAR_SEND_CALENDAR [" UI64FMTD "]", guid); - WorldPacket data(SMSG_CALENDAR_SEND_CALENDAR, 4+4*0+4+4*0+4+4); - - data << uint32(0); // invite count - /* - for (;;) - { - uint64 inviteId; - uint64 unkGuid0; - uint8 unk1, unk2, unk3; - uint64 creatorGuid; - } - */ - - data << uint32(0); // event count - /* - for (;;) - { - uint64 eventId; - std::string title; // 128 chars - uint32 type; - uint32 occurrenceTime; - uint32 flags; - uint32 unk4; -- possibly mapid for dungeon/raid - uint64 creatorGuid; - } - */ - - data << uint32(cur_time); // server time - data << uint32(secsToTimeBitFields(cur_time)); // server time - - uint32 counter = 0; - size_t p_counter = data.wpos(); - data << uint32(counter); // instance save count - - for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) - for (Player::BoundInstancesMap::const_iterator itr = _player->m_boundInstances[i].begin(); itr != _player->m_boundInstances[i].end(); ++itr) - if (itr->second.perm) - { - InstanceSave const* save = itr->second.save; - data << uint32(save->GetMapId()); - data << uint32(save->GetDifficulty()); - data << uint32(save->GetResetTime() - cur_time); - data << uint64(save->GetInstanceId()); // instance save id as unique instance copy id - ++counter; - } - - data.put(p_counter, counter); - - data << uint32(1135753200); // unk (28.12.2005 07:00) - - counter = 0; - p_counter = data.wpos(); - data << uint32(counter); // raid reset count - - std::set sentMaps; - - ResetTimeByMapDifficultyMap const& resets = sInstanceSaveMgr->GetResetTimeMap(); - for (ResetTimeByMapDifficultyMap::const_iterator itr = resets.begin(); itr != resets.end(); ++itr) - { - uint32 mapId = PAIR32_LOPART(itr->first); - - if (sentMaps.find(mapId) != sentMaps.end()) - continue; - - MapEntry const* mapEntry = sMapStore.LookupEntry(mapId); - if (!mapEntry || !mapEntry->IsRaid()) - continue; - - sentMaps.insert(mapId); - - data << uint32(mapId); - data << uint32(itr->second - cur_time); - data << uint32(mapEntry->unk_time); - ++counter; - } - - data.put(p_counter, counter); - - data << uint32(0); // holiday count? - /* - for (;;) - { - uint32 unk5, unk6, unk7, unk8, unk9; - for (uint32 j = 0; j < 26; ++j) - { - uint32 unk10; - } - for (uint32 j = 0; j < 10; ++j) - { - uint32 unk11; - } - for (uint32 j = 0; j < 10; ++j) - { - uint32 unk12; - } - std::string holidayName; // 64 chars - } - */ - - SendPacket(&data); -} - -void WorldSession::HandleCalendarGetEvent(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_GET_EVENT"); - recv_data.read_skip(); // unk -} - -void WorldSession::HandleCalendarGuildFilter(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_GUILD_FILTER"); - recv_data.read_skip(); // unk1 - recv_data.read_skip(); // unk2 - recv_data.read_skip(); // unk3 -} - -void WorldSession::HandleCalendarArenaTeam(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_ARENA_TEAM"); - recv_data.read_skip(); // unk -} - -void WorldSession::HandleCalendarAddEvent(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_ADD_EVENT"); - recv_data.rfinish(); // set to end to avoid warnings spam - - //std::string unk1, unk2; - //recv_data >> (std::string)unk1; - //recv_data >> (std::string)unk2; - - //uint8 unk3, unk4; - //uint32 unk5, unk6, unk7, unk8, unk9, count = 0; - //recv_data >> (uint8)unk3; - //recv_data >> (uint8)unk4; - //recv_data >> (uint32)unk5; - //recv_data >> (uint32)unk6; - //recv_data >> (uint32)unk7; - //recv_data >> (uint32)unk8; - //recv_data >> (uint32)unk9; - //if (!((unk9 >> 6) & 1)) - //{ - // recv_data >> (uint32)count; - // if (count) - // { - // uint8 unk12, unk13; - // uint64 guid; - // for (int i=0; i> (uint8)unk12; - // recv_data >> (uint8)unk13; - // } - // } - //} -} - -void WorldSession::HandleCalendarUpdateEvent(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_UPDATE_EVENT"); - recv_data.rfinish(); // set to end to avoid warnings spam - - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> std::string - //recv_data >> std::string - //recv_data >> uint8 - //recv_data >> uint8 - //recv_data >> uint32 - //recv_data >> uint32 - //recv_data >> uint32 - //recv_data >> uint32 - //recv_data >> uint32 -} - -void WorldSession::HandleCalendarRemoveEvent(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_REMOVE_EVENT"); - recv_data.rfinish(); // set to end to avoid warnings spam - - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> uint32 - -} - -void WorldSession::HandleCalendarCopyEvent(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_COPY_EVENT"); - recv_data.rfinish(); // set to end to avoid warnings spam - - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> uint32 - -} - -void WorldSession::HandleCalendarEventInvite(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_EVENT_INVITE"); - recv_data.rfinish(); // set to end to avoid warnings spam - - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> std::string - //recv_data >> uint8 - //recv_data >> uint8 - -} - -void WorldSession::HandleCalendarEventRsvp(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_EVENT_RSVP"); - recv_data.rfinish(); // set to end to avoid warnings spam - - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> uint32 - -} - -void WorldSession::HandleCalendarEventRemoveInvite(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_EVENT_REMOVE_INVITE"); - recv_data.rfinish(); // set to end to avoid warnings spam - - //recv_data.readPackGUID(guid) - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> uint64 -} - -void WorldSession::HandleCalendarEventStatus(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_EVENT_STATUS"); - recv_data.rfinish(); // set to end to avoid warnings spam - - //recv_data.readPackGUID(guid) - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> uint32 -} - -void WorldSession::HandleCalendarEventModeratorStatus(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_EVENT_MODERATOR_STATUS"); - recv_data.rfinish(); // set to end to avoid warnings spam - - //recv_data.readPackGUID(guid) - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> uint32 -} - -void WorldSession::HandleCalendarComplain(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_COMPLAIN"); - recv_data.rfinish(); // set to end to avoid warnings spam - - //recv_data >> uint64 - //recv_data >> uint64 - //recv_data >> uint64 -} - -void WorldSession::HandleCalendarGetNumPending(WorldPacket& /*recv_data*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CALENDAR_GET_NUM_PENDING"); // empty - - WorldPacket data(SMSG_CALENDAR_SEND_NUM_PENDING, 4); - data << uint32(0); // 0 - no pending invites, 1 - some pending invites - SendPacket(&data); -} diff --git a/src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp b/src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp deleted file mode 100755 index 9b749fa8005..00000000000 --- a/src/server/game/Server/Protocol/Handlers/ChannelHandler.cpp +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "ObjectMgr.h" // for normalizePlayerName -#include "ChannelMgr.h" - -void WorldSession::HandleJoinChannel(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); - - uint32 channel_id; - uint8 unknown1, unknown2; - std::string channelname, pass; - - recvPacket >> channel_id; - recvPacket >> unknown1 >> unknown2; - recvPacket >> channelname; - recvPacket >> pass; - - if (channel_id) - { - ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(channel_id); - if (!channel) - return; - - AreaTableEntry const* current_zone = GetAreaEntryByAreaID(_player->GetZoneId()); - if (!current_zone) - return; - - if (!_player->CanJoinConstantChannelInZone(channel, current_zone)) - return; - } - - if (channelname.empty()) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - { - cMgr->team = _player->GetTeam(); - if (Channel* chn = cMgr->GetJoinChannel(channelname, channel_id)) - chn->Join(_player->GetGUID(), pass.c_str()); - } -} - -void WorldSession::HandleLeaveChannel(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); - - uint32 unk; - std::string channelname; - recvPacket >> unk; // channel id? - recvPacket >> channelname; - - if (channelname.empty()) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - { - if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->Leave(_player->GetGUID(), true); - cMgr->LeftChannel(channelname); - } -} - -void WorldSession::HandleChannelList(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); - std::string channelname; - recvPacket >> channelname; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->List(_player); -} - -void WorldSession::HandleChannelPassword(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); - std::string channelname, pass; - recvPacket >> channelname; - - recvPacket >> pass; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->Password(_player->GetGUID(), pass.c_str()); -} - -void WorldSession::HandleChannelSetOwner(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); - std::string channelname, newp; - recvPacket >> channelname; - - recvPacket >> newp; - - if (!normalizePlayerName(newp)) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->SetOwner(_player->GetGUID(), newp.c_str()); -} - -void WorldSession::HandleChannelOwner(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); - std::string channelname; - recvPacket >> channelname; - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->SendWhoOwner(_player->GetGUID()); -} - -void WorldSession::HandleChannelModerator(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); - std::string channelname, otp; - recvPacket >> channelname; - - recvPacket >> otp; - - if (!normalizePlayerName(otp)) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->SetModerator(_player->GetGUID(), otp.c_str()); -} - -void WorldSession::HandleChannelUnmoderator(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); - std::string channelname, otp; - recvPacket >> channelname; - - recvPacket >> otp; - - if (!normalizePlayerName(otp)) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->UnsetModerator(_player->GetGUID(), otp.c_str()); -} - -void WorldSession::HandleChannelMute(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); - std::string channelname, otp; - recvPacket >> channelname; - - recvPacket >> otp; - - if (!normalizePlayerName(otp)) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->SetMute(_player->GetGUID(), otp.c_str()); -} - -void WorldSession::HandleChannelUnmute(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); - - std::string channelname, otp; - recvPacket >> channelname; - - recvPacket >> otp; - - if (!normalizePlayerName(otp)) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->UnsetMute(_player->GetGUID(), otp.c_str()); -} - -void WorldSession::HandleChannelInvite(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); - std::string channelname, otp; - recvPacket >> channelname; - - recvPacket >> otp; - - if (!normalizePlayerName(otp)) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->Invite(_player->GetGUID(), otp.c_str()); -} - -void WorldSession::HandleChannelKick(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); - std::string channelname, otp; - recvPacket >> channelname; - - recvPacket >> otp; - if (!normalizePlayerName(otp)) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->Kick(_player->GetGUID(), otp.c_str()); -} - -void WorldSession::HandleChannelBan(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); - std::string channelname, otp; - recvPacket >> channelname; - - recvPacket >> otp; - - if (!normalizePlayerName(otp)) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->Ban(_player->GetGUID(), otp.c_str()); -} - -void WorldSession::HandleChannelUnban(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); - - std::string channelname, otp; - recvPacket >> channelname; - - recvPacket >> otp; - - if (!normalizePlayerName(otp)) - return; - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->UnBan(_player->GetGUID(), otp.c_str()); -} - -void WorldSession::HandleChannelAnnouncements(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); - std::string channelname; - recvPacket >> channelname; - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->Announce(_player->GetGUID()); -} - -void WorldSession::HandleChannelDisplayListQuery(WorldPacket &recvPacket) -{ - // this should be OK because the 2 function _were_ the same - HandleChannelList(recvPacket); -} - -void WorldSession::HandleGetChannelMemberCount(WorldPacket &recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); - std::string channelname; - recvPacket >> channelname; - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - { - if (Channel* chn = cMgr->GetChannel(channelname, _player)) - { - WorldPacket data(SMSG_CHANNEL_MEMBER_COUNT, chn->GetName().size()+1+1+4); - data << chn->GetName(); - data << uint8(chn->GetFlags()); - data << uint32(chn->GetNumPlayers()); - SendPacket(&data); - } - } -} - -void WorldSession::HandleSetChannelWatch(WorldPacket &recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); - std::string channelname; - recvPacket >> channelname; - /*if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - if (Channel* chn = cMgr->GetChannel(channelname, _player)) - chn->JoinNotify(_player->GetGUID());*/ -} - diff --git a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp deleted file mode 100644 index bd9668ce5b8..00000000000 --- a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp +++ /dev/null @@ -1,1915 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "ObjectAccessor.h" -#include "ObjectMgr.h" -#include "ArenaTeamMgr.h" -#include "GuildMgr.h" -#include "SystemConfig.h" -#include "World.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "DatabaseEnv.h" - -#include "ArenaTeam.h" -#include "Chat.h" -#include "Group.h" -#include "Guild.h" -#include "Language.h" -#include "Log.h" -#include "Opcodes.h" -#include "Player.h" -#include "PlayerDump.h" -#include "SharedDefines.h" -#include "SocialMgr.h" -#include "UpdateMask.h" -#include "Util.h" -#include "ScriptMgr.h" -#include "Battleground.h" -#include "AccountMgr.h" -#include "LFGMgr.h" - -class LoginQueryHolder : public SQLQueryHolder -{ - private: - uint32 m_accountId; - uint64 m_guid; - public: - LoginQueryHolder(uint32 accountId, uint64 guid) - : m_accountId(accountId), m_guid(guid) { } - uint64 GetGuid() const { return m_guid; } - uint32 GetAccountId() const { return m_accountId; } - bool Initialize(); -}; - -bool LoginQueryHolder::Initialize() -{ - SetSize(MAX_PLAYER_LOGIN_QUERY); - - bool res = true; - uint32 lowGuid = GUID_LOPART(m_guid); - PreparedStatement* stmt = NULL; - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADFROM, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GROUP_MEMBER); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADGROUP, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_INSTANCE); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_AURAS); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADAURAS, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SPELL); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADSPELLS, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUS); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_DAILYQUESTSTATUS); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_WEEKLYQUESTSTATUS); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADWEEKLYQUESTSTATUS, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SEASONALQUESTSTATUS); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADSEASONALQUESTSTATUS, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_REPUTATION); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADREPUTATION, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_INVENTORY); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADINVENTORY, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACTIONS); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADACTIONS, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MAILCOUNT); - stmt->setUInt32(0, lowGuid); - stmt->setUInt64(1, uint64(time(NULL))); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADMAILCOUNT, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MAILDATE); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADMAILDATE, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SOCIALLIST); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADSOCIALLIST, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_HOMEBIND); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADHOMEBIND, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADSPELLCOOLDOWNS, stmt); - - if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED)) - { - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_DECLINEDNAMES); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES, stmt); - } - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADGUILD, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ARENAINFO); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADARENAINFO, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACHIEVEMENTS); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADACHIEVEMENTS, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_CRITERIAPROGRESS); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADCRITERIAPROGRESS, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_EQUIPMENTSETS); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADEQUIPMENTSETS, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_BGDATA); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADBGDATA, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GLYPHS); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADGLYPHS, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_TALENTS); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADTALENTS, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PLAYER_ACCOUNT_DATA); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADACCOUNTDATA, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SKILLS); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADSKILLS, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_RANDOMBG); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADRANDOMBG, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_BANNED); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADBANNED, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUSREW); - stmt->setUInt32(0, lowGuid); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADQUESTSTATUSREW, stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES); - stmt->setUInt32(0, m_accountId); - res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADINSTANCELOCKTIMES, stmt); - - return res; -} - -void WorldSession::HandleCharEnum(PreparedQueryResult result) -{ - WorldPacket data(SMSG_CHAR_ENUM, 100); // we guess size - - uint8 num = 0; - - data << num; - - _allowedCharsToLogin.clear(); - if (result) - { - do - { - uint32 guidlow = (*result)[0].GetUInt32(); - sLog->outDetail("Loading char guid %u from account %u.", guidlow, GetAccountId()); - if (Player::BuildEnumData(result, &data)) - { - _allowedCharsToLogin.insert(guidlow); - ++num; - } - } - while (result->NextRow()); - } - - data.put(0, num); - - SendPacket(&data); -} - -void WorldSession::HandleCharEnumOpcode(WorldPacket & /*recv_data*/) -{ - // remove expired bans - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_EXPIRED_BANS); - CharacterDatabase.Execute(stmt); - - /// get all the data necessary for loading all characters (along with their pets) on the account - - if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED)) - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ENUM_DECLINED_NAME); - else - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ENUM); - - stmt->setUInt8(0, PET_SAVE_AS_CURRENT); - stmt->setUInt32(1, GetAccountId()); - - _charEnumCallback = CharacterDatabase.AsyncQuery(stmt); -} - -void WorldSession::HandleCharCreateOpcode(WorldPacket & recv_data) -{ - std::string name; - uint8 race_, class_; - - recv_data >> name; - - recv_data >> race_; - recv_data >> class_; - - // extract other data required for player creating - uint8 gender, skin, face, hairStyle, hairColor, facialHair, outfitId; - recv_data >> gender >> skin >> face; - recv_data >> hairStyle >> hairColor >> facialHair >> outfitId; - - WorldPacket data(SMSG_CHAR_CREATE, 1); // returned with diff.values in all cases - - if (AccountMgr::IsPlayerAccount(GetSecurity())) - { - if (uint32 mask = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED)) - { - bool disabled = false; - - uint32 team = Player::TeamForRace(race_); - switch (team) - { - case ALLIANCE: disabled = mask & (1 << 0); break; - case HORDE: disabled = mask & (1 << 1); break; - } - - if (disabled) - { - data << (uint8)CHAR_CREATE_DISABLED; - SendPacket(&data); - return; - } - } - } - - ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(class_); - if (!classEntry) - { - data << (uint8)CHAR_CREATE_FAILED; - SendPacket(&data); - sLog->outError("Class (%u) not found in DBC while creating new char for account (ID: %u): wrong DBC files or cheater?", class_, GetAccountId()); - return; - } - - ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(race_); - if (!raceEntry) - { - data << (uint8)CHAR_CREATE_FAILED; - SendPacket(&data); - sLog->outError("Race (%u) not found in DBC while creating new char for account (ID: %u): wrong DBC files or cheater?", race_, GetAccountId()); - return; - } - - // prevent character creating Expansion race without Expansion account - if (raceEntry->expansion > Expansion()) - { - data << (uint8)CHAR_CREATE_EXPANSION; - sLog->outError("Expansion %u account:[%d] tried to Create character with expansion %u race (%u)", Expansion(), GetAccountId(), raceEntry->expansion, race_); - SendPacket(&data); - return; - } - - // prevent character creating Expansion class without Expansion account - if (classEntry->expansion > Expansion()) - { - data << (uint8)CHAR_CREATE_EXPANSION_CLASS; - sLog->outError("Expansion %u account:[%d] tried to Create character with expansion %u class (%u)", Expansion(), GetAccountId(), classEntry->expansion, class_); - SendPacket(&data); - return; - } - - if (AccountMgr::IsPlayerAccount(GetSecurity())) - { - uint32 raceMaskDisabled = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK); - if ((1 << (race_ - 1)) & raceMaskDisabled) - { - data << uint8(CHAR_CREATE_DISABLED); - SendPacket(&data); - return; - } - - uint32 classMaskDisabled = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK); - if ((1 << (class_ - 1)) & classMaskDisabled) - { - data << uint8(CHAR_CREATE_DISABLED); - SendPacket(&data); - return; - } - } - - // prevent character creating with invalid name - if (!normalizePlayerName(name)) - { - data << (uint8)CHAR_NAME_NO_NAME; - SendPacket(&data); - sLog->outError("Account:[%d] but tried to Create character with empty [name] ", GetAccountId()); - return; - } - - // check name limitations - uint8 res = ObjectMgr::CheckPlayerName(name, true); - if (res != CHAR_NAME_SUCCESS) - { - data << uint8(res); - SendPacket(&data); - return; - } - - if (AccountMgr::IsPlayerAccount(GetSecurity()) && sObjectMgr->IsReservedName(name)) - { - data << (uint8)CHAR_NAME_RESERVED; - SendPacket(&data); - return; - } - - // speedup check for heroic class disabled case - uint32 heroic_free_slots = sWorld->getIntConfig(CONFIG_HEROIC_CHARACTERS_PER_REALM); - if (heroic_free_slots == 0 && AccountMgr::IsPlayerAccount(GetSecurity()) && class_ == CLASS_DEATH_KNIGHT) - { - data << (uint8)CHAR_CREATE_UNIQUE_CLASS_LIMIT; - SendPacket(&data); - return; - } - - // speedup check for heroic class disabled case - uint32 req_level_for_heroic = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER); - if (AccountMgr::IsPlayerAccount(GetSecurity()) && class_ == CLASS_DEATH_KNIGHT && req_level_for_heroic > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - data << (uint8)CHAR_CREATE_LEVEL_REQUIREMENT; - SendPacket(&data); - return; - } - - delete _charCreateCallback.GetParam(); // Delete existing if any, to make the callback chain reset to stage 0 - _charCreateCallback.SetParam(new CharacterCreateInfo(name, race_, class_, gender, skin, face, hairStyle, hairColor, facialHair, outfitId, recv_data)); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); - stmt->setString(0, name); - _charCreateCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); -} - -void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, CharacterCreateInfo* createInfo) -{ - /** This is a series of callbacks executed consecutively as a result from the database becomes available. - This is much more efficient than synchronous requests on packet handler, and much less DoS prone. - It also prevents data syncrhonisation errors. - */ - switch (_charCreateCallback.GetStage()) - { - case 0: - { - if (result) - { - WorldPacket data(SMSG_CHAR_CREATE, 1); - data << uint8(CHAR_CREATE_NAME_IN_USE); - SendPacket(&data); - delete createInfo; - _charCreateCallback.Reset(); - return; - } - - ASSERT(_charCreateCallback.GetParam() == createInfo); - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SUM_REALM_CHARACTERS); - stmt->setUInt32(0, GetAccountId()); - - _charCreateCallback.FreeResult(); - _charCreateCallback.SetFutureResult(LoginDatabase.AsyncQuery(stmt)); - _charCreateCallback.NextStage(); - } - break; - case 1: - { - uint16 acctCharCount = 0; - if (result) - { - Field* fields = result->Fetch(); - // SELECT SUM(x) is MYSQL_TYPE_NEWDECIMAL - needs to be read as string - const char* ch = fields[0].GetCString(); - if (ch) - acctCharCount = atoi(ch); - } - - if (acctCharCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_ACCOUNT)) - { - WorldPacket data(SMSG_CHAR_CREATE, 1); - data << uint8(CHAR_CREATE_ACCOUNT_LIMIT); - SendPacket(&data); - delete createInfo; - _charCreateCallback.Reset(); - return; - } - - - ASSERT(_charCreateCallback.GetParam() == createInfo); - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS); - stmt->setUInt32(0, GetAccountId()); - - _charCreateCallback.FreeResult(); - _charCreateCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); - _charCreateCallback.NextStage(); - } - break; - case 2: - { - if (result) - { - Field* fields = result->Fetch(); - createInfo->CharCount = fields[0].GetUInt8(); - - if (createInfo->CharCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM)) - { - WorldPacket data(SMSG_CHAR_CREATE, 1); - data << uint8(CHAR_CREATE_SERVER_LIMIT); - SendPacket(&data); - delete createInfo; - _charCreateCallback.Reset(); - return; - } - } - - bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS) || !AccountMgr::IsPlayerAccount(GetSecurity()); - uint32 skipCinematics = sWorld->getIntConfig(CONFIG_SKIP_CINEMATICS); - - _charCreateCallback.FreeResult(); - - if (!allowTwoSideAccounts || skipCinematics == 1 || createInfo->Class == CLASS_DEATH_KNIGHT) - { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_CREATE_INFO); - stmt->setUInt32(0, GetAccountId()); - stmt->setUInt32(1, (skipCinematics == 1 || createInfo->Class == CLASS_DEATH_KNIGHT) ? 10 : 1); - _charCreateCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); - _charCreateCallback.NextStage(); - return; - } - - _charCreateCallback.NextStage(); - HandleCharCreateCallback(PreparedQueryResult(NULL), createInfo); // Will jump to case 3 - } - break; - case 3: - { - bool haveSameRace = false; - uint32 heroicReqLevel = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER); - bool hasHeroicReqLevel = (heroicReqLevel == 0); - bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS) || !AccountMgr::IsPlayerAccount(GetSecurity()); - uint32 skipCinematics = sWorld->getIntConfig(CONFIG_SKIP_CINEMATICS); - - if (result) - { - uint32 team = Player::TeamForRace(createInfo->Race); - uint32 freeHeroicSlots = sWorld->getIntConfig(CONFIG_HEROIC_CHARACTERS_PER_REALM); - - Field* field = result->Fetch(); - uint8 accRace = field[1].GetUInt8(); - - if (AccountMgr::IsPlayerAccount(GetSecurity()) && createInfo->Class == CLASS_DEATH_KNIGHT) - { - uint8 accClass = field[2].GetUInt8(); - if (accClass == CLASS_DEATH_KNIGHT) - { - if (freeHeroicSlots > 0) - --freeHeroicSlots; - - if (freeHeroicSlots == 0) - { - WorldPacket data(SMSG_CHAR_CREATE, 1); - data << uint8(CHAR_CREATE_UNIQUE_CLASS_LIMIT); - SendPacket(&data); - delete createInfo; - _charCreateCallback.Reset(); - return; - } - } - - if (!hasHeroicReqLevel) - { - uint8 accLevel = field[0].GetUInt8(); - if (accLevel >= heroicReqLevel) - hasHeroicReqLevel = true; - } - } - - // need to check team only for first character - // TODO: what to if account already has characters of both races? - if (!allowTwoSideAccounts) - { - uint32 accTeam = 0; - if (accRace > 0) - accTeam = Player::TeamForRace(accRace); - - if (accTeam != team) - { - WorldPacket data(SMSG_CHAR_CREATE, 1); - data << uint8(CHAR_CREATE_PVP_TEAMS_VIOLATION); - SendPacket(&data); - delete createInfo; - _charCreateCallback.Reset(); - return; - } - } - - // search same race for cinematic or same class if need - // TODO: check if cinematic already shown? (already logged in?; cinematic field) - while ((skipCinematics == 1 && !haveSameRace) || createInfo->Class == CLASS_DEATH_KNIGHT) - { - if (!result->NextRow()) - break; - - field = result->Fetch(); - accRace = field[1].GetUInt8(); - - if (!haveSameRace) - haveSameRace = createInfo->Race == accRace; - - if (AccountMgr::IsPlayerAccount(GetSecurity()) && createInfo->Class == CLASS_DEATH_KNIGHT) - { - uint8 acc_class = field[2].GetUInt8(); - if (acc_class == CLASS_DEATH_KNIGHT) - { - if (freeHeroicSlots > 0) - --freeHeroicSlots; - - if (freeHeroicSlots == 0) - { - WorldPacket data(SMSG_CHAR_CREATE, 1); - data << uint8(CHAR_CREATE_UNIQUE_CLASS_LIMIT); - SendPacket(&data); - delete createInfo; - _charCreateCallback.Reset(); - return; - } - } - - if (!hasHeroicReqLevel) - { - uint8 acc_level = field[0].GetUInt8(); - if (acc_level >= heroicReqLevel) - hasHeroicReqLevel = true; - } - } - } - } - - if (AccountMgr::IsPlayerAccount(GetSecurity()) && createInfo->Class == CLASS_DEATH_KNIGHT && !hasHeroicReqLevel) - { - WorldPacket data(SMSG_CHAR_CREATE, 1); - data << uint8(CHAR_CREATE_LEVEL_REQUIREMENT); - SendPacket(&data); - delete createInfo; - _charCreateCallback.Reset(); - return; - } - - if (createInfo->Data.rpos() < createInfo->Data.wpos()) - { - uint8 unk; - createInfo->Data >> unk; - sLog->outDebug(LOG_FILTER_NETWORKIO, "Character creation %s (account %u) has unhandled tail data: [%u]", createInfo->Name.c_str(), GetAccountId(), unk); - } - - Player newChar(this); - if (!newChar.Create(sObjectMgr->GenerateLowGuid(HIGHGUID_PLAYER), createInfo)) - { - // Player not create (race/class/etc problem?) - newChar.CleanupsBeforeDelete(); - - WorldPacket data(SMSG_CHAR_CREATE, 1); - data << uint8(CHAR_CREATE_ERROR); - SendPacket(&data); - delete createInfo; - _charCreateCallback.Reset(); - return; - } - - if ((haveSameRace && skipCinematics == 1) || skipCinematics == 2) - newChar.setCinematic(1); // not show intro - - newChar.SetAtLoginFlag(AT_LOGIN_FIRST); // First login - - // Player created, save it now - newChar.SaveToDB(true); - createInfo->CharCount += 1; - - SQLTransaction trans = LoginDatabase.BeginTransaction(); - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS); - stmt->setUInt32(0, GetAccountId()); - stmt->setUInt32(1, realmID); - trans->Append(stmt); - - stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS); - stmt->setUInt32(0, createInfo->CharCount); - stmt->setUInt32(1, GetAccountId()); - stmt->setUInt32(2, realmID); - trans->Append(stmt); - - LoginDatabase.CommitTransaction(trans); - - newChar.CleanupsBeforeDelete(); - - WorldPacket data(SMSG_CHAR_CREATE, 1); - data << uint8(CHAR_CREATE_SUCCESS); - SendPacket(&data); - - std::string IP_str = GetRemoteAddress(); - sLog->outDetail("Account: %d (IP: %s) Create Character:[%s] (GUID: %u)", GetAccountId(), IP_str.c_str(), createInfo->Name.c_str(), newChar.GetGUIDLow()); - sLog->outChar("Account: %d (IP: %s) Create Character:[%s] (GUID: %u)", GetAccountId(), IP_str.c_str(), createInfo->Name.c_str(), newChar.GetGUIDLow()); - sScriptMgr->OnPlayerCreate(&newChar); - sWorld->AddCharacterNameData(newChar.GetGUIDLow(), std::string(newChar.GetName()), newChar.getGender(), newChar.getRace(), newChar.getClass()); - - delete createInfo; - _charCreateCallback.Reset(); - } - break; - } -} - -void WorldSession::HandleCharDeleteOpcode(WorldPacket & recv_data) -{ - uint64 guid; - recv_data >> guid; - - // can't delete loaded character - if (ObjectAccessor::FindPlayer(guid)) - return; - - uint32 accountId = 0; - std::string name; - - // is guild leader - if (sGuildMgr->GetGuildByLeader(guid)) - { - WorldPacket data(SMSG_CHAR_DELETE, 1); - data << (uint8)CHAR_DELETE_FAILED_GUILD_LEADER; - SendPacket(&data); - return; - } - - // is arena team captain - if (sArenaTeamMgr->GetArenaTeamByCaptain(guid)) - { - WorldPacket data(SMSG_CHAR_DELETE, 1); - data << (uint8)CHAR_DELETE_FAILED_ARENA_CAPTAIN; - SendPacket(&data); - return; - } - - QueryResult result = CharacterDatabase.PQuery("SELECT account, name FROM characters WHERE guid='%u'", GUID_LOPART(guid)); - if (result) - { - Field* fields = result->Fetch(); - accountId = fields[0].GetUInt32(); - name = fields[1].GetString(); - } - - // prevent deleting other players' characters using cheating tools - if (accountId != GetAccountId()) - return; - - std::string IP_str = GetRemoteAddress(); - sLog->outDetail("Account: %d (IP: %s) Delete Character:[%s] (GUID: %u)", GetAccountId(), IP_str.c_str(), name.c_str(), GUID_LOPART(guid)); - sLog->outChar("Account: %d (IP: %s) Delete Character:[%s] (GUID: %u)", GetAccountId(), IP_str.c_str(), name.c_str(), GUID_LOPART(guid)); - sScriptMgr->OnPlayerDelete(guid); - sWorld->DeleteCharaceterNameData(GUID_LOPART(guid)); - - if (sLog->IsOutCharDump()) // optimize GetPlayerDump call - { - std::string dump; - if (PlayerDumpWriter().GetDump(GUID_LOPART(guid), dump)) - sLog->outCharDump(dump.c_str(), GetAccountId(), GUID_LOPART(guid), name.c_str()); - } - - Player::DeleteFromDB(guid, GetAccountId()); - - WorldPacket data(SMSG_CHAR_DELETE, 1); - data << (uint8)CHAR_DELETE_SUCCESS; - SendPacket(&data); -} - -void WorldSession::HandlePlayerLoginOpcode(WorldPacket & recv_data) -{ - if (PlayerLoading() || GetPlayer() != NULL) - { - sLog->outError("Player tryes to login again, AccountId = %d", GetAccountId()); - return; - } - - m_playerLoading = true; - uint64 playerGuid = 0; - - sLog->outStaticDebug("WORLD: Recvd Player Logon Message"); - - recv_data >> playerGuid; - - if (!CharCanLogin(GUID_LOPART(playerGuid))) - { - sLog->outError("Account (%u) can't login with that character (%u).", GetAccountId(), GUID_LOPART(playerGuid)); - KickPlayer(); - return; - } - - LoginQueryHolder *holder = new LoginQueryHolder(GetAccountId(), playerGuid); - if (!holder->Initialize()) - { - delete holder; // delete all unprocessed queries - m_playerLoading = false; - return; - } - - _charLoginCallback = CharacterDatabase.DelayQueryHolder((SQLQueryHolder*)holder); -} - -void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) -{ - uint64 playerGuid = holder->GetGuid(); - - Player* pCurrChar = new Player(this); - // for send server info and strings (config) - ChatHandler chH = ChatHandler(pCurrChar); - - // "GetAccountId() == db stored account id" checked in LoadFromDB (prevent login not own character using cheating tools) - if (!pCurrChar->LoadFromDB(GUID_LOPART(playerGuid), holder)) - { - SetPlayer(NULL); - KickPlayer(); // disconnect client, player no set to session and it will not deleted or saved at kick - delete pCurrChar; // delete it manually - delete holder; // delete all unprocessed queries - m_playerLoading = false; - return; - } - - pCurrChar->GetMotionMaster()->Initialize(); - pCurrChar->SendDungeonDifficulty(false); - - WorldPacket data(SMSG_LOGIN_VERIFY_WORLD, 20); - data << pCurrChar->GetMapId(); - data << pCurrChar->GetPositionX(); - data << pCurrChar->GetPositionY(); - data << pCurrChar->GetPositionZ(); - data << pCurrChar->GetOrientation(); - SendPacket(&data); - - // load player specific part before send times - LoadAccountData(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADACCOUNTDATA), PER_CHARACTER_CACHE_MASK); - SendAccountDataTimes(PER_CHARACTER_CACHE_MASK); - - data.Initialize(SMSG_FEATURE_SYSTEM_STATUS, 2); // added in 2.2.0 - data << uint8(2); // unknown value - data << uint8(0); // enable(1)/disable(0) voice chat interface in client - SendPacket(&data); - - // Send MOTD - { - data.Initialize(SMSG_MOTD, 50); // new in 2.0.1 - data << (uint32)0; - - uint32 linecount=0; - std::string str_motd = sWorld->GetMotd(); - std::string::size_type pos, nextpos; - - pos = 0; - while ((nextpos= str_motd.find('@', pos)) != std::string::npos) - { - if (nextpos != pos) - { - data << str_motd.substr(pos, nextpos-pos); - ++linecount; - } - pos = nextpos+1; - } - - if (posoutStaticDebug("WORLD: Sent motd (SMSG_MOTD)"); - - // send server info - if (sWorld->getIntConfig(CONFIG_ENABLE_SINFO_LOGIN) == 1) - chH.PSendSysMessage(_FULLVERSION); - - sLog->outStaticDebug("WORLD: Sent server info"); - } - - //QueryResult* result = CharacterDatabase.PQuery("SELECT guildid, rank FROM guild_member WHERE guid = '%u'", pCurrChar->GetGUIDLow()); - if (PreparedQueryResult resultGuild = holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADGUILD)) - { - Field* fields = resultGuild->Fetch(); - pCurrChar->SetInGuild(fields[0].GetUInt32()); - pCurrChar->SetRank(fields[1].GetUInt8()); - } - else if (pCurrChar->GetGuildId()) // clear guild related fields in case wrong data about non existed membership - { - pCurrChar->SetInGuild(0); - pCurrChar->SetRank(0); - } - - if (pCurrChar->GetGuildId() != 0) - { - if (Guild* guild = sGuildMgr->GetGuildById(pCurrChar->GetGuildId())) - guild->SendLoginInfo(this); - else - { - // remove wrong guild data - sLog->outError("Player %s (GUID: %u) marked as member of not existing guild (id: %u), removing guild membership for player.", pCurrChar->GetName(), pCurrChar->GetGUIDLow(), pCurrChar->GetGuildId()); - pCurrChar->SetInGuild(0); - } - } - - data.Initialize(SMSG_LEARNED_DANCE_MOVES, 4+4); - data << uint32(0); - data << uint32(0); - SendPacket(&data); - - pCurrChar->SendInitialPacketsBeforeAddToMap(); - - //Show cinematic at the first time that player login - if (!pCurrChar->getCinematic()) - { - pCurrChar->setCinematic(1); - - if (ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(pCurrChar->getClass())) - { - if (cEntry->CinematicSequence) - pCurrChar->SendCinematicStart(cEntry->CinematicSequence); - else if (ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(pCurrChar->getRace())) - pCurrChar->SendCinematicStart(rEntry->CinematicSequence); - - // send new char string if not empty - if (!sWorld->GetNewCharString().empty()) - chH.PSendSysMessage("%s", sWorld->GetNewCharString().c_str()); - } - } - - if (Group* group = pCurrChar->GetGroup()) - { - if (group->isLFGGroup()) - { - LfgDungeonSet Dungeons; - Dungeons.insert(sLFGMgr->GetDungeon(group->GetGUID())); - sLFGMgr->SetSelectedDungeons(pCurrChar->GetGUID(), Dungeons); - sLFGMgr->SetState(pCurrChar->GetGUID(), sLFGMgr->GetState(group->GetGUID())); - } - } - - if (!pCurrChar->GetMap()->AddPlayerToMap(pCurrChar) || !pCurrChar->CheckInstanceLoginValid()) - { - AreaTrigger const* at = sObjectMgr->GetGoBackTrigger(pCurrChar->GetMapId()); - if (at) - pCurrChar->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, pCurrChar->GetOrientation()); - else - pCurrChar->TeleportTo(pCurrChar->m_homebindMapId, pCurrChar->m_homebindX, pCurrChar->m_homebindY, pCurrChar->m_homebindZ, pCurrChar->GetOrientation()); - } - - sObjectAccessor->AddObject(pCurrChar); - //sLog->outDebug("Player %s added to Map.", pCurrChar->GetName()); - - pCurrChar->SendInitialPacketsAfterAddToMap(); - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_ONLINE); - - stmt->setUInt32(0, pCurrChar->GetGUIDLow()); - - CharacterDatabase.Execute(stmt); - - stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_ONLINE); - - stmt->setUInt32(0, GetAccountId()); - - LoginDatabase.Execute(stmt); - - pCurrChar->SetInGameTime(getMSTime()); - - // announce group about member online (must be after add to player list to receive announce to self) - if (Group* group = pCurrChar->GetGroup()) - { - //pCurrChar->groupInfo.group->SendInit(this); // useless - group->SendUpdate(); - group->ResetMaxEnchantingLevel(); - } - - // friend status - sSocialMgr->SendFriendStatus(pCurrChar, FRIEND_ONLINE, pCurrChar->GetGUIDLow(), true); - - // Place character in world (and load zone) before some object loading - pCurrChar->LoadCorpse(); - - // setting Ghost+speed if dead - if (pCurrChar->m_deathState != ALIVE) - { - // not blizz like, we must correctly save and load player instead... - if (pCurrChar->getRace() == RACE_NIGHTELF) - pCurrChar->CastSpell(pCurrChar, 20584, true, 0);// auras SPELL_AURA_INCREASE_SPEED(+speed in wisp form), SPELL_AURA_INCREASE_SWIM_SPEED(+swim speed in wisp form), SPELL_AURA_TRANSFORM (to wisp form) - pCurrChar->CastSpell(pCurrChar, 8326, true, 0); // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?) - - pCurrChar->SetMovement(MOVE_WATER_WALK); - } - - pCurrChar->ContinueTaxiFlight(); - - // reset for all pets before pet loading - if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS)) - Pet::resetTalentsForAllPetsOf(pCurrChar); - - // Load pet if any (if player not alive and in taxi flight or another then pet will remember as temporary unsummoned) - pCurrChar->LoadPet(); - - // Set FFA PvP for non GM in non-rest mode - if (sWorld->IsFFAPvPRealm() && !pCurrChar->isGameMaster() && !pCurrChar->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING)) - pCurrChar->SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); - - if (pCurrChar->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP)) - pCurrChar->SetContestedPvP(); - - // Apply at_login requests - if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_SPELLS)) - { - pCurrChar->resetSpells(); - SendNotification(LANG_RESET_SPELLS); - } - - if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_TALENTS)) - { - pCurrChar->resetTalents(true); - pCurrChar->SendTalentsInfoData(false); // original talents send already in to SendInitialPacketsBeforeAddToMap, resend reset state - SendNotification(LANG_RESET_TALENTS); - } - - if (pCurrChar->HasAtLoginFlag(AT_LOGIN_FIRST)) - pCurrChar->RemoveAtLoginFlag(AT_LOGIN_FIRST); - - // show time before shutdown if shutdown planned. - if (sWorld->IsShuttingDown()) - sWorld->ShutdownMsg(true, pCurrChar); - - if (sWorld->getBoolConfig(CONFIG_ALL_TAXI_PATHS)) - pCurrChar->SetTaxiCheater(true); - - if (pCurrChar->isGameMaster()) - SendNotification(LANG_GM_ON); - - std::string IP_str = GetRemoteAddress(); - sLog->outChar("Account: %d (IP: %s) Login Character:[%s] (GUID: %u)", - GetAccountId(), IP_str.c_str(), pCurrChar->GetName(), pCurrChar->GetGUIDLow()); - - if (!pCurrChar->IsStandState() && !pCurrChar->HasUnitState(UNIT_STAT_STUNNED)) - pCurrChar->SetStandState(UNIT_STAND_STATE_STAND); - - m_playerLoading = false; - - sScriptMgr->OnPlayerLogin(pCurrChar); - delete holder; -} - -void WorldSession::HandleSetFactionAtWar(WorldPacket & recv_data) -{ - sLog->outStaticDebug("WORLD: Received CMSG_SET_FACTION_ATWAR"); - - uint32 repListID; - uint8 flag; - - recv_data >> repListID; - recv_data >> flag; - - GetPlayer()->GetReputationMgr().SetAtWar(repListID, flag); -} - -//I think this function is never used :/ I dunno, but i guess this opcode not exists -void WorldSession::HandleSetFactionCheat(WorldPacket & /*recv_data*/) -{ - sLog->outError("WORLD SESSION: HandleSetFactionCheat, not expected call, please report."); - GetPlayer()->GetReputationMgr().SendStates(); -} - -void WorldSession::HandleTutorialFlag(WorldPacket & recv_data) -{ - uint32 data; - recv_data >> data; - - uint8 index = uint8(data / 32); - if (index >= MAX_ACCOUNT_TUTORIAL_VALUES) - return; - - uint32 value = (data % 32); - - uint32 flag = GetTutorialInt(index); - flag |= (1 << value); - SetTutorialInt(index, flag); -} - -void WorldSession::HandleTutorialClear(WorldPacket & /*recv_data*/) -{ - for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i) - SetTutorialInt(i, 0xFFFFFFFF); -} - -void WorldSession::HandleTutorialReset(WorldPacket & /*recv_data*/) -{ - for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i) - SetTutorialInt(i, 0x00000000); -} - -void WorldSession::HandleSetWatchedFactionOpcode(WorldPacket & recv_data) -{ - sLog->outStaticDebug("WORLD: Received CMSG_SET_WATCHED_FACTION"); - uint32 fact; - recv_data >> fact; - GetPlayer()->SetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, fact); -} - -void WorldSession::HandleSetFactionInactiveOpcode(WorldPacket & recv_data) -{ - sLog->outStaticDebug("WORLD: Received CMSG_SET_FACTION_INACTIVE"); - uint32 replistid; - uint8 inactive; - recv_data >> replistid >> inactive; - - _player->GetReputationMgr().SetInactive(replistid, inactive); -} - -void WorldSession::HandleShowingHelmOpcode(WorldPacket& recv_data) -{ - sLog->outStaticDebug("CMSG_SHOWING_HELM for %s", _player->GetName()); - recv_data.read_skip(); // unknown, bool? - _player->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM); -} - -void WorldSession::HandleShowingCloakOpcode(WorldPacket& recv_data) -{ - sLog->outStaticDebug("CMSG_SHOWING_CLOAK for %s", _player->GetName()); - recv_data.read_skip(); // unknown, bool? - _player->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK); -} - -void WorldSession::HandleCharRenameOpcode(WorldPacket& recv_data) -{ - uint64 guid; - std::string newName; - - recv_data >> guid; - recv_data >> newName; - - // prevent character rename to invalid name - if (!normalizePlayerName(newName)) - { - WorldPacket data(SMSG_CHAR_RENAME, 1); - data << uint8(CHAR_NAME_NO_NAME); - SendPacket(&data); - return; - } - - uint8 res = ObjectMgr::CheckPlayerName(newName, true); - if (res != CHAR_NAME_SUCCESS) - { - WorldPacket data(SMSG_CHAR_RENAME, 1); - data << uint8(res); - SendPacket(&data); - return; - } - - // check name limitations - if (AccountMgr::IsPlayerAccount(GetSecurity()) && sObjectMgr->IsReservedName(newName)) - { - WorldPacket data(SMSG_CHAR_RENAME, 1); - data << uint8(CHAR_NAME_RESERVED); - SendPacket(&data); - return; - } - - // Ensure that the character belongs to the current account, that rename at login is enabled - // and that there is no character with the desired new name - _charRenameCallback.SetParam(newName); - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_FREE_NAME); - - stmt->setUInt32(0, GUID_LOPART(guid)); - stmt->setUInt32(1, GetAccountId()); - stmt->setUInt16(2, AT_LOGIN_RENAME); - stmt->setUInt16(3, AT_LOGIN_RENAME); - stmt->setString(4, newName); - - _charRenameCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); -} - -void WorldSession::HandleChangePlayerNameOpcodeCallBack(PreparedQueryResult result, std::string newName) -{ - if (!result) - { - WorldPacket data(SMSG_CHAR_RENAME, 1); - data << uint8(CHAR_CREATE_ERROR); - SendPacket(&data); - return; - } - - Field* fields = result->Fetch(); - - uint32 guidLow = fields[0].GetUInt32(); - std::string oldName = fields[1].GetString(); - - uint64 guid = MAKE_NEW_GUID(guidLow, 0, HIGHGUID_PLAYER); - - // Update name and at_login flag in the db - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_NAME); - - stmt->setString(0, newName); - stmt->setUInt16(1, AT_LOGIN_RENAME); - stmt->setUInt32(2, guidLow); - - CharacterDatabase.Execute(stmt); - - // Removed declined name from db - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_DECLINED_NAME); - - stmt->setUInt32(0, guidLow); - - CharacterDatabase.Execute(stmt); - - sLog->outChar("Account: %d (IP: %s) Character:[%s] (guid:%u) Changed name to: %s", GetAccountId(), GetRemoteAddress().c_str(), oldName.c_str(), guidLow, newName.c_str()); - - WorldPacket data(SMSG_CHAR_RENAME, 1+8+(newName.size()+1)); - data << uint8(RESPONSE_SUCCESS); - data << uint64(guid); - data << newName; - SendPacket(&data); - - sWorld->UpdateCharacterNameData(guidLow, newName); -} - -void WorldSession::HandleSetPlayerDeclinedNames(WorldPacket& recv_data) -{ - uint64 guid; - - recv_data >> guid; - - // not accept declined names for unsupported languages - std::string name; - if (!sObjectMgr->GetPlayerNameByGUID(guid, name)) - { - WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); - data << uint32(1); - data << uint64(guid); - SendPacket(&data); - return; - } - - std::wstring wname; - if (!Utf8toWStr(name, wname)) - { - WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); - data << uint32(1); - data << uint64(guid); - SendPacket(&data); - return; - } - - if (!isCyrillicCharacter(wname[0])) // name already stored as only single alphabet using - { - WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); - data << uint32(1); - data << uint64(guid); - SendPacket(&data); - return; - } - - std::string name2; - DeclinedName declinedname; - - recv_data >> name2; - - if (name2 != name) // character have different name - { - WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); - data << uint32(1); - data << uint64(guid); - SendPacket(&data); - return; - } - - for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i) - { - recv_data >> declinedname.name[i]; - if (!normalizePlayerName(declinedname.name[i])) - { - WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); - data << uint32(1); - data << uint64(guid); - SendPacket(&data); - return; - } - } - - if (!ObjectMgr::CheckDeclinedNames(wname, declinedname)) - { - WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); - data << uint32(1); - data << uint64(guid); - SendPacket(&data); - return; - } - - for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i) - CharacterDatabase.EscapeString(declinedname.name[i]); - - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - trans->PAppend("DELETE FROM character_declinedname WHERE guid = '%u'", GUID_LOPART(guid)); - trans->PAppend("INSERT INTO character_declinedname (guid, genitive, dative, accusative, instrumental, prepositional) VALUES ('%u', '%s', '%s', '%s', '%s', '%s')", - GUID_LOPART(guid), declinedname.name[0].c_str(), declinedname.name[1].c_str(), declinedname.name[2].c_str(), declinedname.name[3].c_str(), declinedname.name[4].c_str()); - CharacterDatabase.CommitTransaction(trans); - - WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, 4+8); - data << uint32(0); // OK - data << uint64(guid); - SendPacket(&data); -} - -void WorldSession::HandleAlterAppearance(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_ALTER_APPEARANCE"); - - uint32 Hair, Color, FacialHair, SkinColor; - recv_data >> Hair >> Color >> FacialHair >> SkinColor; - - BarberShopStyleEntry const* bs_hair = sBarberShopStyleStore.LookupEntry(Hair); - - if (!bs_hair || bs_hair->type != 0 || bs_hair->race != _player->getRace() || bs_hair->gender != _player->getGender()) - return; - - BarberShopStyleEntry const* bs_facialHair = sBarberShopStyleStore.LookupEntry(FacialHair); - - if (!bs_facialHair || bs_facialHair->type != 2 || bs_facialHair->race != _player->getRace() || bs_facialHair->gender != _player->getGender()) - return; - - BarberShopStyleEntry const* bs_skinColor = sBarberShopStyleStore.LookupEntry(SkinColor); - - if (bs_skinColor && (bs_skinColor->type != 3 || bs_skinColor->race != _player->getRace() || bs_skinColor->gender != _player->getGender())) - return; - - uint32 Cost = _player->GetBarberShopCost(bs_hair->hair_id, Color, bs_facialHair->hair_id, bs_skinColor); - - // 0 - ok - // 1, 3 - not enough money - // 2 - you have to seat on barber chair - if (!_player->HasEnoughMoney(Cost)) - { - WorldPacket data(SMSG_BARBER_SHOP_RESULT, 4); - data << uint32(1); // no money - SendPacket(&data); - return; - } - else - { - WorldPacket data(SMSG_BARBER_SHOP_RESULT, 4); - data << uint32(0); // ok - SendPacket(&data); - } - - _player->ModifyMoney(-int32(Cost)); // it isn't free - _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER, Cost); - - _player->SetByteValue(PLAYER_BYTES, 2, uint8(bs_hair->hair_id)); - _player->SetByteValue(PLAYER_BYTES, 3, uint8(Color)); - _player->SetByteValue(PLAYER_BYTES_2, 0, uint8(bs_facialHair->hair_id)); - if (bs_skinColor) - _player->SetByteValue(PLAYER_BYTES, 0, uint8(bs_skinColor->hair_id)); - - _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP, 1); - - _player->SetStandState(0); // stand up -} - -void WorldSession::HandleRemoveGlyph(WorldPacket & recv_data) -{ - uint32 slot; - recv_data >> slot; - - if (slot >= MAX_GLYPH_SLOT_INDEX) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "Client sent wrong glyph slot number in opcode CMSG_REMOVE_GLYPH %u", slot); - return; - } - - if (uint32 glyph = _player->GetGlyph(slot)) - { - if (GlyphPropertiesEntry const* gp = sGlyphPropertiesStore.LookupEntry(glyph)) - { - _player->RemoveAurasDueToSpell(gp->SpellId); - _player->SetGlyph(slot, 0); - _player->SendTalentsInfoData(false); - } - } -} - -void WorldSession::HandleCharCustomize(WorldPacket& recv_data) -{ - uint64 guid; - std::string newName; - - recv_data >> guid; - recv_data >> newName; - - uint8 gender, skin, face, hairStyle, hairColor, facialHair; - recv_data >> gender >> skin >> hairColor >> hairStyle >> facialHair >> face; - - QueryResult result = CharacterDatabase.PQuery("SELECT at_login FROM characters WHERE guid ='%u'", GUID_LOPART(guid)); - if (!result) - { - WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); - data << uint8(CHAR_CREATE_ERROR); - SendPacket(&data); - return; - } - - Field* fields = result->Fetch(); - uint32 at_loginFlags = fields[0].GetUInt16(); - - if (!(at_loginFlags & AT_LOGIN_CUSTOMIZE)) - { - WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); - data << uint8(CHAR_CREATE_ERROR); - SendPacket(&data); - return; - } - - // prevent character rename to invalid name - if (!normalizePlayerName(newName)) - { - WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); - data << uint8(CHAR_NAME_NO_NAME); - SendPacket(&data); - return; - } - - uint8 res = ObjectMgr::CheckPlayerName(newName, true); - if (res != CHAR_NAME_SUCCESS) - { - WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); - data << uint8(res); - SendPacket(&data); - return; - } - - // check name limitations - if (AccountMgr::IsPlayerAccount(GetSecurity()) && sObjectMgr->IsReservedName(newName)) - { - WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); - data << uint8(CHAR_NAME_RESERVED); - SendPacket(&data); - return; - } - - // character with this name already exist - if (uint64 newguid = sObjectMgr->GetPlayerGUIDByName(newName)) - { - if (newguid != guid) - { - WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); - data << uint8(CHAR_CREATE_NAME_IN_USE); - SendPacket(&data); - return; - } - } - - if (QueryResult oldNameResult = CharacterDatabase.PQuery("SELECT name FROM characters WHERE guid ='%u'", GUID_LOPART(guid))) - { - std::string oldname = oldNameResult->Fetch()[0].GetString(); - std::string IP_str = GetRemoteAddress(); - sLog->outChar("Account: %d (IP: %s), Character[%s] (guid:%u) Customized to: %s", GetAccountId(), IP_str.c_str(), oldname.c_str(), GUID_LOPART(guid), newName.c_str()); - } - Player::Customize(guid, gender, skin, face, hairStyle, hairColor, facialHair); - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_NAME_AT_LOGIN); - - stmt->setString(0, newName); - stmt->setUInt16(1, uint16(AT_LOGIN_CUSTOMIZE)); - stmt->setUInt32(2, GUID_LOPART(guid)); - - CharacterDatabase.Execute(stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_DECLINED_NAME); - - stmt->setUInt32(0, GUID_LOPART(guid)); - - CharacterDatabase.Execute(stmt); - - sWorld->UpdateCharacterNameData(GUID_LOPART(guid), newName, gender); - - WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1+8+(newName.size()+1)+6); - data << uint8(RESPONSE_SUCCESS); - data << uint64(guid); - data << newName; - data << uint8(gender); - data << uint8(skin); - data << uint8(face); - data << uint8(hairStyle); - data << uint8(hairColor); - data << uint8(facialHair); - SendPacket(&data); -} - -void WorldSession::HandleEquipmentSetSave(WorldPacket &recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_EQUIPMENT_SET_SAVE"); - - uint64 setGuid; - recv_data.readPackGUID(setGuid); - - uint32 index; - recv_data >> index; - if (index >= MAX_EQUIPMENT_SET_INDEX) // client set slots amount - return; - - std::string name; - recv_data >> name; - - std::string iconName; - recv_data >> iconName; - - EquipmentSet eqSet; - - eqSet.Guid = setGuid; - eqSet.Name = name; - eqSet.IconName = iconName; - eqSet.state = EQUIPMENT_SET_NEW; - - for (uint32 i = 0; i < EQUIPMENT_SLOT_END; ++i) - { - uint64 itemGuid; - recv_data.readPackGUID(itemGuid); - - Item* item = _player->GetItemByPos(INVENTORY_SLOT_BAG_0, i); - - if (!item && itemGuid) // cheating check 1 - return; - - if (item && item->GetGUID() != itemGuid) // cheating check 2 - return; - - eqSet.Items[i] = GUID_LOPART(itemGuid); - } - - _player->SetEquipmentSet(index, eqSet); -} - -void WorldSession::HandleEquipmentSetDelete(WorldPacket &recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_EQUIPMENT_SET_DELETE"); - - uint64 setGuid; - recv_data.readPackGUID(setGuid); - - _player->DeleteEquipmentSet(setGuid); -} - -void WorldSession::HandleEquipmentSetUse(WorldPacket &recv_data) -{ - if (_player->isInCombat()) - return; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_EQUIPMENT_SET_USE"); - - for (uint32 i = 0; i < EQUIPMENT_SLOT_END; ++i) - { - uint64 itemGuid; - recv_data.readPackGUID(itemGuid); - - uint8 srcbag, srcslot; - recv_data >> srcbag >> srcslot; - - sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "Item " UI64FMTD ": srcbag %u, srcslot %u", itemGuid, srcbag, srcslot); - - Item* item = _player->GetItemByGuid(itemGuid); - - uint16 dstpos = i | (INVENTORY_SLOT_BAG_0 << 8); - - if (!item) - { - Item* uItem = _player->GetItemByPos(INVENTORY_SLOT_BAG_0, i); - if (!uItem) - continue; - - ItemPosCountVec sDest; - InventoryResult msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, sDest, uItem, false); - if (msg == EQUIP_ERR_OK) - { - _player->RemoveItem(INVENTORY_SLOT_BAG_0, i, true); - _player->StoreItem(sDest, uItem, true); - } - else - _player->SendEquipError(msg, uItem, NULL); - - continue; - } - - if (item->GetPos() == dstpos) - continue; - - _player->SwapItem(item->GetPos(), dstpos); - } - - WorldPacket data(SMSG_EQUIPMENT_SET_USE_RESULT, 1); - data << uint8(0); // 4 - equipment swap failed - inventory is full - SendPacket(&data); -} - -void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recv_data) -{ - // TODO: Move queries to prepared statements - uint64 guid; - std::string newname; - uint8 gender, skin, face, hairStyle, hairColor, facialHair, race; - recv_data >> guid; - recv_data >> newname; - recv_data >> gender >> skin >> hairColor >> hairStyle >> facialHair >> face >> race; - - uint32 lowGuid = GUID_LOPART(guid); - QueryResult result = CharacterDatabase.PQuery("SELECT class, level, at_login FROM characters WHERE guid ='%u'", lowGuid); - if (!result) - { - WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1); - data << uint8(CHAR_CREATE_ERROR); - SendPacket(&data); - return; - } - - Field* fields = result->Fetch(); - uint32 playerClass = fields[0].GetUInt32(); - uint32 level = fields[1].GetUInt32(); - uint32 at_loginFlags = fields[2].GetUInt16(); - uint32 used_loginFlag = ((recv_data.GetOpcode() == CMSG_CHAR_RACE_CHANGE) ? AT_LOGIN_CHANGE_RACE : AT_LOGIN_CHANGE_FACTION); - - if (!sObjectMgr->GetPlayerInfo(race, playerClass)) - { - WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1); - data << uint8(CHAR_CREATE_ERROR); - SendPacket(&data); - return; - } - - if (!(at_loginFlags & used_loginFlag)) - { - WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1); - data << uint8(CHAR_CREATE_ERROR); - SendPacket(&data); - return; - } - - if (AccountMgr::IsPlayerAccount(GetSecurity())) - { - uint32 raceMaskDisabled = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK); - if ((1 << (race - 1)) & raceMaskDisabled) - { - WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1); - data << uint8(CHAR_CREATE_ERROR); - SendPacket(&data); - return; - } - } - - // prevent character rename to invalid name - if (!normalizePlayerName(newname)) - { - WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1); - data << uint8(CHAR_NAME_NO_NAME); - SendPacket(&data); - return; - } - - uint8 res = ObjectMgr::CheckPlayerName(newname, true); - if (res != CHAR_NAME_SUCCESS) - { - WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1); - data << uint8(res); - SendPacket(&data); - return; - } - - // check name limitations - if (AccountMgr::IsPlayerAccount(GetSecurity()) && sObjectMgr->IsReservedName(newname)) - { - WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1); - data << uint8(CHAR_NAME_RESERVED); - SendPacket (&data); - return; - } - - // character with this name already exist - if (uint64 newguid = sObjectMgr->GetPlayerGUIDByName(newname)) - { - if (newguid != guid) - { - WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1); - data << uint8(CHAR_CREATE_NAME_IN_USE); - SendPacket(&data); - return; - } - } - - CharacterDatabase.EscapeString(newname); - Player::Customize(guid, gender, skin, face, hairStyle, hairColor, facialHair); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - trans->PAppend("UPDATE `characters` SET name='%s', race='%u', at_login=at_login & ~ %u WHERE guid='%u'", newname.c_str(), race, used_loginFlag, lowGuid); - trans->PAppend("DELETE FROM character_declinedname WHERE guid ='%u'", lowGuid); - sWorld->UpdateCharacterNameData(GUID_LOPART(guid), newname, gender, race); - - BattlegroundTeamId team = BG_TEAM_ALLIANCE; - - // Search each faction is targeted - switch (race) - { - case RACE_ORC: - case RACE_TAUREN: - case RACE_UNDEAD_PLAYER: - case RACE_TROLL: - case RACE_BLOODELF: - team = BG_TEAM_HORDE; - break; - default: - break; - } - - // Switch Languages - // delete all languages first - trans->PAppend("DELETE FROM `character_skills` WHERE `skill` IN (98, 113, 759, 111, 313, 109, 115, 315, 673, 137) AND `guid`='%u'", lowGuid); - - // now add them back - if (team == BG_TEAM_ALLIANCE) - { - trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 98, 300, 300)", lowGuid); - switch (race) - { - case RACE_DWARF: - trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 111, 300, 300)", lowGuid); - break; - case RACE_DRAENEI: - trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 759, 300, 300)", lowGuid); - break; - case RACE_GNOME: - trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 313, 300, 300)", lowGuid); - break; - case RACE_NIGHTELF: - trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 113, 300, 300)", lowGuid); - break; - } - } - else if (team == BG_TEAM_HORDE) - { - trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 109, 300, 300)", lowGuid); - switch (race) - { - case RACE_UNDEAD_PLAYER: - trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 673, 300, 300)", lowGuid); - break; - case RACE_TAUREN: - trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 115, 300, 300)", lowGuid); - break; - case RACE_TROLL: - trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 315, 300, 300)", lowGuid); - break; - case RACE_BLOODELF: - trans->PAppend("INSERT INTO `character_skills` (guid, skill, value, max) VALUES (%u, 137, 300, 300)", lowGuid); - break; - } - } - - if (recv_data.GetOpcode() == CMSG_CHAR_FACTION_CHANGE) - { - // Delete all Flypaths - trans->PAppend("UPDATE `characters` SET taxi_path = '' WHERE guid ='%u'", lowGuid); - - if (level > 7) - { - // Update Taxi path - // this doesn't seem to be 100% blizzlike... but it can't really be helped. - std::ostringstream taximaskstream; - uint32 numFullTaximasks = level / 7; - if (numFullTaximasks > 11) - numFullTaximasks = 11; - if (team == BG_TEAM_ALLIANCE) - { - if (playerClass != CLASS_DEATH_KNIGHT) - { - for (uint8 i = 0; i < numFullTaximasks; ++i) - taximaskstream << uint32(sAllianceTaxiNodesMask[i]) << ' '; - } - else - { - for (uint8 i = 0; i < numFullTaximasks; ++i) - taximaskstream << uint32(sAllianceTaxiNodesMask[i] | sDeathKnightTaxiNodesMask[i]) << ' '; - } - } - else - { - if (playerClass != CLASS_DEATH_KNIGHT) - { - for (uint8 i = 0; i < numFullTaximasks; ++i) - taximaskstream << uint32(sHordeTaxiNodesMask[i]) << ' '; - } - else - { - for (uint8 i = 0; i < numFullTaximasks; ++i) - taximaskstream << uint32(sHordeTaxiNodesMask[i] | sDeathKnightTaxiNodesMask[i]) << ' '; - } - } - - uint32 numEmptyTaximasks = 11 - numFullTaximasks; - for (uint8 i = 0; i < numEmptyTaximasks; ++i) - taximaskstream << "0 "; - taximaskstream << '0'; - std::string taximask = taximaskstream.str(); - trans->PAppend("UPDATE `characters` SET `taximask`= '%s' WHERE `guid` = '%u'", taximask.c_str(), lowGuid); - } - - // Delete all current quests - trans->PAppend("DELETE FROM `character_queststatus` WHERE guid ='%u'", GUID_LOPART(guid)); - - // Delete record of the faction old completed quests - { - std::ostringstream quests; - ObjectMgr::QuestMap const& qTemplates = sObjectMgr->GetQuestTemplates(); - for (ObjectMgr::QuestMap::const_iterator iter = qTemplates.begin(); iter != qTemplates.end(); ++iter) - { - Quest *qinfo = iter->second; - uint32 requiredRaces = qinfo->GetRequiredRaces(); - if (team == BG_TEAM_ALLIANCE) - { - if (requiredRaces & RACEMASK_ALLIANCE) - { - quests << uint32(qinfo->GetQuestId()); - quests << ','; - } - } - else // if (team == BG_TEAM_HORDE) - { - if (requiredRaces & RACEMASK_HORDE) - { - quests << uint32(qinfo->GetQuestId()); - quests << ','; - } - } - } - - std::string questsStr = quests.str(); - questsStr = questsStr.substr(0, questsStr.length() - 1); - - if (!questsStr.empty()) - trans->PAppend("DELETE FROM `character_queststatus_rewarded` WHERE guid='%u' AND quest IN (%s)", lowGuid, questsStr.c_str()); - } - - if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD)) - { - // Reset guild - if (QueryResult result = CharacterDatabase.PQuery("SELECT guildid FROM `guild_member` WHERE guid ='%u'", lowGuid)) - if (Guild* guild = sGuildMgr->GetGuildById((result->Fetch()[0]).GetUInt32())) - guild->DeleteMember(MAKE_NEW_GUID(lowGuid, 0, HIGHGUID_PLAYER)); - } - - if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND)) - { - // Delete Friend List - trans->PAppend("DELETE FROM `character_social` WHERE `guid`= '%u'", lowGuid); - trans->PAppend("DELETE FROM `character_social` WHERE `friend`= '%u'", lowGuid); - } - - // Leave Arena Teams - Player::LeaveAllArenaTeams(guid); - - // Reset homebind and position - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_HOMEBIND); - stmt->setUInt32(0, lowGuid); - trans->Append(stmt); - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PLAYER_HOMEBIND); - stmt->setUInt32(0, lowGuid); - if (team == BG_TEAM_ALLIANCE) - { - stmt->setUInt16(1, 0); - stmt->setUInt16(2, 1519); - stmt->setFloat (3, -8867.68f); - stmt->setFloat (4, 673.373f); - stmt->setFloat (5, 97.9034f); - Player::SavePositionInDB(0, -8867.68f, 673.373f, 97.9034f, 0.0f, 1519, lowGuid); - } - else - { - stmt->setUInt16(1, 1); - stmt->setUInt16(2, 1637); - stmt->setFloat (3, 1633.33f); - stmt->setFloat (4, -4439.11f); - stmt->setFloat (5, 15.7588f); - Player::SavePositionInDB(1, 1633.33f, -4439.11f, 15.7588f, 0.0f, 1637, lowGuid); - } - trans->Append(stmt); - - // Achievement conversion - for (std::map::const_iterator it = sObjectMgr->factionchange_achievements.begin(); it != sObjectMgr->factionchange_achievements.end(); ++it) - { - uint32 achiev_alliance = it->first; - uint32 achiev_horde = it->second; - trans->PAppend("DELETE FROM `character_achievement` WHERE `achievement`=%u AND `guid`=%u", - team == BG_TEAM_ALLIANCE ? achiev_alliance : achiev_horde, lowGuid); - trans->PAppend("UPDATE `character_achievement` SET achievement = '%u' where achievement = '%u' AND guid = '%u'", - team == BG_TEAM_ALLIANCE ? achiev_alliance : achiev_horde, team == BG_TEAM_ALLIANCE ? achiev_horde : achiev_alliance, lowGuid); - } - - // Item conversion - for (std::map::const_iterator it = sObjectMgr->factionchange_items.begin(); it != sObjectMgr->factionchange_items.end(); ++it) - { - uint32 item_alliance = it->first; - uint32 item_horde = it->second; - trans->PAppend("UPDATE `item_instance` ii, `character_inventory` ci SET ii.itemEntry = '%u' WHERE ii.itemEntry = '%u' AND ci.guid = '%u' AND ci.item = ii.guid", - team == BG_TEAM_ALLIANCE ? item_alliance : item_horde, team == BG_TEAM_ALLIANCE ? item_horde : item_alliance, guid); - } - - // Spell conversion - for (std::map::const_iterator it = sObjectMgr->factionchange_spells.begin(); it != sObjectMgr->factionchange_spells.end(); ++it) - { - uint32 spell_alliance = it->first; - uint32 spell_horde = it->second; - trans->PAppend("DELETE FROM `character_spell` WHERE `spell`=%u AND `guid`=%u", - team == BG_TEAM_ALLIANCE ? spell_alliance : spell_horde, lowGuid); - trans->PAppend("UPDATE `character_spell` SET spell = '%u' where spell = '%u' AND guid = '%u'", - team == BG_TEAM_ALLIANCE ? spell_alliance : spell_horde, team == BG_TEAM_ALLIANCE ? spell_horde : spell_alliance, lowGuid); - } - - // Reputation conversion - for (std::map::const_iterator it = sObjectMgr->factionchange_reputations.begin(); it != sObjectMgr->factionchange_reputations.end(); ++it) - { - uint32 reputation_alliance = it->first; - uint32 reputation_horde = it->second; - trans->PAppend("DELETE FROM character_reputation WHERE faction = '%u' AND guid = '%u'", - team == BG_TEAM_ALLIANCE ? reputation_alliance : reputation_horde, lowGuid); - trans->PAppend("UPDATE `character_reputation` SET faction = '%u' where faction = '%u' AND guid = '%u'", - team == BG_TEAM_ALLIANCE ? reputation_alliance : reputation_horde, team == BG_TEAM_ALLIANCE ? reputation_horde : reputation_alliance, lowGuid); - } - } - - CharacterDatabase.CommitTransaction(trans); - - std::string IP_str = GetRemoteAddress(); - sLog->outDebug(LOG_FILTER_UNITS, "Account: %d (IP: %s), Character guid: %u Change Race/Faction to: %s", GetAccountId(), IP_str.c_str(), lowGuid, newname.c_str()); - - WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1 + 8 + (newname.size() + 1) + 1 + 1 + 1 + 1 + 1 + 1 + 1); - data << uint8(RESPONSE_SUCCESS); - data << uint64(guid); - data << newname; - data << uint8(gender); - data << uint8(skin); - data << uint8(face); - data << uint8(hairStyle); - data << uint8(hairColor); - data << uint8(facialHair); - data << uint8(race); - SendPacket(&data); -} diff --git a/src/server/game/Server/Protocol/Handlers/ChatHandler.cpp b/src/server/game/Server/Protocol/Handlers/ChatHandler.cpp deleted file mode 100755 index 3d689196256..00000000000 --- a/src/server/game/Server/Protocol/Handlers/ChatHandler.cpp +++ /dev/null @@ -1,635 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "ObjectAccessor.h" -#include "ObjectMgr.h" -#include "GuildMgr.h" -#include "World.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "DatabaseEnv.h" - -#include "CellImpl.h" -#include "Chat.h" -#include "ChannelMgr.h" -#include "GridNotifiersImpl.h" -#include "Group.h" -#include "Guild.h" -#include "Language.h" -#include "Log.h" -#include "Opcodes.h" -#include "Player.h" -#include "SpellAuras.h" -#include "SpellAuraEffects.h" -#include "Util.h" -#include "ScriptMgr.h" -#include "AccountMgr.h" - -bool WorldSession::processChatmessageFurtherAfterSecurityChecks(std::string& msg, uint32 lang) -{ - if (lang != LANG_ADDON) - { - // strip invisible characters for non-addon messages - if (sWorld->getBoolConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING)) - stripLineInvisibleChars(msg); - - if (sWorld->getIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY) && AccountMgr::IsPlayerAccount(GetSecurity()) - && !ChatHandler(this).isValidChatMessage(msg.c_str())) - { - sLog->outError("Player %s (GUID: %u) sent a chatmessage with an invalid link: %s", GetPlayer()->GetName(), - GetPlayer()->GetGUIDLow(), msg.c_str()); - if (sWorld->getIntConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_KICK)) - KickPlayer(); - return false; - } - } - - return true; -} - -void WorldSession::HandleMessagechatOpcode(WorldPacket & recv_data) -{ - uint32 type; - uint32 lang; - - recv_data >> type; - recv_data >> lang; - - if (type >= MAX_CHAT_MSG_TYPE) - { - sLog->outError("CHAT: Wrong message type received: %u", type); - recv_data.rfinish(); - return; - } - - Player* sender = GetPlayer(); - - //sLog->outDebug("CHAT: packet received. type %u, lang %u", type, lang); - - // prevent talking at unknown language (cheating) - LanguageDesc const* langDesc = GetLanguageDescByID(lang); - if (!langDesc) - { - SendNotification(LANG_UNKNOWN_LANGUAGE); - recv_data.rfinish(); - return; - } - if (langDesc->skill_id != 0 && !sender->HasSkill(langDesc->skill_id)) - { - // also check SPELL_AURA_COMPREHEND_LANGUAGE (client offers option to speak in that language) - Unit::AuraEffectList const& langAuras = sender->GetAuraEffectsByType(SPELL_AURA_COMPREHEND_LANGUAGE); - bool foundAura = false; - for (Unit::AuraEffectList::const_iterator i = langAuras.begin(); i != langAuras.end(); ++i) - { - if ((*i)->GetMiscValue() == int32(lang)) - { - foundAura = true; - break; - } - } - if (!foundAura) - { - SendNotification(LANG_NOT_LEARNED_LANGUAGE); - recv_data.rfinish(); - return; - } - } - - if (lang == LANG_ADDON) - { - if (sWorld->getBoolConfig(CONFIG_CHATLOG_ADDON)) - { - std::string msg = ""; - recv_data >> msg; - - if (msg.empty()) - return; - - sScriptMgr->OnPlayerChat(sender, uint32(CHAT_MSG_ADDON), lang, msg); - } - - // Disabled addon channel? - if (!sWorld->getBoolConfig(CONFIG_ADDON_CHANNEL)) - return; - } - // LANG_ADDON should not be changed nor be affected by flood control - else - { - // send in universal language if player in .gmon mode (ignore spell effects) - if (sender->isGameMaster()) - lang = LANG_UNIVERSAL; - else - { - // send in universal language in two side iteration allowed mode - if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT)) - lang = LANG_UNIVERSAL; - else - { - switch (type) - { - case CHAT_MSG_PARTY: - case CHAT_MSG_PARTY_LEADER: - case CHAT_MSG_RAID: - case CHAT_MSG_RAID_LEADER: - case CHAT_MSG_RAID_WARNING: - // allow two side chat at group channel if two side group allowed - if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP)) - lang = LANG_UNIVERSAL; - break; - case CHAT_MSG_GUILD: - case CHAT_MSG_OFFICER: - // allow two side chat at guild channel if two side guild allowed - if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD)) - lang = LANG_UNIVERSAL; - break; - } - } - - // but overwrite it by SPELL_AURA_MOD_LANGUAGE auras (only single case used) - Unit::AuraEffectList const& ModLangAuras = sender->GetAuraEffectsByType(SPELL_AURA_MOD_LANGUAGE); - if (!ModLangAuras.empty()) - lang = ModLangAuras.front()->GetMiscValue(); - } - - if (!sender->CanSpeak()) - { - std::string timeStr = secsToTimeString(m_muteTime - time(NULL)); - SendNotification(GetTrinityString(LANG_WAIT_BEFORE_SPEAKING), timeStr.c_str()); - recv_data.rfinish(); // Prevent warnings - return; - } - - if (type != CHAT_MSG_AFK && type != CHAT_MSG_DND) - sender->UpdateSpeakTime(); - } - - if (sender->HasAura(1852) && type != CHAT_MSG_WHISPER) - { - std::string msg=""; - recv_data >> msg; - - SendNotification(GetTrinityString(LANG_GM_SILENCE), sender->GetName()); - return; - } - - std::string to, channel, msg; - bool ignoreChecks = false; - switch (type) - { - case CHAT_MSG_SAY: - case CHAT_MSG_EMOTE: - case CHAT_MSG_YELL: - case CHAT_MSG_PARTY: - case CHAT_MSG_PARTY_LEADER: - case CHAT_MSG_GUILD: - case CHAT_MSG_OFFICER: - case CHAT_MSG_RAID: - case CHAT_MSG_RAID_LEADER: - case CHAT_MSG_RAID_WARNING: - case CHAT_MSG_BATTLEGROUND: - case CHAT_MSG_BATTLEGROUND_LEADER: - recv_data >> msg; - break; - case CHAT_MSG_WHISPER: - recv_data >> to; - recv_data >> msg; - break; - case CHAT_MSG_CHANNEL: - recv_data >> channel; - recv_data >> msg; - break; - case CHAT_MSG_AFK: - case CHAT_MSG_DND: - recv_data >> msg; - ignoreChecks = true; - break; - } - - if (!ignoreChecks) - { - if (msg.empty()) - return; - - if (ChatHandler(this).ParseCommands(msg.c_str()) > 0) - return; - - if (!processChatmessageFurtherAfterSecurityChecks(msg, lang)) - return; - - if (msg.empty()) - return; - } - - switch (type) - { - case CHAT_MSG_SAY: - case CHAT_MSG_EMOTE: - case CHAT_MSG_YELL: - { - if (sender->getLevel() < sWorld->getIntConfig(CONFIG_CHAT_SAY_LEVEL_REQ)) - { - SendNotification(GetTrinityString(LANG_SAY_REQ), sWorld->getIntConfig(CONFIG_CHAT_SAY_LEVEL_REQ)); - return; - } - - if (type == CHAT_MSG_SAY) - sender->Say(msg, lang); - else if (type == CHAT_MSG_EMOTE) - sender->TextEmote(msg); - else if (type == CHAT_MSG_YELL) - sender->Yell(msg, lang); - } break; - case CHAT_MSG_WHISPER: - { - if (sender->getLevel() < sWorld->getIntConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ)) - { - SendNotification(GetTrinityString(LANG_WHISPER_REQ), sWorld->getIntConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ)); - return; - } - - if (!normalizePlayerName(to)) - { - SendPlayerNotFoundNotice(to); - break; - } - - Player* receiver = sObjectAccessor->FindPlayerByName(to.c_str()); - bool senderIsPlayer = AccountMgr::IsPlayerAccount(GetSecurity()); - bool receiverIsPlayer = AccountMgr::IsPlayerAccount(receiver ? receiver->GetSession()->GetSecurity() : SEC_PLAYER); - if (!receiver || (senderIsPlayer && !receiverIsPlayer && !receiver->isAcceptWhispers() && !receiver->IsInWhisperWhiteList(sender->GetGUID()))) - { - SendPlayerNotFoundNotice(to); - return; - } - - if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT) && senderIsPlayer && receiverIsPlayer) - if (GetPlayer()->GetTeam() != receiver->GetTeam()) - { - SendWrongFactionNotice(); - return; - } - - if (GetPlayer()->HasAura(1852) && !receiver->isGameMaster()) - { - SendNotification(GetTrinityString(LANG_GM_SILENCE), GetPlayer()->GetName()); - return; - } - - // If player is a Gamemaster and doesn't accept whisper, we auto-whitelist every player that the Gamemaster is talking to - if (!senderIsPlayer && !sender->isAcceptWhispers() && !sender->IsInWhisperWhiteList(receiver->GetGUID())) - sender->AddWhisperWhiteList(receiver->GetGUID()); - - GetPlayer()->Whisper(msg, lang, receiver->GetGUID()); - } break; - case CHAT_MSG_PARTY: - case CHAT_MSG_PARTY_LEADER: - { - // if player is in battleground, he cannot say to battleground members by /p - Group* group = GetPlayer()->GetOriginalGroup(); - if (!group) - { - group = _player->GetGroup(); - if (!group || group->isBGGroup()) - return; - } - - if (type == CHAT_MSG_PARTY_LEADER && !group->IsLeader(_player->GetGUID())) - return; - - sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); - - WorldPacket data; - ChatHandler::FillMessageData(&data, this, uint8(type), lang, NULL, 0, msg.c_str(), NULL); - group->BroadcastPacket(&data, false, group->GetMemberGroup(GetPlayer()->GetGUID())); - } break; - case CHAT_MSG_GUILD: - { - if (GetPlayer()->GetGuildId()) - { - if (Guild* guild = sGuildMgr->GetGuildById(GetPlayer()->GetGuildId())) - { - sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, guild); - - guild->BroadcastToGuild(this, false, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL); - } - } - } break; - case CHAT_MSG_OFFICER: - { - if (GetPlayer()->GetGuildId()) - { - if (Guild* guild = sGuildMgr->GetGuildById(GetPlayer()->GetGuildId())) - { - sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, guild); - - guild->BroadcastToGuild(this, true, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL); - } - } - } break; - case CHAT_MSG_RAID: - { - // if player is in battleground, he cannot say to battleground members by /ra - Group* group = GetPlayer()->GetOriginalGroup(); - if (!group) - { - group = GetPlayer()->GetGroup(); - if (!group || group->isBGGroup() || !group->isRaidGroup()) - return; - } - - sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); - - WorldPacket data; - ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID, lang, "", 0, msg.c_str(), NULL); - group->BroadcastPacket(&data, false); - } break; - case CHAT_MSG_RAID_LEADER: - { - // if player is in battleground, he cannot say to battleground members by /ra - Group* group = GetPlayer()->GetOriginalGroup(); - if (!group) - { - group = GetPlayer()->GetGroup(); - if (!group || group->isBGGroup() || !group->isRaidGroup() || !group->IsLeader(_player->GetGUID())) - return; - } - - sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); - - WorldPacket data; - ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_LEADER, lang, "", 0, msg.c_str(), NULL); - group->BroadcastPacket(&data, false); - } break; - case CHAT_MSG_RAID_WARNING: - { - Group* group = GetPlayer()->GetGroup(); - if (!group || !group->isRaidGroup() || !(group->IsLeader(GetPlayer()->GetGUID()) || group->IsAssistant(GetPlayer()->GetGUID())) || group->isBGGroup()) - return; - - sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); - - WorldPacket data; - //in battleground, raid warning is sent only to players in battleground - code is ok - ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_WARNING, lang, "", 0, msg.c_str(), NULL); - group->BroadcastPacket(&data, false); - } break; - case CHAT_MSG_BATTLEGROUND: - { - //battleground raid is always in Player->GetGroup(), never in GetOriginalGroup() - Group* group = GetPlayer()->GetGroup(); - if (!group || !group->isBGGroup()) - return; - - sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); - - WorldPacket data; - ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND, lang, "", 0, msg.c_str(), NULL); - group->BroadcastPacket(&data, false); - } break; - case CHAT_MSG_BATTLEGROUND_LEADER: - { - // battleground raid is always in Player->GetGroup(), never in GetOriginalGroup() - Group* group = GetPlayer()->GetGroup(); - if (!group || !group->isBGGroup() || !group->IsLeader(GetPlayer()->GetGUID())) - return; - - sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); - - WorldPacket data; - ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND_LEADER, lang, "", 0, msg.c_str(), NULL); - group->BroadcastPacket(&data, false); - } break; - case CHAT_MSG_CHANNEL: - { - if (AccountMgr::IsPlayerAccount(GetSecurity())) - { - if (_player->getLevel() < sWorld->getIntConfig(CONFIG_CHAT_CHANNEL_LEVEL_REQ)) - { - SendNotification(GetTrinityString(LANG_CHANNEL_REQ), sWorld->getIntConfig(CONFIG_CHAT_CHANNEL_LEVEL_REQ)); - return; - } - } - - if (ChannelMgr* cMgr = channelMgr(_player->GetTeam())) - { - - if (Channel* chn = cMgr->GetChannel(channel, _player)) - { - sScriptMgr->OnPlayerChat(_player, type, lang, msg, chn); - - chn->Say(_player->GetGUID(), msg.c_str(), lang); - } - } - } break; - case CHAT_MSG_AFK: - { - if ((msg.empty() || !_player->isAFK()) && !_player->isInCombat()) - { - if (!_player->isAFK()) - { - if (msg.empty()) - msg = GetTrinityString(LANG_PLAYER_AFK_DEFAULT); - _player->afkMsg = msg; - } - - sScriptMgr->OnPlayerChat(_player, type, lang, msg); - - _player->ToggleAFK(); - if (_player->isAFK() && _player->isDND()) - _player->ToggleDND(); - } - } break; - case CHAT_MSG_DND: - { - if (msg.empty() || !_player->isDND()) - { - if (!_player->isDND()) - { - if (msg.empty()) - msg = GetTrinityString(LANG_PLAYER_DND_DEFAULT); - _player->dndMsg = msg; - } - - sScriptMgr->OnPlayerChat(_player, type, lang, msg); - - _player->ToggleDND(); - if (_player->isDND() && _player->isAFK()) - _player->ToggleAFK(); - } - } break; - default: - sLog->outError("CHAT: unknown message type %u, lang: %u", type, lang); - break; - } -} - -void WorldSession::HandleEmoteOpcode(WorldPacket & recv_data) -{ - if (!GetPlayer()->isAlive() || GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - return; - - uint32 emote; - recv_data >> emote; - sScriptMgr->OnPlayerEmote(GetPlayer(), emote); - GetPlayer()->HandleEmoteCommand(emote); -} - -namespace Trinity -{ - class EmoteChatBuilder - { - public: - EmoteChatBuilder(Player const& player, uint32 text_emote, uint32 emote_num, Unit const* target) - : i_player(player), i_text_emote(text_emote), i_emote_num(emote_num), i_target(target) {} - - void operator()(WorldPacket& data, LocaleConstant loc_idx) - { - char const* nam = i_target ? i_target->GetNameForLocaleIdx(loc_idx) : NULL; - uint32 namlen = (nam ? strlen(nam) : 0) + 1; - - data.Initialize(SMSG_TEXT_EMOTE, (20+namlen)); - data << i_player.GetGUID(); - data << (uint32)i_text_emote; - data << i_emote_num; - data << (uint32)namlen; - if (namlen > 1) - data.append(nam, namlen); - else - data << (uint8)0x00; - } - - private: - Player const& i_player; - uint32 i_text_emote; - uint32 i_emote_num; - Unit const* i_target; - }; -} // namespace Trinity - -void WorldSession::HandleTextEmoteOpcode(WorldPacket & recv_data) -{ - if (!GetPlayer()->isAlive()) - return; - - if (!GetPlayer()->CanSpeak()) - { - std::string timeStr = secsToTimeString(m_muteTime - time(NULL)); - SendNotification(GetTrinityString(LANG_WAIT_BEFORE_SPEAKING), timeStr.c_str()); - return; - } - - uint32 text_emote, emoteNum; - uint64 guid; - - recv_data >> text_emote; - recv_data >> emoteNum; - recv_data >> guid; - - sScriptMgr->OnPlayerTextEmote(GetPlayer(), text_emote, emoteNum, guid); - - EmotesTextEntry const* em = sEmotesTextStore.LookupEntry(text_emote); - if (!em) - return; - - uint32 emote_anim = em->textid; - - switch (emote_anim) - { - case EMOTE_STATE_SLEEP: - case EMOTE_STATE_SIT: - case EMOTE_STATE_KNEEL: - case EMOTE_ONESHOT_NONE: - break; - default: - // Only allow text-emotes for "dead" entities (feign death included) - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - break; - GetPlayer()->HandleEmoteCommand(emote_anim); - break; - } - - Unit* unit = ObjectAccessor::GetUnit(*_player, guid); - - CellCoord p = Trinity::ComputeCellCoord(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY()); - - Cell cell(p); - cell.SetNoCreate(); - - Trinity::EmoteChatBuilder emote_builder(*GetPlayer(), text_emote, emoteNum, unit); - Trinity::LocalizedPacketDo emote_do(emote_builder); - Trinity::PlayerDistWorker > emote_worker(GetPlayer(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), emote_do); - TypeContainerVisitor >, WorldTypeMapContainer> message(emote_worker); - cell.Visit(p, message, *GetPlayer()->GetMap(), *GetPlayer(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE)); - - GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, text_emote, 0, unit); - - //Send scripted event call - if (unit && unit->GetTypeId() == TYPEID_UNIT && ((Creature*)unit)->AI()) - ((Creature*)unit)->AI()->ReceiveEmote(GetPlayer(), text_emote); -} - -void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recv_data) -{ - uint64 iguid; - uint8 unk; - //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: Received CMSG_CHAT_IGNORED"); - - recv_data >> iguid; - recv_data >> unk; // probably related to spam reporting - - Player* player = ObjectAccessor::FindPlayer(iguid); - if (!player || !player->GetSession()) - return; - - WorldPacket data; - ChatHandler::FillMessageData(&data, this, CHAT_MSG_IGNORED, LANG_UNIVERSAL, NULL, GetPlayer()->GetGUID(), GetPlayer()->GetName(), NULL); - player->GetSession()->SendPacket(&data); -} - -void WorldSession::HandleChannelDeclineInvite(WorldPacket &recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Opcode %u", recvPacket.GetOpcode()); -} - -void WorldSession::SendPlayerNotFoundNotice(std::string name) -{ - WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, name.size()+1); - data << name; - SendPacket(&data); -} - -void WorldSession::SendPlayerAmbiguousNotice(std::string name) -{ - WorldPacket data(SMSG_CHAT_PLAYER_AMBIGUOUS, name.size()+1); - data << name; - SendPacket(&data); -} - -void WorldSession::SendWrongFactionNotice() -{ - WorldPacket data(SMSG_CHAT_WRONG_FACTION, 0); - SendPacket(&data); -} - -void WorldSession::SendChatRestrictedNotice(ChatRestrictionType restriction) -{ - WorldPacket data(SMSG_CHAT_RESTRICTED, 1); - data << uint8(restriction); - SendPacket(&data); -} diff --git a/src/server/game/Server/Protocol/Handlers/CombatHandler.cpp b/src/server/game/Server/Protocol/Handlers/CombatHandler.cpp deleted file mode 100755 index 6693cdfca27..00000000000 --- a/src/server/game/Server/Protocol/Handlers/CombatHandler.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "Log.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "ObjectAccessor.h" -#include "CreatureAI.h" -#include "ObjectDefines.h" -#include "Vehicle.h" -#include "VehicleDefines.h" - -void WorldSession::HandleAttackSwingOpcode(WorldPacket& recv_data) -{ - uint64 guid; - recv_data >> guid; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_ATTACKSWING Message guidlow:%u guidhigh:%u", GUID_LOPART(guid), GUID_HIPART(guid)); - - Unit* pEnemy = ObjectAccessor::GetUnit(*_player, guid); - - if (!pEnemy) - { - // stop attack state at client - SendAttackStop(NULL); - return; - } - - if (!_player->IsValidAttackTarget(pEnemy)) - { - // stop attack state at client - SendAttackStop(pEnemy); - return; - } - - //! Client explicitly checks the following before sending CMSG_ATTACKSWING packet, - //! so we'll place the same check here. Note that it might be possible to reuse this snippet - //! in other places as well. - if (Vehicle* vehicle = _player->GetVehicle()) - { - VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(_player); - ASSERT(seat); - if (!(seat->m_flags & VEHICLE_SEAT_FLAG_CAN_ATTACK)) - { - SendAttackStop(pEnemy); - return; - } - } - - _player->Attack(pEnemy, true); -} - -void WorldSession::HandleAttackStopOpcode(WorldPacket & /*recv_data*/) -{ - GetPlayer()->AttackStop(); -} - -void WorldSession::HandleSetSheathedOpcode(WorldPacket& recv_data) -{ - uint32 sheathed; - recv_data >> sheathed; - - //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: Recvd CMSG_SETSHEATHED Message guidlow:%u value1:%u", GetPlayer()->GetGUIDLow(), sheathed); - - if (sheathed >= MAX_SHEATH_STATE) - { - sLog->outError("Unknown sheath state %u ??", sheathed); - return; - } - - GetPlayer()->SetSheath(SheathState(sheathed)); -} - -void WorldSession::SendAttackStop(Unit const* enemy) -{ - WorldPacket data(SMSG_ATTACKSTOP, (8+8+4)); // we guess size - data.append(GetPlayer()->GetPackGUID()); - data.append(enemy ? enemy->GetPackGUID() : 0); // must be packed guid - data << uint32(0); // unk, can be 1 also - SendPacket(&data); -} diff --git a/src/server/game/Server/Protocol/Handlers/DuelHandler.cpp b/src/server/game/Server/Protocol/Handlers/DuelHandler.cpp deleted file mode 100755 index 8afd9f3b978..00000000000 --- a/src/server/game/Server/Protocol/Handlers/DuelHandler.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Log.h" -#include "Opcodes.h" -#include "UpdateData.h" -#include "Player.h" - -void WorldSession::HandleDuelAcceptedOpcode(WorldPacket& recvPacket) -{ - uint64 guid; - Player* player; - Player* plTarget; - - recvPacket >> guid; - - if (!GetPlayer()->duel) // ignore accept from duel-sender - return; - - player = GetPlayer(); - plTarget = player->duel->opponent; - - if (player == player->duel->initiator || !plTarget || player == plTarget || player->duel->startTime != 0 || plTarget->duel->startTime != 0) - return; - - //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: Received CMSG_DUEL_ACCEPTED"); - sLog->outStaticDebug("Player 1 is: %u (%s)", player->GetGUIDLow(), player->GetName()); - sLog->outStaticDebug("Player 2 is: %u (%s)", plTarget->GetGUIDLow(), plTarget->GetName()); - - time_t now = time(NULL); - player->duel->startTimer = now; - plTarget->duel->startTimer = now; - - player->SendDuelCountdown(3000); - plTarget->SendDuelCountdown(3000); -} - -void WorldSession::HandleDuelCancelledOpcode(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_DUEL_CANCELLED"); - uint64 guid; - recvPacket >> guid; - - // no duel requested - if (!GetPlayer()->duel) - return; - - // player surrendered in a duel using /forfeit - if (GetPlayer()->duel->startTime != 0) - { - GetPlayer()->CombatStopWithPets(true); - if (GetPlayer()->duel->opponent) - GetPlayer()->duel->opponent->CombatStopWithPets(true); - - GetPlayer()->CastSpell(GetPlayer(), 7267, true); // beg - GetPlayer()->DuelComplete(DUEL_WON); - return; - } - - GetPlayer()->DuelComplete(DUEL_INTERRUPTED); -} diff --git a/src/server/game/Server/Protocol/Handlers/GroupHandler.cpp b/src/server/game/Server/Protocol/Handlers/GroupHandler.cpp deleted file mode 100755 index 9343a5356b6..00000000000 --- a/src/server/game/Server/Protocol/Handlers/GroupHandler.cpp +++ /dev/null @@ -1,996 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "DatabaseEnv.h" -#include "Opcodes.h" -#include "Log.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "World.h" -#include "ObjectMgr.h" -#include "GroupMgr.h" -#include "Player.h" -#include "Group.h" -#include "SocialMgr.h" -#include "Util.h" -#include "SpellAuras.h" -#include "Vehicle.h" - -class Aura; - -/* differeces from off: - -you can uninvite yourself - is is useful - -you can accept invitation even if leader went offline -*/ -/* todo: - -group_destroyed msg is sent but not shown - -reduce xp gaining when in raid group - -quest sharing has to be corrected - -FIX sending PartyMemberStats -*/ - -void WorldSession::SendPartyResult(PartyOperation operation, const std::string& member, PartyResult res, uint32 val /* = 0 */) -{ - WorldPacket data(SMSG_PARTY_COMMAND_RESULT, 4 + member.size() + 1 + 4 + 4); - data << uint32(operation); - data << member; - data << uint32(res); - data << uint32(val); // LFD cooldown related (used with ERR_PARTY_LFG_BOOT_COOLDOWN_S and ERR_PARTY_LFG_BOOT_NOT_ELIGIBLE_S) - - SendPacket(&data); -} - -void WorldSession::HandleGroupInviteOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GROUP_INVITE"); - - std::string membername; - recv_data >> membername; - recv_data.read_skip(); - - // attempt add selected player - - // cheating - if (!normalizePlayerName(membername)) - { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_BAD_PLAYER_NAME_S); - return; - } - - Player* player = sObjectAccessor->FindPlayerByName(membername.c_str()); - - // no player - if (!player) - { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_BAD_PLAYER_NAME_S); - return; - } - - // restrict invite to GMs - if (!sWorld->getBoolConfig(CONFIG_ALLOW_GM_GROUP) && !GetPlayer()->isGameMaster() && player->isGameMaster()) - return; - - // can't group with - if (!GetPlayer()->isGameMaster() && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && GetPlayer()->GetTeam() != player->GetTeam()) - { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_PLAYER_WRONG_FACTION); - return; - } - if (GetPlayer()->GetInstanceId() != 0 && player->GetInstanceId() != 0 && GetPlayer()->GetInstanceId() != player->GetInstanceId() && GetPlayer()->GetMapId() == player->GetMapId()) - { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_TARGET_NOT_IN_INSTANCE_S); - return; - } - // just ignore us - if (player->GetInstanceId() != 0 && player->GetDungeonDifficulty() != GetPlayer()->GetDungeonDifficulty()) - { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_IGNORING_YOU_S); - return; - } - - if (player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) - { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_IGNORING_YOU_S); - return; - } - - Group* group = GetPlayer()->GetGroup(); - if (group && group->isBGGroup()) - group = GetPlayer()->GetOriginalGroup(); - - Group* group2 = player->GetGroup(); - if (group2 && group2->isBGGroup()) - group2 = player->GetOriginalGroup(); - // player already in another group or invited - if (group2 || player->GetGroupInvite()) - { - SendPartyResult(PARTY_OP_INVITE, membername, ERR_ALREADY_IN_GROUP_S); - - if (group2) - { - // tell the player that they were invited but it failed as they were already in a group - WorldPacket data(SMSG_GROUP_INVITE, 10); // guess size - data << uint8(0); // invited/already in group flag - data << GetPlayer()->GetName(); // max len 48 - data << uint32(0); // unk - data << uint8(0); // count - data << uint32(0); // unk - player->GetSession()->SendPacket(&data); - } - - return; - } - - if (group) - { - // not have permissions for invite - if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) - { - SendPartyResult(PARTY_OP_INVITE, "", ERR_NOT_LEADER); - return; - } - // not have place - if (group->IsFull()) - { - SendPartyResult(PARTY_OP_INVITE, "", ERR_GROUP_FULL); - return; - } - } - - // ok, but group not exist, start a new group - // but don't create and save the group to the DB until - // at least one person joins - if (!group) - { - group = new Group; - // new group: if can't add then delete - if (!group->AddLeaderInvite(GetPlayer())) - { - delete group; - return; - } - if (!group->AddInvite(player)) - { - delete group; - return; - } - } - else - { - // already existed group: if can't add then just leave - if (!group->AddInvite(player)) - { - return; - } - } - - // ok, we do it - WorldPacket data(SMSG_GROUP_INVITE, 10); // guess size - data << uint8(1); // invited/already in group flag - data << GetPlayer()->GetName(); // max len 48 - data << uint32(0); // unk - data << uint8(0); // count - data << uint32(0); // unk - player->GetSession()->SendPacket(&data); - - SendPartyResult(PARTY_OP_INVITE, membername, ERR_PARTY_RESULT_OK); -} - -void WorldSession::HandleGroupAcceptOpcode(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GROUP_ACCEPT"); - - recv_data.read_skip(); - Group* group = GetPlayer()->GetGroupInvite(); - - if (!group) - return; - - // Remove player from invitees in any case - group->RemoveInvite(GetPlayer()); - - if (group->GetLeaderGUID() == GetPlayer()->GetGUID()) - { - sLog->outError("HandleGroupAcceptOpcode: player %s(%d) tried to accept an invite to his own group", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow()); - return; - } - - // Group is full - if (group->IsFull()) - { - SendPartyResult(PARTY_OP_INVITE, "", ERR_GROUP_FULL); - return; - } - - Player* leader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()); - - // Forming a new group, create it - if (!group->IsCreated()) - { - // This can happen if the leader is zoning. To be removed once delayed actions for zoning are implemented - if (!leader) - { - group->RemoveAllInvites(); - return; - } - - // If we're about to create a group there really should be a leader present - ASSERT(leader); - group->RemoveInvite(leader); - group->Create(leader); - sGroupMgr->AddGroup(group); - } - - // Everything is fine, do it, PLAYER'S GROUP IS SET IN ADDMEMBER!!! - if (!group->AddMember(GetPlayer())) - return; - - group->BroadcastGroupUpdate(); -} - -void WorldSession::HandleGroupDeclineOpcode(WorldPacket & /*recv_data*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GROUP_DECLINE"); - - Group *group = GetPlayer()->GetGroupInvite(); - if (!group) return; - - // Remember leader if online (group pointer will be invalid if group gets disbanded) - Player* leader = ObjectAccessor::FindPlayer(group->GetLeaderGUID()); - - // uninvite, group can be deleted - GetPlayer()->UninviteFromGroup(); - - if (!leader || !leader->GetSession()) - return; - - // report - std::string name = std::string(GetPlayer()->GetName()); - WorldPacket data(SMSG_GROUP_DECLINE, name.length()); - data << name.c_str(); - leader->GetSession()->SendPacket(&data); -} - -void WorldSession::HandleGroupUninviteGuidOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GROUP_UNINVITE_GUID"); - - uint64 guid; - std::string reason; - recv_data >> guid; - recv_data >> reason; - - //can't uninvite yourself - if (guid == GetPlayer()->GetGUID()) - { - sLog->outError("WorldSession::HandleGroupUninviteGuidOpcode: leader %s(%d) tried to uninvite himself from the group.", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow()); - return; - } - - PartyResult res = GetPlayer()->CanUninviteFromGroup(); - if (res != ERR_PARTY_RESULT_OK) - { - SendPartyResult(PARTY_OP_UNINVITE, "", res); - return; - } - - Group* grp = GetPlayer()->GetGroup(); - if (!grp) - return; - - if (grp->IsLeader(guid)) - { - SendPartyResult(PARTY_OP_UNINVITE, "", ERR_NOT_LEADER); - return; - } - - if (grp->IsMember(guid)) - { - Player::RemoveFromGroup(grp, guid, GROUP_REMOVEMETHOD_KICK, GetPlayer()->GetGUID(), reason.c_str()); - return; - } - - if (Player* player = grp->GetInvited(guid)) - { - player->UninviteFromGroup(); - return; - } - - SendPartyResult(PARTY_OP_UNINVITE, "", ERR_TARGET_NOT_IN_GROUP_S); -} - -void WorldSession::HandleGroupUninviteOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GROUP_UNINVITE"); - - std::string membername; - recv_data >> membername; - - // player not found - if (!normalizePlayerName(membername)) - return; - - // can't uninvite yourself - if (GetPlayer()->GetName() == membername) - { - sLog->outError("WorldSession::HandleGroupUninviteOpcode: leader %s(%d) tried to uninvite himself from the group.", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow()); - return; - } - - PartyResult res = GetPlayer()->CanUninviteFromGroup(); - if (res != ERR_PARTY_RESULT_OK) - { - SendPartyResult(PARTY_OP_UNINVITE, "", res); - return; - } - - Group* grp = GetPlayer()->GetGroup(); - if (!grp) - return; - - if (uint64 guid = grp->GetMemberGUID(membername)) - { - Player::RemoveFromGroup(grp, guid, GROUP_REMOVEMETHOD_KICK, GetPlayer()->GetGUID()); - return; - } - - if (Player* player = grp->GetInvited(membername)) - { - player->UninviteFromGroup(); - return; - } - - SendPartyResult(PARTY_OP_UNINVITE, membername, ERR_TARGET_NOT_IN_GROUP_S); -} - -void WorldSession::HandleGroupSetLeaderOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GROUP_SET_LEADER"); - - uint64 guid; - recv_data >> guid; - - Player* player = ObjectAccessor::FindPlayer(guid); - Group* group = GetPlayer()->GetGroup(); - - if (!group || !player) - return; - - if (!group->IsLeader(GetPlayer()->GetGUID()) || player->GetGroup() != group) - return; - - // Everything's fine, accepted. - group->ChangeLeader(guid); - group->SendUpdate(); -} - -void WorldSession::HandleGroupDisbandOpcode(WorldPacket & /*recv_data*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GROUP_DISBAND"); - - Group* grp = GetPlayer()->GetGroup(); - if (!grp) - return; - - if (_player->InBattleground()) - { - SendPartyResult(PARTY_OP_INVITE, "", ERR_INVITE_RESTRICTED); - return; - } - - /** error handling **/ - /********************/ - - // everything's fine, do it - SendPartyResult(PARTY_OP_LEAVE, GetPlayer()->GetName(), ERR_PARTY_RESULT_OK); - - GetPlayer()->RemoveFromGroup(GROUP_REMOVEMETHOD_LEAVE); -} - -void WorldSession::HandleLootMethodOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_LOOT_METHOD"); - - uint32 lootMethod; - uint64 lootMaster; - uint32 lootThreshold; - recv_data >> lootMethod >> lootMaster >> lootThreshold; - - Group* group = GetPlayer()->GetGroup(); - if (!group) - return; - - /** error handling **/ - if (!group->IsLeader(GetPlayer()->GetGUID())) - return; - /********************/ - - // everything's fine, do it - group->SetLootMethod((LootMethod)lootMethod); - group->SetLooterGuid(lootMaster); - group->SetLootThreshold((ItemQualities)lootThreshold); - group->SendUpdate(); -} - -void WorldSession::HandleLootRoll(WorldPacket &recv_data) -{ - if (!GetPlayer()->GetGroup()) - { - recv_data.rfinish(); - return; - } - - uint64 Guid; - uint32 NumberOfPlayers; - uint8 rollType; - recv_data >> Guid; //guid of the item rolled - recv_data >> NumberOfPlayers; - recv_data >> rollType; //0: pass, 1: need, 2: greed - - //sLog->outDebug("WORLD RECIEVE CMSG_LOOT_ROLL, From:%u, Numberofplayers:%u, Choise:%u", (uint32)Guid, NumberOfPlayers, Choise); - - Group* group = GetPlayer()->GetGroup(); - if (!group) - return; - - // everything's fine, do it - group->CountRollVote(GetPlayer()->GetGUID(), Guid, NumberOfPlayers, rollType); - - switch (rollType) - { - case ROLL_NEED: - GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED, 1); - break; - case ROLL_GREED: - GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED, 1); - break; - } -} - -void WorldSession::HandleMinimapPingOpcode(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received MSG_MINIMAP_PING"); - - if (!GetPlayer()->GetGroup()) - return; - - float x, y; - recv_data >> x; - recv_data >> y; - - //sLog->outDebug("Received opcode MSG_MINIMAP_PING X: %f, Y: %f", x, y); - - /** error handling **/ - /********************/ - - // everything's fine, do it - WorldPacket data(MSG_MINIMAP_PING, (8+4+4)); - data << uint64(GetPlayer()->GetGUID()); - data << float(x); - data << float(y); - GetPlayer()->GetGroup()->BroadcastPacket(&data, true, -1, GetPlayer()->GetGUID()); -} - -void WorldSession::HandleRandomRollOpcode(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received MSG_RANDOM_ROLL"); - - uint32 minimum, maximum, roll; - recv_data >> minimum; - recv_data >> maximum; - - /** error handling **/ - if (minimum > maximum || maximum > 10000) // < 32768 for urand call - return; - /********************/ - - // everything's fine, do it - roll = urand(minimum, maximum); - - //sLog->outDebug("ROLL: MIN: %u, MAX: %u, ROLL: %u", minimum, maximum, roll); - - WorldPacket data(MSG_RANDOM_ROLL, 4+4+4+8); - data << uint32(minimum); - data << uint32(maximum); - data << uint32(roll); - data << uint64(GetPlayer()->GetGUID()); - if (GetPlayer()->GetGroup()) - GetPlayer()->GetGroup()->BroadcastPacket(&data, false); - else - SendPacket(&data); -} - -void WorldSession::HandleRaidTargetUpdateOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received MSG_RAID_TARGET_UPDATE"); - - Group* group = GetPlayer()->GetGroup(); - if (!group) - return; - - uint8 x; - recv_data >> x; - - /** error handling **/ - /********************/ - - // everything's fine, do it - if (x == 0xFF) // target icon request - { - group->SendTargetIconList(this); - } - else // target icon update - { - if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) - return; - - uint64 guid; - recv_data >> guid; - group->SetTargetIcon(x, _player->GetGUID(), guid); - } -} - -void WorldSession::HandleGroupRaidConvertOpcode(WorldPacket & /*recv_data*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GROUP_RAID_CONVERT"); - - Group* group = GetPlayer()->GetGroup(); - if (!group) - return; - - if (_player->InBattleground()) - return; - - /** error handling **/ - if (!group->IsLeader(GetPlayer()->GetGUID()) || group->GetMembersCount() < 2) - return; - /********************/ - - // everything's fine, do it (is it 0 (PARTY_OP_INVITE) correct code) - SendPartyResult(PARTY_OP_INVITE, "", ERR_PARTY_RESULT_OK); - group->ConvertToRaid(); -} - -void WorldSession::HandleGroupChangeSubGroupOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GROUP_CHANGE_SUB_GROUP"); - - // we will get correct pointer for group here, so we don't have to check if group is BG raid - Group* group = GetPlayer()->GetGroup(); - if (!group) - return; - - std::string name; - uint8 groupNr; - recv_data >> name; - recv_data >> groupNr; - - if (groupNr >= MAX_RAID_SUBGROUPS) - return; - - uint64 senderGuid = GetPlayer()->GetGUID(); - if (!group->IsLeader(senderGuid) && !group->IsAssistant(senderGuid)) - return; - - if (!group->HasFreeSlotSubGroup(groupNr)) - return; - - Player* movedPlayer = sObjectAccessor->FindPlayerByName(name.c_str()); - uint64 guid; - if (movedPlayer) - { - guid = movedPlayer->GetGUID(); - } - else - { - CharacterDatabase.EscapeString(name); - guid = sObjectMgr->GetPlayerGUIDByName(name.c_str()); - } - - group->ChangeMembersGroup(guid, groupNr); -} - -void WorldSession::HandleGroupAssistantLeaderOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GROUP_ASSISTANT_LEADER"); - - Group* group = GetPlayer()->GetGroup(); - if (!group) - return; - - if (!group->IsLeader(GetPlayer()->GetGUID())) - return; - - uint64 guid; - bool apply; - recv_data >> guid; - recv_data >> apply; - - group->SetGroupMemberFlag(guid, apply, MEMBER_FLAG_ASSISTANT); - - group->SendUpdate(); -} - -void WorldSession::HandlePartyAssignmentOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received MSG_PARTY_ASSIGNMENT"); - - Group* group = GetPlayer()->GetGroup(); - if (!group) - return; - - uint64 senderGuid = GetPlayer()->GetGUID(); - if (!group->IsLeader(senderGuid) && !group->IsAssistant(senderGuid)) - return; - - uint8 assignment; - bool apply; - uint64 guid; - recv_data >> assignment >> apply; - recv_data >> guid; - - switch (assignment) - { - case GROUP_ASSIGN_MAINASSIST: - group->RemoveUniqueGroupMemberFlag(MEMBER_FLAG_MAINASSIST); - group->SetGroupMemberFlag(guid, apply, MEMBER_FLAG_MAINASSIST); - break; - case GROUP_ASSIGN_MAINTANK: - group->RemoveUniqueGroupMemberFlag(MEMBER_FLAG_MAINTANK); // Remove main assist flag from current if any. - group->SetGroupMemberFlag(guid, apply, MEMBER_FLAG_MAINTANK); - default: - break; - } - - group->SendUpdate(); -} - -void WorldSession::HandleRaidReadyCheckOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received MSG_RAID_READY_CHECK"); - - Group* group = GetPlayer()->GetGroup(); - if (!group) - return; - - if (recv_data.empty()) // request - { - /** error handling **/ - if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) - return; - /********************/ - - // everything's fine, do it - WorldPacket data(MSG_RAID_READY_CHECK, 8); - data << GetPlayer()->GetGUID(); - group->BroadcastPacket(&data, false, -1); - - group->OfflineReadyCheck(); - } - else // answer - { - uint8 state; - recv_data >> state; - - // everything's fine, do it - WorldPacket data(MSG_RAID_READY_CHECK_CONFIRM, 9); - data << uint64(GetPlayer()->GetGUID()); - data << uint8(state); - group->BroadcastReadyCheck(&data); - } -} - -void WorldSession::HandleRaidReadyCheckFinishedOpcode(WorldPacket & /*recv_data*/) -{ - //Group* group = GetPlayer()->GetGroup(); - //if (!group) - // return; - - //if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) - // return; - - // Is any reaction need? -} - -void WorldSession::BuildPartyMemberStatsChangedPacket(Player* player, WorldPacket* data) -{ - uint32 mask = player->GetGroupUpdateFlag(); - - if (mask == GROUP_UPDATE_FLAG_NONE) - return; - - if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) // if update power type, update current/max power also - mask |= (GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER); - - if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) // same for pets - mask |= (GROUP_UPDATE_FLAG_PET_CUR_POWER | GROUP_UPDATE_FLAG_PET_MAX_POWER); - - uint32 byteCount = 0; - for (int i = 1; i < GROUP_UPDATE_FLAGS_COUNT; ++i) - if (mask & (1 << i)) - byteCount += GroupUpdateLength[i]; - - data->Initialize(SMSG_PARTY_MEMBER_STATS, 8 + 4 + byteCount); - data->append(player->GetPackGUID()); - *data << (uint32) mask; - - if (mask & GROUP_UPDATE_FLAG_STATUS) - { - if (player) - { - if (player->IsPvP()) - *data << (uint16) (MEMBER_STATUS_ONLINE | MEMBER_STATUS_PVP); - else - *data << (uint16) MEMBER_STATUS_ONLINE; - } - else - *data << (uint16) MEMBER_STATUS_OFFLINE; - } - - if (mask & GROUP_UPDATE_FLAG_CUR_HP) - *data << (uint32) player->GetHealth(); - - if (mask & GROUP_UPDATE_FLAG_MAX_HP) - *data << (uint32) player->GetMaxHealth(); - - Powers powerType = player->getPowerType(); - if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) - *data << (uint8) powerType; - - if (mask & GROUP_UPDATE_FLAG_CUR_POWER) - *data << (uint16) player->GetPower(powerType); - - if (mask & GROUP_UPDATE_FLAG_MAX_POWER) - *data << (uint16) player->GetMaxPower(powerType); - - if (mask & GROUP_UPDATE_FLAG_LEVEL) - *data << (uint16) player->getLevel(); - - if (mask & GROUP_UPDATE_FLAG_ZONE) - *data << (uint16) player->GetZoneId(); - - if (mask & GROUP_UPDATE_FLAG_POSITION) - *data << (uint16) player->GetPositionX() << (uint16) player->GetPositionY(); - - if (mask & GROUP_UPDATE_FLAG_AURAS) - { - uint64 auramask = player->GetAuraUpdateMaskForRaid(); - *data << uint64(auramask); - for (uint32 i = 0; i < MAX_AURAS; ++i) - { - if (auramask & (uint64(1) << i)) - { - AuraApplication const* aurApp = player->GetVisibleAura(i); - *data << uint32(aurApp ? aurApp->GetBase()->GetId() : 0); - *data << uint8(1); - } - } - } - - Pet* pet = player->GetPet(); - if (mask & GROUP_UPDATE_FLAG_PET_GUID) - { - if (pet) - *data << (uint64) pet->GetGUID(); - else - *data << (uint64) 0; - } - - if (mask & GROUP_UPDATE_FLAG_PET_NAME) - { - if (pet) - *data << pet->GetName(); - else - *data << (uint8) 0; - } - - if (mask & GROUP_UPDATE_FLAG_PET_MODEL_ID) - { - if (pet) - *data << (uint16) pet->GetDisplayId(); - else - *data << (uint16) 0; - } - - if (mask & GROUP_UPDATE_FLAG_PET_CUR_HP) - { - if (pet) - *data << (uint32) pet->GetHealth(); - else - *data << (uint32) 0; - } - - if (mask & GROUP_UPDATE_FLAG_PET_MAX_HP) - { - if (pet) - *data << (uint32) pet->GetMaxHealth(); - else - *data << (uint32) 0; - } - - if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) - { - if (pet) - *data << (uint8) pet->getPowerType(); - else - *data << (uint8) 0; - } - - if (mask & GROUP_UPDATE_FLAG_PET_CUR_POWER) - { - if (pet) - *data << (uint16) pet->GetPower(pet->getPowerType()); - else - *data << (uint16) 0; - } - - if (mask & GROUP_UPDATE_FLAG_PET_MAX_POWER) - { - if (pet) - *data << (uint16) pet->GetMaxPower(pet->getPowerType()); - else - *data << (uint16) 0; - } - - if (mask & GROUP_UPDATE_FLAG_VEHICLE_SEAT) - { - if (Vehicle* veh = player->GetVehicle()) - *data << (uint32) veh->GetVehicleInfo()->m_seatID[player->m_movementInfo.t_seat]; - } - - if (mask & GROUP_UPDATE_FLAG_PET_AURAS) - { - if (pet) - { - uint64 auramask = pet->GetAuraUpdateMaskForRaid(); - *data << uint64(auramask); - for (uint32 i = 0; i < MAX_AURAS; ++i) - { - if (auramask & (uint64(1) << i)) - { - AuraApplication const* aurApp = player->GetVisibleAura(i); - *data << uint32(aurApp ? aurApp->GetBase()->GetId() : 0); - *data << uint8(1); - } - } - } - else - *data << (uint64) 0; - } -} - -/*this procedure handles clients CMSG_REQUEST_PARTY_MEMBER_STATS request*/ -void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket &recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_REQUEST_PARTY_MEMBER_STATS"); - uint64 Guid; - recv_data >> Guid; - - Player* player = HashMapHolder::Find(Guid); - if (!player) - { - WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 3+4+2); - data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related - data.appendPackGUID(Guid); - data << (uint32) GROUP_UPDATE_FLAG_STATUS; - data << (uint16) MEMBER_STATUS_OFFLINE; - SendPacket(&data); - return; - } - - Pet* pet = player->GetPet(); - - WorldPacket data(SMSG_PARTY_MEMBER_STATS_FULL, 4+2+2+2+1+2*6+8+1+8); - data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related - data.append(player->GetPackGUID()); - - uint32 mask1 = 0x00040BFF; // common mask, real flags used 0x000040BFF - if (pet) - mask1 = 0x7FFFFFFF; // for hunters and other classes with pets - - Powers powerType = player->getPowerType(); - data << (uint32) mask1; // group update mask - data << (uint16) MEMBER_STATUS_ONLINE; // member's online status - data << (uint32) player->GetHealth(); // GROUP_UPDATE_FLAG_CUR_HP - data << (uint32) player->GetMaxHealth(); // GROUP_UPDATE_FLAG_MAX_HP - data << (uint8) powerType; // GROUP_UPDATE_FLAG_POWER_TYPE - data << (uint16) player->GetPower(powerType); // GROUP_UPDATE_FLAG_CUR_POWER - data << (uint16) player->GetMaxPower(powerType); // GROUP_UPDATE_FLAG_MAX_POWER - data << (uint16) player->getLevel(); // GROUP_UPDATE_FLAG_LEVEL - data << (uint16) player->GetZoneId(); // GROUP_UPDATE_FLAG_ZONE - data << (uint16) player->GetPositionX(); // GROUP_UPDATE_FLAG_POSITION - data << (uint16) player->GetPositionY(); // GROUP_UPDATE_FLAG_POSITION - - uint64 auramask = 0; - size_t maskPos = data.wpos(); - data << (uint64) auramask; // placeholder - for (uint8 i = 0; i < MAX_AURAS; ++i) - { - if (AuraApplication * aurApp = player->GetVisibleAura(i)) - { - auramask |= (uint64(1) << i); - data << (uint32) aurApp->GetBase()->GetId(); - data << (uint8) 1; - } - } - data.put(maskPos, auramask); // GROUP_UPDATE_FLAG_AURAS - - if (pet) - { - Powers petpowertype = pet->getPowerType(); - data << (uint64) pet->GetGUID(); // GROUP_UPDATE_FLAG_PET_GUID - data << pet->GetName(); // GROUP_UPDATE_FLAG_PET_NAME - data << (uint16) pet->GetDisplayId(); // GROUP_UPDATE_FLAG_PET_MODEL_ID - data << (uint32) pet->GetHealth(); // GROUP_UPDATE_FLAG_PET_CUR_HP - data << (uint32) pet->GetMaxHealth(); // GROUP_UPDATE_FLAG_PET_MAX_HP - data << (uint8) petpowertype; // GROUP_UPDATE_FLAG_PET_POWER_TYPE - data << (uint16) pet->GetPower(petpowertype); // GROUP_UPDATE_FLAG_PET_CUR_POWER - data << (uint16) pet->GetMaxPower(petpowertype); // GROUP_UPDATE_FLAG_PET_MAX_POWER - - uint64 petauramask = 0; - size_t petMaskPos = data.wpos(); - data << (uint64) petauramask; // placeholder - for (uint8 i = 0; i < MAX_AURAS; ++i) - { - if (AuraApplication * auraApp = pet->GetVisibleAura(i)) - { - petauramask |= (uint64(1) << i); - data << (uint32) auraApp->GetBase()->GetId(); - data << (uint8) 1; - } - } - data.put(petMaskPos, petauramask); // GROUP_UPDATE_FLAG_PET_AURAS - } - else - { - data << (uint8) 0; // GROUP_UPDATE_FLAG_PET_NAME - data << (uint64) 0; // GROUP_UPDATE_FLAG_PET_AURAS - } - - SendPacket(&data); -} - -/*!*/void WorldSession::HandleRequestRaidInfoOpcode(WorldPacket & /*recv_data*/) -{ - // every time the player checks the character screen - _player->SendRaidInfo(); -} - -/*void WorldSession::HandleGroupCancelOpcode(WorldPacket & recv_data) -{ - sLog->outDebug("WORLD: got CMSG_GROUP_CANCEL."); -}*/ - -void WorldSession::HandleOptOutOfLootOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_OPT_OUT_OF_LOOT"); - - uint32 passOnLoot; - recv_data >> passOnLoot; // 1 always pass, 0 do not pass - - // ignore if player not loaded - if (!GetPlayer()) // needed because STATUS_AUTHED - { - if (passOnLoot != 0) - sLog->outError("CMSG_OPT_OUT_OF_LOOT value<>0 for not-loaded character!"); - return; - } - - GetPlayer()->SetPassOnGroupLoot(passOnLoot); -} diff --git a/src/server/game/Server/Protocol/Handlers/GuildHandler.cpp b/src/server/game/Server/Protocol/Handlers/GuildHandler.cpp deleted file mode 100755 index d2a5f8014b8..00000000000 --- a/src/server/game/Server/Protocol/Handlers/GuildHandler.cpp +++ /dev/null @@ -1,570 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "World.h" -#include "ObjectMgr.h" -#include "GuildMgr.h" -#include "Log.h" -#include "Opcodes.h" -#include "Guild.h" -#include "GossipDef.h" -#include "SocialMgr.h" - -// Helper for getting guild object of session's player. -// If guild does not exist, sends error (if necessary). -inline Guild* _GetPlayerGuild(WorldSession* session, bool sendError = false) -{ - if (uint32 guildId = session->GetPlayer()->GetGuildId()) // If guild id = 0, player is not in guild - if (Guild* guild = sGuildMgr->GetGuildById(guildId)) // Find guild by id - return guild; - if (sendError) - Guild::SendCommandResult(session, GUILD_CREATE_S, ERR_GUILD_PLAYER_NOT_IN_GUILD); - return NULL; -} - -void WorldSession::HandleGuildQueryOpcode(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_QUERY"); - - uint32 guildId; - recvPacket >> guildId; - // Use received guild id to access guild method (not player's guild id) - if (Guild* guild = sGuildMgr->GetGuildById(guildId)) - guild->HandleQuery(this); - else - Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_PLAYER_NOT_IN_GUILD); -} - -void WorldSession::HandleGuildCreateOpcode(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_CREATE"); - - std::string name; - recvPacket >> name; - - if (!GetPlayer()->GetGuildId()) // Player cannot be in guild - { - Guild* guild = new Guild(); - if (guild->Create(GetPlayer(), name)) - sGuildMgr->AddGuild(guild); - else - delete guild; - } -} - -void WorldSession::HandleGuildInviteOpcode(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_INVITE"); - - std::string invitedName; - recvPacket >> invitedName; - - if (normalizePlayerName(invitedName)) - if (Guild* guild = _GetPlayerGuild(this, true)) - guild->HandleInviteMember(this, invitedName); -} - -void WorldSession::HandleGuildRemoveOpcode(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_REMOVE"); - - std::string playerName; - recvPacket >> playerName; - - if (normalizePlayerName(playerName)) - if (Guild* guild = _GetPlayerGuild(this, true)) - guild->HandleRemoveMember(this, playerName); -} - -void WorldSession::HandleGuildAcceptOpcode(WorldPacket& /*recvPacket*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_ACCEPT"); - // Player cannot be in guild - if (!GetPlayer()->GetGuildId()) - // Guild where player was invited must exist - if (Guild* guild = sGuildMgr->GetGuildById(GetPlayer()->GetGuildIdInvited())) - guild->HandleAcceptMember(this); -} - -void WorldSession::HandleGuildDeclineOpcode(WorldPacket& /*recvPacket*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_DECLINE"); - - GetPlayer()->SetGuildIdInvited(0); - GetPlayer()->SetInGuild(0); -} - -void WorldSession::HandleGuildInfoOpcode(WorldPacket& /*recvPacket*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_INFO"); - - if (Guild* guild = _GetPlayerGuild(this, true)) - guild->SendInfo(this); -} - -void WorldSession::HandleGuildRosterOpcode(WorldPacket& /*recvPacket*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_ROSTER"); - - if (Guild* guild = _GetPlayerGuild(this)) - guild->HandleRoster(this); -} - -void WorldSession::HandleGuildPromoteOpcode(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_PROMOTE"); - - std::string playerName; - recvPacket >> playerName; - - if (normalizePlayerName(playerName)) - if (Guild* guild = _GetPlayerGuild(this, true)) - guild->HandleUpdateMemberRank(this, playerName, false); -} - -void WorldSession::HandleGuildDemoteOpcode(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_DEMOTE"); - - std::string playerName; - recvPacket >> playerName; - - if (normalizePlayerName(playerName)) - if (Guild* guild = _GetPlayerGuild(this, true)) - guild->HandleUpdateMemberRank(this, playerName, true); -} - -void WorldSession::HandleGuildLeaveOpcode(WorldPacket& /*recvPacket*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_LEAVE"); - - if (Guild* guild = _GetPlayerGuild(this, true)) - guild->HandleLeaveMember(this); -} - -void WorldSession::HandleGuildDisbandOpcode(WorldPacket& /*recvPacket*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_DISBAND"); - - if (Guild* guild = _GetPlayerGuild(this, true)) - guild->HandleDisband(this); -} - -void WorldSession::HandleGuildLeaderOpcode(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_LEADER"); - - std::string name; - recvPacket >> name; - - if (normalizePlayerName(name)) - if (Guild* guild = _GetPlayerGuild(this, true)) - guild->HandleSetLeader(this, name); -} - -void WorldSession::HandleGuildMOTDOpcode(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_MOTD"); - - std::string motd; // Empty by default - if (!recvPacket.empty()) - recvPacket >> motd; - - if (Guild* guild = _GetPlayerGuild(this, true)) - guild->HandleSetMOTD(this, motd); -} - -void WorldSession::HandleGuildSetPublicNoteOpcode(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_SET_PUBLIC_NOTE"); - - std::string playerName; - recvPacket >> playerName; - - std::string publicNote; - recvPacket >> publicNote; - - if (normalizePlayerName(playerName)) - if (Guild* guild = _GetPlayerGuild(this, true)) - guild->HandleSetMemberNote(this, playerName, publicNote, false); -} - -void WorldSession::HandleGuildSetOfficerNoteOpcode(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_SET_OFFICER_NOTE"); - - std::string playerName; - recvPacket >> playerName; - - std::string officerNote; - recvPacket >> officerNote; - - if (normalizePlayerName(playerName)) - if (Guild* guild = _GetPlayerGuild(this, true)) - guild->HandleSetMemberNote(this, playerName, officerNote, true); -} - -void WorldSession::HandleGuildRankOpcode(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_RANK"); - - Guild* guild = _GetPlayerGuild(this, true); - if (!guild) - { - recvPacket.rpos(recvPacket.wpos()); - return; - } - - uint32 rankId; - recvPacket >> rankId; - - uint32 rights; - recvPacket >> rights; - - std::string rankName; - recvPacket >> rankName; - - uint32 money; - recvPacket >> money; - - GuildBankRightsAndSlotsVec rightsAndSlots(GUILD_BANK_MAX_TABS); - for (uint8 tabId = 0; tabId < GUILD_BANK_MAX_TABS; ++tabId) - { - uint32 bankRights; - uint32 slots; - - recvPacket >> bankRights; - recvPacket >> slots; - - rightsAndSlots[tabId] = GuildBankRightsAndSlots(uint8(bankRights), slots); - } - - guild->HandleSetRankInfo(this, rankId, rankName, rights, money, rightsAndSlots); -} - -void WorldSession::HandleGuildAddRankOpcode(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_ADD_RANK"); - - std::string rankName; - recvPacket >> rankName; - - if (Guild* guild = _GetPlayerGuild(this, true)) - guild->HandleAddNewRank(this, rankName); -} - -void WorldSession::HandleGuildDelRankOpcode(WorldPacket& /*recvPacket*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_DEL_RANK"); - - if (Guild* guild = _GetPlayerGuild(this, true)) - guild->HandleRemoveLowestRank(this); -} - -void WorldSession::HandleGuildChangeInfoTextOpcode(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GUILD_INFO_TEXT"); - - std::string info; - recvPacket >> info; - - if (Guild* guild = _GetPlayerGuild(this, true)) - guild->HandleSetInfo(this, info); -} - -void WorldSession::HandleSaveGuildEmblemOpcode(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received MSG_SAVE_GUILD_EMBLEM"); - - uint64 vendorGuid; - recvPacket >> vendorGuid; - - EmblemInfo emblemInfo; - emblemInfo.ReadPacket(recvPacket); - - if (GetPlayer()->GetNPCIfCanInteractWith(vendorGuid, UNIT_NPC_FLAG_TABARDDESIGNER)) - { - // Remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - if (Guild* guild = _GetPlayerGuild(this)) - guild->HandleSetEmblem(this, emblemInfo); - else - // "You are not part of a guild!"; - Guild::SendSaveEmblemResult(this, ERR_GUILDEMBLEM_NOGUILD); - } - else - { - // "That's not an emblem vendor!" - Guild::SendSaveEmblemResult(this, ERR_GUILDEMBLEM_INVALIDVENDOR); - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleSaveGuildEmblemOpcode - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(vendorGuid)); - } -} - -void WorldSession::HandleGuildEventLogQueryOpcode(WorldPacket& /* recvPacket */) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (MSG_GUILD_EVENT_LOG_QUERY)"); - - if (Guild* guild = _GetPlayerGuild(this)) - guild->SendEventLog(this); -} - -void WorldSession::HandleGuildBankMoneyWithdrawn(WorldPacket & /* recv_data */) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (MSG_GUILD_BANK_MONEY_WITHDRAWN)"); - - if (Guild* guild = _GetPlayerGuild(this)) - guild->SendMoneyInfo(this); -} - -void WorldSession::HandleGuildPermissions(WorldPacket& /* recv_data */) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (MSG_GUILD_PERMISSIONS)"); - - if (Guild* guild = _GetPlayerGuild(this)) - guild->SendPermissions(this); -} - -// Called when clicking on Guild bank gameobject -void WorldSession::HandleGuildBankerActivate(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (CMSG_GUILD_BANKER_ACTIVATE)"); - - uint64 GoGuid; - recv_data >> GoGuid; - - uint8 unk; - recv_data >> unk; - - if (GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - { - if (Guild* guild = _GetPlayerGuild(this)) - guild->SendBankTabsInfo(this); - else - Guild::SendCommandResult(this, GUILD_UNK1, ERR_GUILD_PLAYER_NOT_IN_GUILD); - } -} - -// Called when opening guild bank tab only (first one) -void WorldSession::HandleGuildBankQueryTab(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (CMSG_GUILD_BANK_QUERY_TAB)"); - - uint64 GoGuid; - recv_data >> GoGuid; - - uint8 tabId; - recv_data >> tabId; - - uint8 unk1; - recv_data >> unk1; - - if (GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - if (Guild* guild = _GetPlayerGuild(this)) - guild->SendBankTabData(this, tabId); -} - -void WorldSession::HandleGuildBankDepositMoney(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (CMSG_GUILD_BANK_DEPOSIT_MONEY)"); - - uint64 GoGuid; - recv_data >> GoGuid; - - uint32 money; - recv_data >> money; - - if (GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - if (money && GetPlayer()->HasEnoughMoney(money)) - if (Guild* guild = _GetPlayerGuild(this)) - guild->HandleMemberDepositMoney(this, money); -} - -void WorldSession::HandleGuildBankWithdrawMoney(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (CMSG_GUILD_BANK_WITHDRAW_MONEY)"); - - uint64 GoGuid; - recv_data >> GoGuid; - - uint32 money; - recv_data >> money; - - if (money) - if (GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - if (Guild* guild = _GetPlayerGuild(this)) - guild->HandleMemberWithdrawMoney(this, money); -} - -void WorldSession::HandleGuildBankSwapItems(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (CMSG_GUILD_BANK_SWAP_ITEMS)"); - - uint64 GoGuid; - recv_data >> GoGuid; - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - { - recv_data.rfinish(); // Prevent additional spam at rejected packet - return; - } - - Guild* guild = _GetPlayerGuild(this); - if (!guild) - { - recv_data.rfinish(); // Prevent additional spam at rejected packet - return; - } - - uint8 bankToBank; - recv_data >> bankToBank; - - uint8 tabId; - uint8 slotId; - uint32 itemEntry; - uint32 splitedAmount = 0; - - if (bankToBank) - { - uint8 destTabId; - recv_data >> destTabId; - - uint8 destSlotId; - recv_data >> destSlotId; - recv_data.read_skip(); // Always 0 - - recv_data >> tabId; - recv_data >> slotId; - recv_data >> itemEntry; - recv_data.read_skip(); // Always 0 - - recv_data >> splitedAmount; - - guild->SwapItems(GetPlayer(), tabId, slotId, destTabId, destSlotId, splitedAmount); - } - else - { - uint8 playerBag = NULL_BAG; - uint8 playerSlotId = NULL_SLOT; - uint8 toChar = 1; - - recv_data >> tabId; - recv_data >> slotId; - recv_data >> itemEntry; - - uint8 autoStore; - recv_data >> autoStore; - if (autoStore) - { - recv_data.read_skip(); // autoStoreCount - recv_data.read_skip(); // ToChar (?), always and expected to be 1 (autostore only triggered in Bank -> Char) - recv_data.read_skip(); // Always 0 - } - else - { - recv_data >> playerBag; - recv_data >> playerSlotId; - recv_data >> toChar; - recv_data >> splitedAmount; - } - - // Player <-> Bank - // Allow to work with inventory only - if (!Player::IsInventoryPos(playerBag, playerSlotId) && !(playerBag == NULL_BAG && playerSlotId == NULL_SLOT)) - GetPlayer()->SendEquipError(EQUIP_ERR_NONE, NULL); - else - guild->SwapItemsWithInventory(GetPlayer(), toChar, tabId, slotId, playerBag, playerSlotId, splitedAmount); - } -} - -void WorldSession::HandleGuildBankBuyTab(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (CMSG_GUILD_BANK_BUY_TAB)"); - - uint64 GoGuid; - recv_data >> GoGuid; - - uint8 tabId; - recv_data >> tabId; - - if (GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - if (Guild* guild = _GetPlayerGuild(this)) - guild->HandleBuyBankTab(this, tabId); -} - -void WorldSession::HandleGuildBankUpdateTab(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (CMSG_GUILD_BANK_UPDATE_TAB)"); - - uint64 GoGuid; - recv_data >> GoGuid; - - uint8 tabId; - recv_data >> tabId; - - std::string name; - recv_data >> name; - - std::string icon; - recv_data >> icon; - - if (!name.empty() && !icon.empty()) - if (GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - if (Guild* guild = _GetPlayerGuild(this)) - guild->HandleSetBankTabInfo(this, tabId, name, icon); -} - -void WorldSession::HandleGuildBankLogQuery(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received (MSG_GUILD_BANK_LOG_QUERY)"); - - uint8 tabId; - recv_data >> tabId; - - if (Guild* guild = _GetPlayerGuild(this)) - guild->SendBankLog(this, tabId); -} - -void WorldSession::HandleQueryGuildBankTabText(WorldPacket &recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received MSG_QUERY_GUILD_BANK_TEXT"); - - uint8 tabId; - recv_data >> tabId; - - if (Guild* guild = _GetPlayerGuild(this)) - guild->SendBankTabText(this, tabId); -} - -void WorldSession::HandleSetGuildBankTabText(WorldPacket &recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_SET_GUILD_BANK_TEXT"); - - uint8 tabId; - recv_data >> tabId; - - std::string text; - recv_data >> text; - - if (Guild* guild = _GetPlayerGuild(this)) - guild->SetBankTabText(tabId, text); -} diff --git a/src/server/game/Server/Protocol/Handlers/ItemHandler.cpp b/src/server/game/Server/Protocol/Handlers/ItemHandler.cpp deleted file mode 100755 index 47700fd088a..00000000000 --- a/src/server/game/Server/Protocol/Handlers/ItemHandler.cpp +++ /dev/null @@ -1,1432 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Opcodes.h" -#include "Log.h" -#include "ObjectMgr.h" -#include "Player.h" -#include "Item.h" -#include "UpdateData.h" -#include "ObjectAccessor.h" -#include "SpellInfo.h" - -void WorldSession::HandleSplitItemOpcode(WorldPacket & recv_data) -{ - //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_SPLIT_ITEM"); - uint8 srcbag, srcslot, dstbag, dstslot; - uint32 count; - - recv_data >> srcbag >> srcslot >> dstbag >> dstslot >> count; - //sLog->outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u, dstslot = %u, count = %u", srcbag, srcslot, dstbag, dstslot, count); - - uint16 src = ((srcbag << 8) | srcslot); - uint16 dst = ((dstbag << 8) | dstslot); - - if (src == dst) - return; - - if (count == 0) - return; //check count - if zero it's fake packet - - if (!_player->IsValidPos(srcbag, srcslot, true)) - { - _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } - - if (!_player->IsValidPos(dstbag, dstslot, false)) // can be autostore pos - { - _player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); - return; - } - - _player->SplitItem(src, dst, count); -} - -void WorldSession::HandleSwapInvItemOpcode(WorldPacket & recv_data) -{ - //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_SWAP_INV_ITEM"); - uint8 srcslot, dstslot; - - recv_data >> dstslot >> srcslot; - //sLog->outDebug("STORAGE: receive srcslot = %u, dstslot = %u", srcslot, dstslot); - - // prevent attempt swap same item to current position generated by client at special checting sequence - if (srcslot == dstslot) - return; - - if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0, srcslot, true)) - { - _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } - - if (!_player->IsValidPos(INVENTORY_SLOT_BAG_0, dstslot, true)) - { - _player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); - return; - } - - uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | srcslot); - uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | dstslot); - - _player->SwapItem(src, dst); -} - -void WorldSession::HandleAutoEquipItemSlotOpcode(WorldPacket & recv_data) -{ - uint64 itemguid; - uint8 dstslot; - recv_data >> itemguid >> dstslot; - - // cheating attempt, client should never send opcode in that case - if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, dstslot)) - return; - - Item* item = _player->GetItemByGuid(itemguid); - uint16 dstpos = dstslot | (INVENTORY_SLOT_BAG_0 << 8); - - if (!item || item->GetPos() == dstpos) - return; - - _player->SwapItem(item->GetPos(), dstpos); -} - -void WorldSession::HandleSwapItem(WorldPacket & recv_data) -{ - //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_SWAP_ITEM"); - uint8 dstbag, dstslot, srcbag, srcslot; - - recv_data >> dstbag >> dstslot >> srcbag >> srcslot ; - //sLog->outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u, dstslot = %u", srcbag, srcslot, dstbag, dstslot); - - uint16 src = ((srcbag << 8) | srcslot); - uint16 dst = ((dstbag << 8) | dstslot); - - // prevent attempt swap same item to current position generated by client at special checting sequence - if (src == dst) - return; - - if (!_player->IsValidPos(srcbag, srcslot, true)) - { - _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } - - if (!_player->IsValidPos(dstbag, dstslot, true)) - { - _player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); - return; - } - - _player->SwapItem(src, dst); -} - -void WorldSession::HandleAutoEquipItemOpcode(WorldPacket & recv_data) -{ - //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_AUTOEQUIP_ITEM"); - uint8 srcbag, srcslot; - - recv_data >> srcbag >> srcslot; - //sLog->outDebug("STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot); - - Item* pSrcItem = _player->GetItemByPos(srcbag, srcslot); - if (!pSrcItem) - return; // only at cheat - - uint16 dest; - InventoryResult msg = _player->CanEquipItem(NULL_SLOT, dest, pSrcItem, !pSrcItem->IsBag()); - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, pSrcItem, NULL); - return; - } - - uint16 src = pSrcItem->GetPos(); - if (dest == src) // prevent equip in same slot, only at cheat - return; - - Item* pDstItem = _player->GetItemByPos(dest); - if (!pDstItem) // empty slot, simple case - { - _player->RemoveItem(srcbag, srcslot, true); - _player->EquipItem(dest, pSrcItem, true); - _player->AutoUnequipOffhandIfNeed(); - } - else // have currently equipped item, not simple case - { - uint8 dstbag = pDstItem->GetBagSlot(); - uint8 dstslot = pDstItem->GetSlot(); - - msg = _player->CanUnequipItem(dest, !pSrcItem->IsBag()); - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, pDstItem, NULL); - return; - } - - // check dest->src move possibility - ItemPosCountVec sSrc; - uint16 eSrc = 0; - if (_player->IsInventoryPos(src)) - { - msg = _player->CanStoreItem(srcbag, srcslot, sSrc, pDstItem, true); - if (msg != EQUIP_ERR_OK) - msg = _player->CanStoreItem(srcbag, NULL_SLOT, sSrc, pDstItem, true); - if (msg != EQUIP_ERR_OK) - msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, sSrc, pDstItem, true); - } - else if (_player->IsBankPos(src)) - { - msg = _player->CanBankItem(srcbag, srcslot, sSrc, pDstItem, true); - if (msg != EQUIP_ERR_OK) - msg = _player->CanBankItem(srcbag, NULL_SLOT, sSrc, pDstItem, true); - if (msg != EQUIP_ERR_OK) - msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, sSrc, pDstItem, true); - } - else if (_player->IsEquipmentPos(src)) - { - msg = _player->CanEquipItem(srcslot, eSrc, pDstItem, true); - if (msg == EQUIP_ERR_OK) - msg = _player->CanUnequipItem(eSrc, true); - } - - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, pDstItem, pSrcItem); - return; - } - - // now do moves, remove... - _player->RemoveItem(dstbag, dstslot, false); - _player->RemoveItem(srcbag, srcslot, false); - - // add to dest - _player->EquipItem(dest, pSrcItem, true); - - // add to src - if (_player->IsInventoryPos(src)) - _player->StoreItem(sSrc, pDstItem, true); - else if (_player->IsBankPos(src)) - _player->BankItem(sSrc, pDstItem, true); - else if (_player->IsEquipmentPos(src)) - _player->EquipItem(eSrc, pDstItem, true); - - _player->AutoUnequipOffhandIfNeed(); - } -} - -void WorldSession::HandleDestroyItemOpcode(WorldPacket & recv_data) -{ - //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_DESTROYITEM"); - uint8 bag, slot, count, data1, data2, data3; - - recv_data >> bag >> slot >> count >> data1 >> data2 >> data3; - //sLog->outDebug("STORAGE: receive bag = %u, slot = %u, count = %u", bag, slot, count); - - uint16 pos = (bag << 8) | slot; - - // prevent drop unequipable items (in combat, for example) and non-empty bags - if (_player->IsEquipmentPos(pos) || _player->IsBagPos(pos)) - { - InventoryResult msg = _player->CanUnequipItem(pos, false); - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, _player->GetItemByPos(pos), NULL); - return; - } - } - - Item* pItem = _player->GetItemByPos(bag, slot); - if (!pItem) - { - _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } - - if (pItem->GetTemplate()->Flags & ITEM_PROTO_FLAG_INDESTRUCTIBLE) - { - _player->SendEquipError(EQUIP_ERR_CANT_DROP_SOULBOUND, NULL, NULL); - return; - } - - if (count) - { - uint32 i_count = count; - _player->DestroyItemCount(pItem, i_count, true); - } - else - _player->DestroyItem(bag, slot, true); -} - -// Only _static_ data send in this packet !!! -void WorldSession::HandleItemQuerySingleOpcode(WorldPacket & recv_data) -{ - //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_ITEM_QUERY_SINGLE"); - uint32 item; - recv_data >> item; - - sLog->outDetail("STORAGE: Item Query = %u", item); - - ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item); - if (pProto) - { - std::string Name = pProto->Name1; - std::string Description = pProto->Description; - - int loc_idx = GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - if (ItemLocale const* il = sObjectMgr->GetItemLocale(pProto->ItemId)) - { - ObjectMgr::GetLocaleString(il->Name, loc_idx, Name); - ObjectMgr::GetLocaleString(il->Description, loc_idx, Description); - } - } - // guess size - WorldPacket data(SMSG_ITEM_QUERY_SINGLE_RESPONSE, 600); - data << pProto->ItemId; - data << pProto->Class; - data << pProto->SubClass; - data << int32(pProto->Unk0); // new 2.0.3, not exist in wdb cache? - data << Name; - data << uint8(0x00); //pProto->Name2; // blizz not send name there, just uint8(0x00); <-- \0 = empty string = empty name... - data << uint8(0x00); //pProto->Name3; // blizz not send name there, just uint8(0x00); - data << uint8(0x00); //pProto->Name4; // blizz not send name there, just uint8(0x00); - data << pProto->DisplayInfoID; - data << pProto->Quality; - data << pProto->Flags; - data << pProto->Flags2; - data << pProto->BuyPrice; - data << pProto->SellPrice; - data << pProto->InventoryType; - data << pProto->AllowableClass; - data << pProto->AllowableRace; - data << pProto->ItemLevel; - data << pProto->RequiredLevel; - data << pProto->RequiredSkill; - data << pProto->RequiredSkillRank; - data << pProto->RequiredSpell; - data << pProto->RequiredHonorRank; - data << pProto->RequiredCityRank; - data << pProto->RequiredReputationFaction; - data << pProto->RequiredReputationRank; - data << int32(pProto->MaxCount); - data << int32(pProto->Stackable); - data << pProto->ContainerSlots; - data << pProto->StatsCount; // item stats count - for (uint32 i = 0; i < pProto->StatsCount; ++i) - { - data << pProto->ItemStat[i].ItemStatType; - data << pProto->ItemStat[i].ItemStatValue; - } - data << pProto->ScalingStatDistribution; // scaling stats distribution - data << pProto->ScalingStatValue; // some kind of flags used to determine stat values column - for (int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i) - { - data << pProto->Damage[i].DamageMin; - data << pProto->Damage[i].DamageMax; - data << pProto->Damage[i].DamageType; - } - - // resistances (7) - data << pProto->Armor; - data << pProto->HolyRes; - data << pProto->FireRes; - data << pProto->NatureRes; - data << pProto->FrostRes; - data << pProto->ShadowRes; - data << pProto->ArcaneRes; - - data << pProto->Delay; - data << pProto->AmmoType; - data << pProto->RangedModRange; - - for (int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s) - { - // send DBC data for cooldowns in same way as it used in Spell::SendSpellCooldown - // use `item_template` or if not set then only use spell cooldowns - SpellInfo const* spell = sSpellMgr->GetSpellInfo(pProto->Spells[s].SpellId); - if (spell) - { - bool db_data = pProto->Spells[s].SpellCooldown >= 0 || pProto->Spells[s].SpellCategoryCooldown >= 0; - - data << pProto->Spells[s].SpellId; - data << pProto->Spells[s].SpellTrigger; - data << uint32(-abs(pProto->Spells[s].SpellCharges)); - - if (db_data) - { - data << uint32(pProto->Spells[s].SpellCooldown); - data << uint32(pProto->Spells[s].SpellCategory); - data << uint32(pProto->Spells[s].SpellCategoryCooldown); - } - else - { - data << uint32(spell->RecoveryTime); - data << uint32(spell->Category); - data << uint32(spell->CategoryRecoveryTime); - } - } - else - { - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(-1); - data << uint32(0); - data << uint32(-1); - } - } - data << pProto->Bonding; - data << Description; - data << pProto->PageText; - data << pProto->LanguageID; - data << pProto->PageMaterial; - data << pProto->StartQuest; - data << pProto->LockID; - data << int32(pProto->Material); - data << pProto->Sheath; - data << pProto->RandomProperty; - data << pProto->RandomSuffix; - data << pProto->Block; - data << pProto->ItemSet; - data << pProto->MaxDurability; - data << pProto->Area; - data << pProto->Map; // Added in 1.12.x & 2.0.1 client branch - data << pProto->BagFamily; - data << pProto->TotemCategory; - for (int s = 0; s < MAX_ITEM_PROTO_SOCKETS; ++s) - { - data << pProto->Socket[s].Color; - data << pProto->Socket[s].Content; - } - data << pProto->socketBonus; - data << pProto->GemProperties; - data << pProto->RequiredDisenchantSkill; - data << pProto->ArmorDamageModifier; - data << uint32(abs(pProto->Duration)); // added in 2.4.2.8209, duration (seconds) - data << pProto->ItemLimitCategory; // WotLK, ItemLimitCategory - data << pProto->HolidayId; // Holiday.dbc? - SendPacket(&data); - } - else - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_ITEM_QUERY_SINGLE - NO item INFO! (ENTRY: %u)", item); - WorldPacket data(SMSG_ITEM_QUERY_SINGLE_RESPONSE, 4); - data << uint32(item | 0x80000000); - SendPacket(&data); - } -} - -void WorldSession::HandleReadItem(WorldPacket & recv_data) -{ - //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_READ_ITEM"); - - uint8 bag, slot; - recv_data >> bag >> slot; - - //sLog->outDetail("STORAGE: Read bag = %u, slot = %u", bag, slot); - Item* pItem = _player->GetItemByPos(bag, slot); - - if (pItem && pItem->GetTemplate()->PageText) - { - WorldPacket data; - - InventoryResult msg = _player->CanUseItem(pItem); - if (msg == EQUIP_ERR_OK) - { - data.Initialize (SMSG_READ_ITEM_OK, 8); - sLog->outDetail("STORAGE: Item page sent"); - } - else - { - data.Initialize(SMSG_READ_ITEM_FAILED, 8); - sLog->outDetail("STORAGE: Unable to read item"); - _player->SendEquipError(msg, pItem, NULL); - } - data << pItem->GetGUID(); - SendPacket(&data); - } - else - _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); -} - -void WorldSession::HandlePageQuerySkippedOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_PAGE_TEXT_QUERY"); - - uint32 itemid; - uint64 guid; - - recv_data >> itemid >> guid; - - sLog->outDetail("Packet Info: itemid: %u guidlow: %u guidentry: %u guidhigh: %u", - itemid, GUID_LOPART(guid), GUID_ENPART(guid), GUID_HIPART(guid)); -} - -void WorldSession::HandleSellItemOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_SELL_ITEM"); - uint64 vendorguid, itemguid; - uint32 count; - - recv_data >> vendorguid >> itemguid >> count; - - if (!itemguid) - return; - - Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR); - if (!creature) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleSellItemOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorguid))); - _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, itemguid, 0); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - Item* pItem = _player->GetItemByGuid(itemguid); - if (pItem) - { - // prevent sell not owner item - if (_player->GetGUID() != pItem->GetOwnerGUID()) - { - _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0); - return; - } - - // prevent sell non empty bag by drag-and-drop at vendor's item list - if (pItem->IsNotEmptyBag()) - { - _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0); - return; - } - - // prevent sell currently looted item - if (_player->GetLootGUID() == pItem->GetGUID()) - { - _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0); - return; - } - - // prevent selling item for sellprice when the item is still refundable - // this probably happens when right clicking a refundable item, the client sends both - // CMSG_SELL_ITEM and CMSG_REFUND_ITEM (unverified) - if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE)) - return; // Therefore, no feedback to client - - // special case at auto sell (sell all) - if (count == 0) - { - count = pItem->GetCount(); - } - else - { - // prevent sell more items that exist in stack (possible only not from client) - if (count > pItem->GetCount()) - { - _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0); - return; - } - } - - ItemTemplate const* pProto = pItem->GetTemplate(); - if (pProto) - { - if (pProto->SellPrice > 0) - { - if (count < pItem->GetCount()) // need split items - { - Item* pNewItem = pItem->CloneItem(count, _player); - if (!pNewItem) - { - sLog->outError("WORLD: HandleSellItemOpcode - could not create clone of item %u; count = %u", pItem->GetEntry(), count); - _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0); - return; - } - - pItem->SetCount(pItem->GetCount() - count); - _player->ItemRemovedQuestCheck(pItem->GetEntry(), count); - if (_player->IsInWorld()) - pItem->SendUpdateToPlayer(_player); - pItem->SetState(ITEM_CHANGED, _player); - - _player->AddItemToBuyBackSlot(pNewItem); - if (_player->IsInWorld()) - pNewItem->SendUpdateToPlayer(_player); - } - else - { - _player->ItemRemovedQuestCheck(pItem->GetEntry(), pItem->GetCount()); - _player->RemoveItem(pItem->GetBagSlot(), pItem->GetSlot(), true); - pItem->RemoveFromUpdateQueueOf(_player); - _player->AddItemToBuyBackSlot(pItem); - } - - uint32 money = pProto->SellPrice * count; - _player->ModifyMoney(money); - _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS, money); - } - else - _player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, itemguid, 0); - return; - } - } - _player->SendSellError(SELL_ERR_CANT_FIND_ITEM, creature, itemguid, 0); - return; -} - -void WorldSession::HandleBuybackItem(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_BUYBACK_ITEM"); - uint64 vendorguid; - uint32 slot; - - recv_data >> vendorguid >> slot; - - Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR); - if (!creature) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleBuybackItem - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorguid))); - _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - Item* pItem = _player->GetItemFromBuyBackSlot(slot); - if (pItem) - { - uint32 price = _player->GetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + slot - BUYBACK_SLOT_START); - if (!_player->HasEnoughMoney(price)) - { - _player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, creature, pItem->GetEntry(), 0); - return; - } - - ItemPosCountVec dest; - InventoryResult msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, pItem, false); - if (msg == EQUIP_ERR_OK) - { - _player->ModifyMoney(-(int32)price); - _player->RemoveItemFromBuyBackSlot(slot, false); - _player->ItemAddedQuestCheck(pItem->GetEntry(), pItem->GetCount()); - _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM, pItem->GetEntry(), pItem->GetCount()); - _player->StoreItem(dest, pItem, true); - } - else - _player->SendEquipError(msg, pItem, NULL); - return; - } - else - _player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, 0, 0); -} - -void WorldSession::HandleBuyItemInSlotOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_BUY_ITEM_IN_SLOT"); - uint64 vendorguid, bagguid; - uint32 item, slot, count; - uint8 bagslot; - - recv_data >> vendorguid >> item >> slot >> bagguid >> bagslot >> count; - - // client expects count starting at 1, and we send vendorslot+1 to client already - if (slot > 0) - --slot; - else - return; // cheating - - uint8 bag = NULL_BAG; // init for case invalid bagGUID - - // find bag slot by bag guid - if (bagguid == _player->GetGUID()) - bag = INVENTORY_SLOT_BAG_0; - else - { - for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) - { - if (Bag* pBag = _player->GetBagByPos(i)) - { - if (bagguid == pBag->GetGUID()) - { - bag = i; - break; - } - } - } - } - - // bag not found, cheating? - if (bag == NULL_BAG) - return; - - GetPlayer()->BuyItemFromVendorSlot(vendorguid, slot, item, count, bag, bagslot); -} - -void WorldSession::HandleBuyItemOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_BUY_ITEM"); - uint64 vendorguid; - uint32 item, slot, count; - uint8 unk1; - - recv_data >> vendorguid >> item >> slot >> count >> unk1; - - // client expects count starting at 1, and we send vendorslot+1 to client already - if (slot > 0) - --slot; - else - return; // cheating - - GetPlayer()->BuyItemFromVendorSlot(vendorguid, slot, item, count, NULL_BAG, NULL_SLOT); -} - -void WorldSession::HandleListInventoryOpcode(WorldPacket & recv_data) -{ - uint64 guid; - - recv_data >> guid; - - if (!GetPlayer()->isAlive()) - return; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_LIST_INVENTORY"); - - SendListInventory(guid); -} - -void WorldSession::SendListInventory(uint64 vendorGuid) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_LIST_INVENTORY"); - - Creature* vendor = GetPlayer()->GetNPCIfCanInteractWith(vendorGuid, UNIT_NPC_FLAG_VENDOR); - if (!vendor) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: SendListInventory - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(vendorGuid))); - _player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - // Stop the npc if moving - if (vendor->HasUnitState(UNIT_STAT_MOVING)) - vendor->StopMoving(); - - VendorItemData const* items = vendor->GetVendorItems(); - if (!items) - { - WorldPacket data(SMSG_LIST_INVENTORY, 8 + 1 + 1); - data << uint64(vendorGuid); - data << uint8(0); // count == 0, next will be error code - data << uint8(0); // "Vendor has no inventory" - SendPacket(&data); - return; - } - - uint8 itemCount = items->GetItemCount(); - uint8 count = 0; - - WorldPacket data(SMSG_LIST_INVENTORY, 8 + 1 + itemCount * 8 * 4); - data << uint64(vendorGuid); - - size_t countPos = data.wpos(); - data << uint8(count); - - float discountMod = _player->GetReputationPriceDiscount(vendor); - - for (uint8 slot = 0; slot < itemCount; ++slot) - { - if (VendorItem const* item = items->GetItem(slot)) - { - if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(item->item)) - { - if (!(itemTemplate->AllowableClass & _player->getClassMask()) && itemTemplate->Bonding == BIND_WHEN_PICKED_UP && !_player->isGameMaster()) - continue; - // Only display items in vendor lists for the team the - // player is on. If GM on, display all items. - if (!_player->isGameMaster() && ((itemTemplate->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY && _player->GetTeam() == ALLIANCE) || (itemTemplate->Flags2 == ITEM_FLAGS_EXTRA_ALLIANCE_ONLY && _player->GetTeam() == HORDE))) - continue; - - // Items sold out are not displayed in list - uint32 leftInStock = !item->maxcount ? 0xFFFFFFFF : vendor->GetVendorItemCurrentCount(item); - if (!_player->isGameMaster() && !leftInStock) - continue; - - ++count; - - // reputation discount - int32 price = item->IsGoldRequired(itemTemplate) ? uint32(floor(itemTemplate->BuyPrice * discountMod)) : 0; - - data << uint32(slot + 1); // client expects counting to start at 1 - data << uint32(item->item); - data << uint32(itemTemplate->DisplayInfoID); - data << int32(leftInStock); - data << uint32(price); - data << uint32(itemTemplate->MaxDurability); - data << uint32(itemTemplate->BuyCount); - data << uint32(item->ExtendedCost); - } - } - } - - if (count == 0) - { - data << uint8(0); - SendPacket(&data); - return; - } - - data.put(countPos, count); - SendPacket(&data); -} - -void WorldSession::HandleAutoStoreBagItemOpcode(WorldPacket & recv_data) -{ - //sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_AUTOSTORE_BAG_ITEM"); - uint8 srcbag, srcslot, dstbag; - - recv_data >> srcbag >> srcslot >> dstbag; - //sLog->outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u", srcbag, srcslot, dstbag); - - Item* pItem = _player->GetItemByPos(srcbag, srcslot); - if (!pItem) - return; - - if (!_player->IsValidPos(dstbag, NULL_SLOT, false)) // can be autostore pos - { - _player->SendEquipError(EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT, NULL, NULL); - return; - } - - uint16 src = pItem->GetPos(); - - // check unequip potability for equipped items and bank bags - if (_player->IsEquipmentPos (src) || _player->IsBagPos (src)) - { - InventoryResult msg = _player->CanUnequipItem(src, !_player->IsBagPos (src)); - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, pItem, NULL); - return; - } - } - - ItemPosCountVec dest; - InventoryResult msg = _player->CanStoreItem(dstbag, NULL_SLOT, dest, pItem, false); - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, pItem, NULL); - return; - } - - // no-op: placed in same slot - if (dest.size() == 1 && dest[0].pos == src) - { - // just remove grey item state - _player->SendEquipError(EQUIP_ERR_NONE, pItem, NULL); - return; - } - - _player->RemoveItem(srcbag, srcslot, true); - _player->StoreItem(dest, pItem, true); -} - -void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_BUY_BANK_SLOT"); - - uint64 guid; - recvPacket >> guid; - - // cheating protection - /* not critical if "cheated", and check skip allow by slots in bank windows open by .bank command. - Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_BANKER); - if (!creature) - { - sLog->outDebug("WORLD: HandleBuyBankSlotOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); - return; - } - */ - - uint32 slot = _player->GetBankBagSlotCount(); - - // next slot - ++slot; - - sLog->outDetail("PLAYER: Buy bank bag slot, slot number = %u", slot); - - BankBagSlotPricesEntry const* slotEntry = sBankBagSlotPricesStore.LookupEntry(slot); - - WorldPacket data(SMSG_BUY_BANK_SLOT_RESULT, 4); - - if (!slotEntry) - { - data << uint32(ERR_BANKSLOT_FAILED_TOO_MANY); - SendPacket(&data); - return; - } - - uint32 price = slotEntry->price; - - if (!_player->HasEnoughMoney(price)) - { - data << uint32(ERR_BANKSLOT_INSUFFICIENT_FUNDS); - SendPacket(&data); - return; - } - - _player->SetBankBagSlotCount(slot); - _player->ModifyMoney(-int32(price)); - - data << uint32(ERR_BANKSLOT_OK); - SendPacket(&data); - - _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT); -} - -void WorldSession::HandleAutoBankItemOpcode(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AUTOBANK_ITEM"); - uint8 srcbag, srcslot; - - recvPacket >> srcbag >> srcslot; - sLog->outDebug(LOG_FILTER_NETWORKIO, "STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot); - - Item* pItem = _player->GetItemByPos(srcbag, srcslot); - if (!pItem) - return; - - ItemPosCountVec dest; - InventoryResult msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, dest, pItem, false); - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, pItem, NULL); - return; - } - - if (dest.size() == 1 && dest[0].pos == pItem->GetPos()) - { - _player->SendEquipError(EQUIP_ERR_NONE, pItem, NULL); - return; - } - - _player->RemoveItem(srcbag, srcslot, true); - _player->ItemRemovedQuestCheck(pItem->GetEntry(), pItem->GetCount()); - _player->BankItem(dest, pItem, true); -} - -void WorldSession::HandleAutoStoreBankItemOpcode(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AUTOSTORE_BANK_ITEM"); - uint8 srcbag, srcslot; - - recvPacket >> srcbag >> srcslot; - sLog->outDebug(LOG_FILTER_NETWORKIO, "STORAGE: receive srcbag = %u, srcslot = %u", srcbag, srcslot); - - Item* pItem = _player->GetItemByPos(srcbag, srcslot); - if (!pItem) - return; - - if (_player->IsBankPos(srcbag, srcslot)) // moving from bank to inventory - { - ItemPosCountVec dest; - InventoryResult msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, pItem, false); - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, pItem, NULL); - return; - } - - _player->RemoveItem(srcbag, srcslot, true); - _player->StoreItem(dest, pItem, true); - _player->ItemAddedQuestCheck(pItem->GetEntry(), pItem->GetCount()); - } - else // moving from inventory to bank - { - ItemPosCountVec dest; - InventoryResult msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, dest, pItem, false); - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, pItem, NULL); - return; - } - - _player->RemoveItem(srcbag, srcslot, true); - _player->BankItem(dest, pItem, true); - } -} - -void WorldSession::HandleSetAmmoOpcode(WorldPacket & recv_data) -{ - if (!GetPlayer()->isAlive()) - { - GetPlayer()->SendEquipError(EQUIP_ERR_YOU_ARE_DEAD, NULL, NULL); - return; - } - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_SET_AMMO"); - uint32 item; - - recv_data >> item; - - if (!item) - GetPlayer()->RemoveAmmo(); - else - GetPlayer()->SetAmmo(item); -} - -void WorldSession::SendEnchantmentLog(uint64 Target, uint64 Caster, uint32 ItemID, uint32 SpellID) -{ - WorldPacket data(SMSG_ENCHANTMENTLOG, (8+8+4+4+1)); // last check 2.0.10 - data << uint64(Target); - data << uint64(Caster); - data << uint32(ItemID); - data << uint32(SpellID); - data << uint8(0); - SendPacket(&data); -} - -void WorldSession::SendItemEnchantTimeUpdate(uint64 Playerguid, uint64 Itemguid, uint32 slot, uint32 Duration) -{ - // last check 2.0.10 - WorldPacket data(SMSG_ITEM_ENCHANT_TIME_UPDATE, (8+4+4+8)); - data << uint64(Itemguid); - data << uint32(slot); - data << uint32(Duration); - data << uint64(Playerguid); - SendPacket(&data); -} - -void WorldSession::HandleItemNameQueryOpcode(WorldPacket & recv_data) -{ - uint32 itemid; - recv_data >> itemid; - recv_data.read_skip(); // guid - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_ITEM_NAME_QUERY %u", itemid); - ItemSetNameEntry const* pName = sObjectMgr->GetItemSetNameEntry(itemid); - if (pName) - { - std::string Name = pName->name; - int loc_idx = GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - if (ItemSetNameLocale const* isnl = sObjectMgr->GetItemSetNameLocale(itemid)) - ObjectMgr::GetLocaleString(isnl->Name, loc_idx, Name); - - WorldPacket data(SMSG_ITEM_NAME_QUERY_RESPONSE, (4+Name.size()+1+4)); - data << uint32(itemid); - data << Name; - data << uint32(pName->InventoryType); - SendPacket(&data); - } -} - -void WorldSession::HandleWrapItemOpcode(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode CMSG_WRAP_ITEM"); - - uint8 gift_bag, gift_slot, item_bag, item_slot; - - recv_data >> gift_bag >> gift_slot; // paper - recv_data >> item_bag >> item_slot; // item - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WRAP: receive gift_bag = %u, gift_slot = %u, item_bag = %u, item_slot = %u", gift_bag, gift_slot, item_bag, item_slot); - - Item* gift = _player->GetItemByPos(gift_bag, gift_slot); - if (!gift) - { - _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL); - return; - } - - if (!(gift->GetTemplate()->Flags & ITEM_PROTO_FLAG_WRAPPER)) // cheating: non-wrapper wrapper - { - _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL); - return; - } - - Item* item = _player->GetItemByPos(item_bag, item_slot); - - if (!item) - { - _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, item, NULL); - return; - } - - if (item == gift) // not possable with pacjket from real client - { - _player->SendEquipError(EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL); - return; - } - - if (item->IsEquipped()) - { - _player->SendEquipError(EQUIP_ERR_EQUIPPED_CANT_BE_WRAPPED, item, NULL); - return; - } - - if (item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR)) // HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED); - { - _player->SendEquipError(EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED, item, NULL); - return; - } - - if (item->IsBag()) - { - _player->SendEquipError(EQUIP_ERR_BAGS_CANT_BE_WRAPPED, item, NULL); - return; - } - - if (item->IsSoulBound()) - { - _player->SendEquipError(EQUIP_ERR_BOUND_CANT_BE_WRAPPED, item, NULL); - return; - } - - if (item->GetMaxStackCount() != 1) - { - _player->SendEquipError(EQUIP_ERR_STACKABLE_CANT_BE_WRAPPED, item, NULL); - return; - } - - // maybe not correct check (it is better than nothing) - if (item->GetTemplate()->MaxCount>0) - { - _player->SendEquipError(EQUIP_ERR_UNIQUE_CANT_BE_WRAPPED, item, NULL); - return; - } - - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - trans->PAppend("INSERT INTO character_gifts VALUES ('%u', '%u', '%u', '%u')", GUID_LOPART(item->GetOwnerGUID()), item->GetGUIDLow(), item->GetEntry(), item->GetUInt32Value(ITEM_FIELD_FLAGS)); - item->SetEntry(gift->GetEntry()); - - switch (item->GetEntry()) - { - case 5042: item->SetEntry(5043); break; - case 5048: item->SetEntry(5044); break; - case 17303: item->SetEntry(17302); break; - case 17304: item->SetEntry(17305); break; - case 17307: item->SetEntry(17308); break; - case 21830: item->SetEntry(21831); break; - } - item->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, _player->GetGUID()); - item->SetUInt32Value(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED); - item->SetState(ITEM_CHANGED, _player); - - if (item->GetState() == ITEM_NEW) // save new item, to have alway for `character_gifts` record in `item_instance` - { - // after save it will be impossible to remove the item from the queue - item->RemoveFromUpdateQueueOf(_player); - item->SaveToDB(trans); // item gave inventory record unchanged and can be save standalone - } - CharacterDatabase.CommitTransaction(trans); - - uint32 count = 1; - _player->DestroyItemCount(gift, count, true); -} - -void WorldSession::HandleSocketOpcode(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_SOCKET_GEMS"); - - uint64 item_guid; - uint64 gem_guids[MAX_GEM_SOCKETS]; - - recv_data >> item_guid; - if (!item_guid) - return; - - for (int i = 0; i < MAX_GEM_SOCKETS; ++i) - recv_data >> gem_guids[i]; - - //cheat -> tried to socket same gem multiple times - if ((gem_guids[0] && (gem_guids[0] == gem_guids[1] || gem_guids[0] == gem_guids[2])) || - (gem_guids[1] && (gem_guids[1] == gem_guids[2]))) - return; - - Item* itemTarget = _player->GetItemByGuid(item_guid); - if (!itemTarget) //missing item to socket - return; - - ItemTemplate const* itemProto = itemTarget->GetTemplate(); - if (!itemProto) - return; - - //this slot is excepted when applying / removing meta gem bonus - uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : uint8(NULL_SLOT); - - Item* Gems[MAX_GEM_SOCKETS]; - for (int i = 0; i < MAX_GEM_SOCKETS; ++i) - Gems[i] = gem_guids[i] ? _player->GetItemByGuid(gem_guids[i]) : NULL; - - GemPropertiesEntry const* GemProps[MAX_GEM_SOCKETS]; - for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //get geminfo from dbc storage - GemProps[i] = (Gems[i]) ? sGemPropertiesStore.LookupEntry(Gems[i]->GetTemplate()->GemProperties) : NULL; - - for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //check for hack maybe - { - if (!GemProps[i]) - continue; - - // tried to put gem in socket where no socket exists (take care about prismatic sockets) - if (!itemProto->Socket[i].Color) - { - // no prismatic socket - if (!itemTarget->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT)) - return; - - // not first not-colored (not normaly used) socket - if (i != 0 && !itemProto->Socket[i-1].Color && (i+1 >= MAX_GEM_SOCKETS || itemProto->Socket[i+1].Color)) - return; - - // ok, this is first not colored socket for item with prismatic socket - } - - // tried to put normal gem in meta socket - if (itemProto->Socket[i].Color == SOCKET_COLOR_META && GemProps[i]->color != SOCKET_COLOR_META) - return; - - // tried to put meta gem in normal socket - if (itemProto->Socket[i].Color != SOCKET_COLOR_META && GemProps[i]->color == SOCKET_COLOR_META) - return; - } - - uint32 GemEnchants[MAX_GEM_SOCKETS]; - uint32 OldEnchants[MAX_GEM_SOCKETS]; - for (int i = 0; i < MAX_GEM_SOCKETS; ++i) //get new and old enchantments - { - GemEnchants[i] = (GemProps[i]) ? GemProps[i]->spellitemenchantement : 0; - OldEnchants[i] = itemTarget->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i)); - } - - // check unique-equipped conditions - for (int i = 0; i < MAX_GEM_SOCKETS; ++i) - { - if (!Gems[i]) - continue; - - // continue check for case when attempt add 2 similar unique equipped gems in one item. - ItemTemplate const* iGemProto = Gems[i]->GetTemplate(); - - // unique item (for new and already placed bit removed enchantments - if (iGemProto->Flags & ITEM_PROTO_FLAG_UNIQUE_EQUIPPED) - { - for (int j = 0; j < MAX_GEM_SOCKETS; ++j) - { - if (i == j) // skip self - continue; - - if (Gems[j]) - { - if (iGemProto->ItemId == Gems[j]->GetEntry()) - { - _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); - return; - } - } - else if (OldEnchants[j]) - { - if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j])) - { - if (iGemProto->ItemId == enchantEntry->GemID) - { - _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); - return; - } - } - } - - } - } - - // unique limit type item - int32 limit_newcount = 0; - if (iGemProto->ItemLimitCategory) - { - if (ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(iGemProto->ItemLimitCategory)) - { - // NOTE: limitEntry->mode is not checked because if item has limit then it is applied in equip case - for (int j = 0; j < MAX_GEM_SOCKETS; ++j) - { - if (Gems[j]) - { - // new gem - if (iGemProto->ItemLimitCategory == Gems[j]->GetTemplate()->ItemLimitCategory) - ++limit_newcount; - } - else if (OldEnchants[j]) - { - // existing gem - if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j])) - if (ItemTemplate const* jProto = sObjectMgr->GetItemTemplate(enchantEntry->GemID)) - if (iGemProto->ItemLimitCategory == jProto->ItemLimitCategory) - ++limit_newcount; - } - } - - if (limit_newcount > 0 && uint32(limit_newcount) > limitEntry->maxCount) - { - _player->SendEquipError(EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL); - return; - } - } - } - - // for equipped item check all equipment for duplicate equipped gems - if (itemTarget->IsEquipped()) - { - if (InventoryResult res = _player->CanEquipUniqueItem(Gems[i], slot, std::max(limit_newcount, 0))) - { - _player->SendEquipError(res, itemTarget, NULL); - return; - } - } - } - - bool SocketBonusActivated = itemTarget->GemsFitSockets(); //save state of socketbonus - _player->ToggleMetaGemsActive(slot, false); //turn off all metagems (except for the target item) - - //if a meta gem is being equipped, all information has to be written to the item before testing if the conditions for the gem are met - - //remove ALL enchants - for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + MAX_GEM_SOCKETS; ++enchant_slot) - _player->ApplyEnchantment(itemTarget, EnchantmentSlot(enchant_slot), false); - - for (int i = 0; i < MAX_GEM_SOCKETS; ++i) - { - if (GemEnchants[i]) - { - itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i), GemEnchants[i], 0, 0); - if (Item* guidItem = _player->GetItemByGuid(gem_guids[i])) - _player->DestroyItem(guidItem->GetBagSlot(), guidItem->GetSlot(), true); - } - } - - for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot) - _player->ApplyEnchantment(itemTarget, EnchantmentSlot(enchant_slot), true); - - bool SocketBonusToBeActivated = itemTarget->GemsFitSockets();//current socketbonus state - if (SocketBonusActivated ^ SocketBonusToBeActivated) //if there was a change... - { - _player->ApplyEnchantment(itemTarget, BONUS_ENCHANTMENT_SLOT, false); - itemTarget->SetEnchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetTemplate()->socketBonus : 0), 0, 0); - _player->ApplyEnchantment(itemTarget, BONUS_ENCHANTMENT_SLOT, true); - //it is not displayed, client has an inbuilt system to determine if the bonus is activated - } - - _player->ToggleMetaGemsActive(slot, true); //turn on all metagems (except for target item) - - itemTarget->ClearSoulboundTradeable(_player); // clear tradeable flag -} - -void WorldSession::HandleCancelTempEnchantmentOpcode(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CANCEL_TEMP_ENCHANTMENT"); - - uint32 eslot; - - recv_data >> eslot; - - // apply only to equipped item - if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, eslot)) - return; - - Item* item = GetPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, eslot); - - if (!item) - return; - - if (!item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)) - return; - - GetPlayer()->ApplyEnchantment(item, TEMP_ENCHANTMENT_SLOT, false); - item->ClearEnchantment(TEMP_ENCHANTMENT_SLOT); -} - -void WorldSession::HandleItemRefundInfoRequest(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_ITEM_REFUND_INFO"); - - uint64 guid; - recv_data >> guid; // item guid - - Item* item = _player->GetItemByGuid(guid); - if (!item) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "Item refund: item not found!"); - return; - } - - GetPlayer()->SendRefundInfo(item); -} - -void WorldSession::HandleItemRefund(WorldPacket &recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_ITEM_REFUND"); - uint64 guid; - recv_data >> guid; // item guid - - Item* item = _player->GetItemByGuid(guid); - if (!item) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "Item refund: item not found!"); - return; - } - - GetPlayer()->RefundItem(item); -} - -/** - * Handles the packet sent by the client when requesting information about item text. - * - * This function is called when player clicks on item which has some flag set - */ -void WorldSession::HandleItemTextQuery(WorldPacket & recv_data ) -{ - uint64 itemGuid; - recv_data >> itemGuid; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_ITEM_TEXT_QUERY item guid: %u", GUID_LOPART(itemGuid)); - - WorldPacket data(SMSG_ITEM_TEXT_QUERY_RESPONSE, (4+10)); // guess size - - if (Item* item = _player->GetItemByGuid(itemGuid)) - { - data << uint8(0); // has text - data << uint64(itemGuid); // item guid - data << item->GetText(); - } - else - { - data << uint8(1); // no text - } - - SendPacket(&data); -} diff --git a/src/server/game/Server/Protocol/Handlers/LFGHandler.cpp b/src/server/game/Server/Protocol/Handlers/LFGHandler.cpp deleted file mode 100755 index 3c6bd28b5cb..00000000000 --- a/src/server/game/Server/Protocol/Handlers/LFGHandler.cpp +++ /dev/null @@ -1,664 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "WorldSession.h" -#include "WorldPacket.h" -#include "DBCStores.h" -#include "Player.h" -#include "Group.h" -#include "LFGMgr.h" -#include "ObjectMgr.h" -#include "GroupMgr.h" -#include "InstanceScript.h" - -void BuildPlayerLockDungeonBlock(WorldPacket& data, const LfgLockMap& lock) -{ - data << uint32(lock.size()); // Size of lock dungeons - for (LfgLockMap::const_iterator it = lock.begin(); it != lock.end(); ++it) - { - data << uint32(it->first); // Dungeon entry (id + type) - data << uint32(it->second); // Lock status - } -} - -void BuildPartyLockDungeonBlock(WorldPacket& data, const LfgLockPartyMap& lockMap) -{ - data << uint8(lockMap.size()); - for (LfgLockPartyMap::const_iterator it = lockMap.begin(); it != lockMap.end(); ++it) - { - data << uint64(it->first); // Player guid - BuildPlayerLockDungeonBlock(data, it->second); - } -} - -void WorldSession::HandleLfgJoinOpcode(WorldPacket& recv_data) -{ - if (!sWorld->getBoolConfig(CONFIG_DUNGEON_FINDER_ENABLE) || - (GetPlayer()->GetGroup() && GetPlayer()->GetGroup()->GetLeaderGUID() != GetPlayer()->GetGUID() && - (GetPlayer()->GetGroup()->GetMembersCount() == MAXGROUPSIZE || !GetPlayer()->GetGroup()->isLFGGroup()))) - { - recv_data.rfinish(); - return; - } - - uint8 numDungeons; - uint32 dungeon; - uint32 roles; - - recv_data >> roles; - recv_data.read_skip(); // uint8 (always 0) - uint8 (always 0) - recv_data >> numDungeons; - if (!numDungeons) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_JOIN [" UI64FMTD "] no dungeons selected", GetPlayer()->GetGUID()); - recv_data.rfinish(); - return; - } - - LfgDungeonSet newDungeons; - for (int8 i = 0 ; i < numDungeons; ++i) - { - recv_data >> dungeon; - newDungeons.insert((dungeon & 0x00FFFFFF)); // remove the type from the dungeon entry - } - - recv_data.read_skip(); // for 0..uint8 (always 3) { uint8 (always 0) } - - std::string comment; - recv_data >> comment; - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_JOIN [" UI64FMTD "] roles: %u, Dungeons: %u, Comment: %s", GetPlayer()->GetGUID(), roles, uint8(newDungeons.size()), comment.c_str()); - sLFGMgr->Join(GetPlayer(), uint8(roles), newDungeons, comment); -} - -void WorldSession::HandleLfgLeaveOpcode(WorldPacket& /*recv_data*/) -{ - Group* grp = GetPlayer()->GetGroup(); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_LEAVE [" UI64FMTD "] in group: %u", GetPlayer()->GetGUID(), grp ? 1 : 0); - - // Check cheating - only leader can leave the queue - if (!grp || grp->GetLeaderGUID() == GetPlayer()->GetGUID()) - sLFGMgr->Leave(GetPlayer(), grp); -} - -void WorldSession::HandleLfgProposalResultOpcode(WorldPacket& recv_data) -{ - uint32 lfgGroupID; // Internal lfgGroupID - bool accept; // Accept to join? - recv_data >> lfgGroupID; - recv_data >> accept; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_PROPOSAL_RESULT [" UI64FMTD "] proposal: %u accept: %u", GetPlayer()->GetGUID(), lfgGroupID, accept ? 1 : 0); - sLFGMgr->UpdateProposal(lfgGroupID, GetPlayer()->GetGUID(), accept); -} - -void WorldSession::HandleLfgSetRolesOpcode(WorldPacket& recv_data) -{ - uint8 roles; - recv_data >> roles; // Player Group Roles - uint64 guid = GetPlayer()->GetGUID(); - Group* grp = GetPlayer()->GetGroup(); - if (!grp) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_SET_ROLES [" UI64FMTD "] Not in group", guid); - return; - } - uint64 gguid = grp->GetGUID(); - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_SET_ROLES: Group [" UI64FMTD "], Player [" UI64FMTD "], Roles: %u", gguid, guid, roles); - sLFGMgr->UpdateRoleCheck(gguid, guid, roles); -} - -void WorldSession::HandleLfgSetCommentOpcode(WorldPacket& recv_data) -{ - std::string comment; - recv_data >> comment; - uint64 guid = GetPlayer()->GetGUID(); - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_SET_LFG_COMMENT [" UI64FMTD "] comment: %s", guid, comment.c_str()); - - sLFGMgr->SetComment(guid, comment); -} - -void WorldSession::HandleLfgSetBootVoteOpcode(WorldPacket& recv_data) -{ - bool agree; // Agree to kick player - recv_data >> agree; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_SET_BOOT_VOTE [" UI64FMTD "] agree: %u", GetPlayer()->GetGUID(), agree ? 1 : 0); - sLFGMgr->UpdateBoot(GetPlayer(), agree); -} - -void WorldSession::HandleLfgTeleportOpcode(WorldPacket& recv_data) -{ - bool out; - recv_data >> out; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_TELEPORT [" UI64FMTD "] out: %u", GetPlayer()->GetGUID(), out ? 1 : 0); - sLFGMgr->TeleportPlayer(GetPlayer(), out, true); -} - -void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& /*recv_data*/) -{ - uint64 guid = GetPlayer()->GetGUID(); - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFD_PLAYER_LOCK_INFO_REQUEST [" UI64FMTD "]", guid); - - // Get Random dungeons that can be done at a certain level and expansion - // FIXME - Should return seasonals (when not disabled) - LfgDungeonSet randomDungeons; - uint8 level = GetPlayer()->getLevel(); - uint8 expansion = GetPlayer()->GetSession()->Expansion(); - for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i) - { - LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(i); - if (dungeon && dungeon->type == LFG_TYPE_RANDOM && dungeon->expansion <= expansion && - dungeon->minlevel <= level && level <= dungeon->maxlevel) - randomDungeons.insert(dungeon->Entry()); - } - - // Get player locked Dungeons - LfgLockMap lock = sLFGMgr->GetLockedDungeons(guid); - uint32 rsize = uint32(randomDungeons.size()); - uint32 lsize = uint32(lock.size()); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_PLAYER_INFO [" UI64FMTD "]", guid); - WorldPacket data(SMSG_LFG_PLAYER_INFO, 1 + rsize * (4 + 1 + 4 + 4 + 4 + 4 + 1 + 4 + 4 + 4) + 4 + lsize * (1 + 4 + 4 + 4 + 4 + 1 + 4 + 4 + 4)); - - data << uint8(randomDungeons.size()); // Random Dungeon count - for (LfgDungeonSet::const_iterator it = randomDungeons.begin(); it != randomDungeons.end(); ++it) - { - data << uint32(*it); // Dungeon Entry (id + type) - LfgReward const* reward = sLFGMgr->GetRandomDungeonReward(*it, level); - Quest const* qRew = NULL; - uint8 done = 0; - if (reward) - { - qRew = sObjectMgr->GetQuestTemplate(reward->reward[0].questId); - if (qRew) - { - done = !GetPlayer()->CanRewardQuest(qRew, false); - if (done) - qRew = sObjectMgr->GetQuestTemplate(reward->reward[1].questId); - } - } - if (qRew) - { - data << uint8(done); - data << uint32(qRew->GetRewOrReqMoney()); - data << uint32(qRew->XPValue(GetPlayer())); - data << uint32(reward->reward[done].variableMoney); - data << uint32(reward->reward[done].variableXP); - data << uint8(qRew->GetRewItemsCount()); - if (qRew->GetRewItemsCount()) - { - ItemTemplate const* iProto = NULL; - for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i) - { - if (!qRew->RewardItemId[i]) - continue; - - iProto = sObjectMgr->GetItemTemplate(qRew->RewardItemId[i]); - - data << uint32(qRew->RewardItemId[i]); - data << uint32(iProto ? iProto->DisplayInfoID : 0); - data << uint32(qRew->RewardItemIdCount[i]); - } - } - } - else - { - data << uint8(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint8(0); - } - } - BuildPlayerLockDungeonBlock(data, lock); - SendPacket(&data); -} - -void WorldSession::HandleLfgPartyLockInfoRequestOpcode(WorldPacket& /*recv_data*/) -{ - uint64 guid = GetPlayer()->GetGUID(); - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFD_PARTY_LOCK_INFO_REQUEST [" UI64FMTD "]", guid); - - Group* grp = GetPlayer()->GetGroup(); - if (!grp) - return; - - // Get the locked dungeons of the other party members - LfgLockPartyMap lockMap; - for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* plrg = itr->getSource(); - if (!plrg) - continue; - - uint64 pguid = plrg->GetGUID(); - if (pguid == guid) - continue; - - lockMap[pguid] = sLFGMgr->GetLockedDungeons(pguid); - } - - uint32 size = 0; - for (LfgLockPartyMap::const_iterator it = lockMap.begin(); it != lockMap.end(); ++it) - size += 8 + 4 + uint32(it->second.size()) * (4 + 4); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_PARTY_INFO [" UI64FMTD "]", guid); - WorldPacket data(SMSG_LFG_PARTY_INFO, 1 + size); - BuildPartyLockDungeonBlock(data, lockMap); - SendPacket(&data); -} - -void WorldSession::HandleLfrSearchOpcode(WorldPacket& recv_data) -{ - uint32 entry; // Raid id to search - recv_data >> entry; - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_SEARCH_LFG_JOIN [" UI64FMTD "] dungeon entry: %u", GetPlayer()->GetGUID(), entry); - //SendLfrUpdateListOpcode(entry); -} - -void WorldSession::HandleLfrLeaveOpcode(WorldPacket& recv_data) -{ - uint32 dungeonId; // Raid id queue to leave - recv_data >> dungeonId; - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_SEARCH_LFG_LEAVE [" UI64FMTD "] dungeonId: %u", GetPlayer()->GetGUID(), dungeonId); - //sLFGMgr->LeaveLfr(GetPlayer(), dungeonId); -} - -void WorldSession::SendLfgUpdatePlayer(const LfgUpdateData& updateData) -{ - bool queued = false; - bool extrainfo = false; - - switch (updateData.updateType) - { - case LFG_UPDATETYPE_JOIN_PROPOSAL: - case LFG_UPDATETYPE_ADDED_TO_QUEUE: - queued = true; - extrainfo = true; - break; - //case LFG_UPDATETYPE_CLEAR_LOCK_LIST: // TODO: Sometimes has extrainfo - Check ocurrences... - case LFG_UPDATETYPE_PROPOSAL_BEGIN: - extrainfo = true; - break; - default: - break; - } - - uint64 guid = GetPlayer()->GetGUID(); - uint8 size = uint8(updateData.dungeons.size()); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_UPDATE_PLAYER [" UI64FMTD "] updatetype: %u", guid, updateData.updateType); - WorldPacket data(SMSG_LFG_UPDATE_PLAYER, 1 + 1 + (extrainfo ? 1 : 0) * (1 + 1 + 1 + 1 + size * 4 + updateData.comment.length())); - data << uint8(updateData.updateType); // Lfg Update type - data << uint8(extrainfo); // Extra info - if (extrainfo) - { - data << uint8(queued); // Join the queue - data << uint8(0); // unk - Always 0 - data << uint8(0); // unk - Always 0 - - data << uint8(size); - if (size) - for (LfgDungeonSet::const_iterator it = updateData.dungeons.begin(); it != updateData.dungeons.end(); ++it) - data << uint32(*it); - data << updateData.comment; - } - SendPacket(&data); -} - -void WorldSession::SendLfgUpdateParty(const LfgUpdateData& updateData) -{ - bool join = false; - bool extrainfo = false; - bool queued = false; - - switch (updateData.updateType) - { - case LFG_UPDATETYPE_JOIN_PROPOSAL: - extrainfo = true; - break; - case LFG_UPDATETYPE_ADDED_TO_QUEUE: - extrainfo = true; - join = true; - queued = true; - break; - case LFG_UPDATETYPE_CLEAR_LOCK_LIST: - // join = true; // TODO: Sometimes queued and extrainfo - Check ocurrences... - queued = true; - break; - case LFG_UPDATETYPE_PROPOSAL_BEGIN: - extrainfo = true; - join = true; - break; - default: - break; - } - - uint64 guid = GetPlayer()->GetGUID(); - uint8 size = uint8(updateData.dungeons.size()); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_UPDATE_PARTY [" UI64FMTD "] updatetype: %u", guid, updateData.updateType); - WorldPacket data(SMSG_LFG_UPDATE_PARTY, 1 + 1 + (extrainfo ? 1 : 0) * (1 + 1 + 1 + 1 + 1 + size * 4 + updateData.comment.length())); - data << uint8(updateData.updateType); // Lfg Update type - data << uint8(extrainfo); // Extra info - if (extrainfo) - { - data << uint8(join); // LFG Join - data << uint8(queued); // Join the queue - data << uint8(0); // unk - Always 0 - data << uint8(0); // unk - Always 0 - for (uint8 i = 0; i < 3; ++i) - data << uint8(0); // unk - Always 0 - - data << uint8(size); - if (size) - for (LfgDungeonSet::const_iterator it = updateData.dungeons.begin(); it != updateData.dungeons.end(); ++it) - data << uint32(*it); - data << updateData.comment; - } - SendPacket(&data); -} - -void WorldSession::SendLfgRoleChosen(uint64 guid, uint8 roles) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_ROLE_CHOSEN [" UI64FMTD "] guid: [" UI64FMTD "] roles: %u", GetPlayer()->GetGUID(), guid, roles); - - WorldPacket data(SMSG_LFG_ROLE_CHOSEN, 8 + 1 + 4); - data << uint64(guid); // Guid - data << uint8(roles > 0); // Ready - data << uint32(roles); // Roles - SendPacket(&data); -} - -void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck* pRoleCheck) -{ - ASSERT(pRoleCheck); - LfgDungeonSet dungeons; - if (pRoleCheck->rDungeonId) - dungeons.insert(pRoleCheck->rDungeonId); - else - dungeons = pRoleCheck->dungeons; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_ROLE_CHECK_UPDATE [" UI64FMTD "]", GetPlayer()->GetGUID()); - WorldPacket data(SMSG_LFG_ROLE_CHECK_UPDATE, 4 + 1 + 1 + dungeons.size() * 4 + 1 + pRoleCheck->roles.size() * (8 + 1 + 4 + 1)); - - data << uint32(pRoleCheck->state); // Check result - data << uint8(pRoleCheck->state == LFG_ROLECHECK_INITIALITING); - data << uint8(dungeons.size()); // Number of dungeons - if (!dungeons.empty()) - { - for (LfgDungeonSet::iterator it = dungeons.begin(); it != dungeons.end(); ++it) - { - LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(*it); - data << uint32(dungeon ? dungeon->Entry() : 0); // Dungeon - } - } - - data << uint8(pRoleCheck->roles.size()); // Players in group - if (!pRoleCheck->roles.empty()) - { - // Leader info MUST be sent 1st :S - uint64 guid = pRoleCheck->leader; - uint8 roles = pRoleCheck->roles.find(guid)->second; - data << uint64(guid); // Guid - data << uint8(roles > 0); // Ready - data << uint32(roles); // Roles - Player* player = ObjectAccessor::FindPlayer(guid); - data << uint8(player ? player->getLevel() : 0); // Level - - for (LfgRolesMap::const_iterator it = pRoleCheck->roles.begin(); it != pRoleCheck->roles.end(); ++it) - { - if (it->first == pRoleCheck->leader) - continue; - - guid = it->first; - roles = it->second; - data << uint64(guid); // Guid - data << uint8(roles > 0); // Ready - data << uint32(roles); // Roles - player = ObjectAccessor::FindPlayer(guid); - data << uint8(player ? player->getLevel() : 0); // Level - } - } - SendPacket(&data); -} - -void WorldSession::SendLfgJoinResult(const LfgJoinResultData& joinData) -{ - uint32 size = 0; - for (LfgLockPartyMap::const_iterator it = joinData.lockmap.begin(); it != joinData.lockmap.end(); ++it) - size += 8 + 4 + uint32(it->second.size()) * (4 + 4); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_JOIN_RESULT [" UI64FMTD "] checkResult: %u checkValue: %u", GetPlayer()->GetGUID(), joinData.result, joinData.state); - WorldPacket data(SMSG_LFG_JOIN_RESULT, 4 + 4 + size); - data << uint32(joinData.result); // Check Result - data << uint32(joinData.state); // Check Value - if (!joinData.lockmap.empty()) - BuildPartyLockDungeonBlock(data, joinData.lockmap); - SendPacket(&data); -} - -void WorldSession::SendLfgQueueStatus(uint32 dungeon, int32 waitTime, int32 avgWaitTime, int32 waitTimeTanks, int32 waitTimeHealer, int32 waitTimeDps, uint32 queuedTime, uint8 tanks, uint8 healers, uint8 dps) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_QUEUE_STATUS [" UI64FMTD "] dungeon: %u - waitTime: %d - avgWaitTime: %d - waitTimeTanks: %d - waitTimeHealer: %d - waitTimeDps: %d - queuedTime: %u - tanks: %u - healers: %u - dps: %u", GetPlayer()->GetGUID(), dungeon, waitTime, avgWaitTime, waitTimeTanks, waitTimeHealer, waitTimeDps, queuedTime, tanks, healers, dps); - - WorldPacket data(SMSG_LFG_QUEUE_STATUS, 4 + 4 + 4 + 4 + 4 +4 + 1 + 1 + 1 + 4); - data << uint32(dungeon); // Dungeon - data << int32(avgWaitTime); // Average Wait time - data << int32(waitTime); // Wait Time - data << int32(waitTimeTanks); // Wait Tanks - data << int32(waitTimeHealer); // Wait Healers - data << int32(waitTimeDps); // Wait Dps - data << uint8(tanks); // Tanks needed - data << uint8(healers); // Healers needed - data << uint8(dps); // Dps needed - data << uint32(queuedTime); // Player wait time in queue - SendPacket(&data); -} - -void WorldSession::SendLfgPlayerReward(uint32 rdungeonEntry, uint32 sdungeonEntry, uint8 done, const LfgReward* reward, const Quest* qRew) -{ - if (!rdungeonEntry || !sdungeonEntry || !qRew) - return; - - uint8 itemNum = uint8(qRew ? qRew->GetRewItemsCount() : 0); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_PLAYER_REWARD [" UI64FMTD "] rdungeonEntry: %u - sdungeonEntry: %u - done: %u", GetPlayer()->GetGUID(), rdungeonEntry, sdungeonEntry, done); - WorldPacket data(SMSG_LFG_PLAYER_REWARD, 4 + 4 + 1 + 4 + 4 + 4 + 4 + 4 + 1 + itemNum * (4 + 4 + 4)); - data << uint32(rdungeonEntry); // Random Dungeon Finished - data << uint32(sdungeonEntry); // Dungeon Finished - data << uint8(done); - data << uint32(1); - data << uint32(qRew->GetRewOrReqMoney()); - data << uint32(qRew->XPValue(GetPlayer())); - data << uint32(reward->reward[done].variableMoney); - data << uint32(reward->reward[done].variableXP); - data << uint8(itemNum); - if (itemNum) - { - ItemTemplate const* iProto = NULL; - for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i) - { - if (!qRew->RewardItemId[i]) - continue; - - iProto = sObjectMgr->GetItemTemplate(qRew->RewardItemId[i]); - - data << uint32(qRew->RewardItemId[i]); - data << uint32(iProto ? iProto->DisplayInfoID : 0); - data << uint32(qRew->RewardItemIdCount[i]); - } - } - SendPacket(&data); -} - -void WorldSession::SendLfgBootPlayer(const LfgPlayerBoot* pBoot) -{ - uint64 guid = GetPlayer()->GetGUID(); - LfgAnswer playerVote = pBoot->votes.find(guid)->second; - uint8 votesNum = 0; - uint8 agreeNum = 0; - uint32 secsleft = uint8((pBoot->cancelTime - time(NULL)) / 1000); - for (LfgAnswerMap::const_iterator it = pBoot->votes.begin(); it != pBoot->votes.end(); ++it) - { - if (it->second != LFG_ANSWER_PENDING) - { - ++votesNum; - if (it->second == LFG_ANSWER_AGREE) - ++agreeNum; - } - } - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_BOOT_PLAYER [" UI64FMTD "] inProgress: %u - didVote: %u - agree: %u - victim: [" UI64FMTD "] votes: %u - agrees: %u - left: %u - needed: %u - reason %s", - guid, uint8(pBoot->inProgress), uint8(playerVote != LFG_ANSWER_PENDING), uint8(playerVote == LFG_ANSWER_AGREE), pBoot->victim, votesNum, agreeNum, secsleft, pBoot->votedNeeded, pBoot->reason.c_str()); - WorldPacket data(SMSG_LFG_BOOT_PLAYER, 1 + 1 + 1 + 8 + 4 + 4 + 4 + 4 + pBoot->reason.length()); - data << uint8(pBoot->inProgress); // Vote in progress - data << uint8(playerVote != LFG_ANSWER_PENDING); // Did Vote - data << uint8(playerVote == LFG_ANSWER_AGREE); // Agree - data << uint64(pBoot->victim); // Victim GUID - data << uint32(votesNum); // Total Votes - data << uint32(agreeNum); // Agree Count - data << uint32(secsleft); // Time Left - data << uint32(pBoot->votedNeeded); // Needed Votes - data << pBoot->reason.c_str(); // Kick reason - SendPacket(&data); -} - -void WorldSession::SendLfgUpdateProposal(uint32 proposalId, const LfgProposal* pProp) -{ - if (!pProp) - return; - - uint64 guid = GetPlayer()->GetGUID(); - LfgProposalPlayerMap::const_iterator itPlayer = pProp->players.find(guid); - if (itPlayer == pProp->players.end()) // Player MUST be in the proposal - return; - - LfgProposalPlayer* ppPlayer = itPlayer->second; - uint32 pLowGroupGuid = ppPlayer->groupLowGuid; - uint32 dLowGuid = pProp->groupLowGuid; - uint32 dungeonId = pProp->dungeonId; - bool isSameDungeon = false; - bool isContinue = false; - Group* grp = dLowGuid ? sGroupMgr->GetGroupByGUID(dLowGuid) : NULL; - uint32 completedEncounters = 0; - if (grp) - { - uint64 gguid = grp->GetGUID(); - isContinue = grp->isLFGGroup() && sLFGMgr->GetState(gguid) != LFG_STATE_FINISHED_DUNGEON; - isSameDungeon = GetPlayer()->GetGroup() == grp && isContinue; - } - - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_PROPOSAL_UPDATE [" UI64FMTD "] state: %u", GetPlayer()->GetGUID(), pProp->state); - WorldPacket data(SMSG_LFG_PROPOSAL_UPDATE, 4 + 1 + 4 + 4 + 1 + 1 + pProp->players.size() * (4 + 1 + 1 + 1 + 1 +1)); - - if (!isContinue) // Only show proposal dungeon if it's continue - { - LfgDungeonSet playerDungeons = sLFGMgr->GetSelectedDungeons(guid); - if (playerDungeons.size() == 1) - dungeonId = (*playerDungeons.begin()); - } - - if (LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(dungeonId)) - { - dungeonId = dungeon->Entry(); - - // Select a player inside to be get completed encounters from - if (grp) - { - for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* groupMember = itr->getSource(); - if (groupMember && groupMember->GetMapId() == uint32(dungeon->map)) - { - if (InstanceScript* instance = groupMember->GetInstanceScript()) - completedEncounters = instance->GetCompletedEncounterMask(); - break; - } - } - } - } - - data << uint32(dungeonId); // Dungeon - data << uint8(pProp->state); // Result state - data << uint32(proposalId); // Internal Proposal ID - data << uint32(completedEncounters); // Bosses killed - data << uint8(isSameDungeon); // Silent (show client window) - data << uint8(pProp->players.size()); // Group size - - for (itPlayer = pProp->players.begin(); itPlayer != pProp->players.end(); ++itPlayer) - { - ppPlayer = itPlayer->second; - data << uint32(ppPlayer->role); // Role - data << uint8(itPlayer->first == guid); // Self player - if (!ppPlayer->groupLowGuid) // Player not it a group - { - data << uint8(0); // Not in dungeon - data << uint8(0); // Not same group - } - else - { - data << uint8(ppPlayer->groupLowGuid == dLowGuid); // In dungeon (silent) - data << uint8(ppPlayer->groupLowGuid == pLowGroupGuid); // Same Group than player - } - data << uint8(ppPlayer->accept != LFG_ANSWER_PENDING); // Answered - data << uint8(ppPlayer->accept == LFG_ANSWER_AGREE); // Accepted - } - SendPacket(&data); -} - -void WorldSession::SendLfgUpdateSearch(bool update) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_UPDATE_SEARCH [" UI64FMTD "] update: %u", GetPlayer()->GetGUID(), update ? 1 : 0); - WorldPacket data(SMSG_LFG_UPDATE_SEARCH, 1); - data << uint8(update); // In Lfg Queue? - SendPacket(&data); -} - -void WorldSession::SendLfgDisabled() -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_DISABLED [" UI64FMTD "]", GetPlayer()->GetGUID()); - WorldPacket data(SMSG_LFG_DISABLED, 0); - SendPacket(&data); -} - -void WorldSession::SendLfgOfferContinue(uint32 dungeonEntry) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_OFFER_CONTINUE [" UI64FMTD "] dungeon entry: %u", GetPlayer()->GetGUID(), dungeonEntry); - WorldPacket data(SMSG_LFG_OFFER_CONTINUE, 4); - data << uint32(dungeonEntry); - SendPacket(&data); -} - -void WorldSession::SendLfgTeleportError(uint8 err) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_TELEPORT_DENIED [" UI64FMTD "] reason: %u", GetPlayer()->GetGUID(), err); - WorldPacket data(SMSG_LFG_TELEPORT_DENIED, 4); - data << uint32(err); // Error - SendPacket(&data); -} - -/* -void WorldSession::SendLfrUpdateListOpcode(uint32 dungeonEntry) -{ - sLog->outDebug(LOG_FILTER_PACKETIO, "SMSG_UPDATE_LFG_LIST [" UI64FMTD "] dungeon entry: %u", GetPlayer()->GetGUID(), dungeonEntry); - WorldPacket data(SMSG_UPDATE_LFG_LIST); - SendPacket(&data); -} -*/ diff --git a/src/server/game/Server/Protocol/Handlers/LootHandler.cpp b/src/server/game/Server/Protocol/Handlers/LootHandler.cpp deleted file mode 100755 index 6508f08dc22..00000000000 --- a/src/server/game/Server/Protocol/Handlers/LootHandler.cpp +++ /dev/null @@ -1,508 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "WorldPacket.h" -#include "Log.h" -#include "Corpse.h" -#include "GameObject.h" -#include "Player.h" -#include "ObjectAccessor.h" -#include "WorldSession.h" -#include "LootMgr.h" -#include "Object.h" -#include "Group.h" -#include "World.h" -#include "Util.h" - -void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_AUTOSTORE_LOOT_ITEM"); - Player* player = GetPlayer(); - uint64 lguid = player->GetLootGUID(); - Loot* loot = NULL; - uint8 lootSlot = 0; - - recv_data >> lootSlot; - - if (IS_GAMEOBJECT_GUID(lguid)) - { - GameObject* go = player->GetMap()->GetGameObject(lguid); - - // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO - if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player, INTERACTION_DISTANCE))) - { - player->SendLootRelease(lguid); - return; - } - - loot = &go->loot; - } - else if (IS_ITEM_GUID(lguid)) - { - Item* pItem = player->GetItemByGuid(lguid); - - if (!pItem) - { - player->SendLootRelease(lguid); - return; - } - - loot = &pItem->loot; - } - else if (IS_CORPSE_GUID(lguid)) - { - Corpse* bones = ObjectAccessor::GetCorpse(*player, lguid); - if (!bones) - { - player->SendLootRelease(lguid); - return; - } - - loot = &bones->loot; - } - else - { - Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid); - - bool ok_loot = creature && creature->isAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed); - - if (!ok_loot || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) - { - player->SendLootRelease(lguid); - return; - } - - loot = &creature->loot; - } - - player->StoreLootItem(lootSlot, loot); -} - -void WorldSession::HandleLootMoneyOpcode(WorldPacket & /*recv_data*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_LOOT_MONEY"); - - Player* player = GetPlayer(); - uint64 guid = player->GetLootGUID(); - if (!guid) - return; - - Loot* loot = NULL; - bool shareMoney = true; - - switch (GUID_HIPART(guid)) - { - case HIGHGUID_GAMEOBJECT: - { - GameObject* go = GetPlayer()->GetMap()->GetGameObject(guid); - - // do not check distance for GO if player is the owner of it (ex. fishing bobber) - if (go && ((go->GetOwnerGUID() == player->GetGUID() || go->IsWithinDistInMap(player, INTERACTION_DISTANCE)))) - loot = &go->loot; - - break; - } - case HIGHGUID_CORPSE: // remove insignia ONLY in BG - { - Corpse* bones = ObjectAccessor::GetCorpse(*player, guid); - - if (bones && bones->IsWithinDistInMap(player, INTERACTION_DISTANCE)) - { - loot = &bones->loot; - shareMoney = false; - } - - break; - } - case HIGHGUID_ITEM: - { - if (Item* item = player->GetItemByGuid(guid)) - { - loot = &item->loot; - shareMoney = false; - } - break; - } - case HIGHGUID_UNIT: - case HIGHGUID_VEHICLE: - { - Creature* creature = player->GetMap()->GetCreature(guid); - bool lootAllowed = creature && creature->isAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed); - if (lootAllowed && creature->IsWithinDistInMap(player, INTERACTION_DISTANCE)) - { - loot = &creature->loot; - if (creature->isAlive()) - shareMoney = false; - } - break; - } - default: - return; // unlootable type - } - - if (loot) - { - loot->NotifyMoneyRemoved(); - if (shareMoney && player->GetGroup()) //item, pickpocket and players can be looted only single player - { - Group* group = player->GetGroup(); - - std::vector playersNear; - for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* member = itr->getSource(); - if (!member) - continue; - - if (player->IsWithinDistInMap(member, sWorld->getFloatConfig(CONFIG_GROUP_XP_DISTANCE), false)) - playersNear.push_back(member); - } - - uint32 goldPerPlayer = uint32((loot->gold) / (playersNear.size())); - - for (std::vector::const_iterator i = playersNear.begin(); i != playersNear.end(); ++i) - { - (*i)->ModifyMoney(goldPerPlayer); - (*i)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, goldPerPlayer); - - WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4 + 1); - data << uint32(goldPerPlayer); - data << uint8(playersNear.size() > 1 ? 0 : 1); // Controls the text displayed in chat. 0 is "Your share is..." and 1 is "You loot..." - (*i)->GetSession()->SendPacket(&data); - } - } - else - { - player->ModifyMoney(loot->gold); - player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, loot->gold); - - WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4 + 1); - data << uint32(loot->gold); - data << uint8(1); // "You loot..." - SendPacket(&data); - } - - loot->gold = 0; - } -} - -void WorldSession::HandleLootOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_LOOT"); - - uint64 guid; - recv_data >> guid; - - // Check possible cheat - if (!_player->isAlive()) - return; - - GetPlayer()->SendLoot(guid, LOOT_CORPSE); - - // interrupt cast - if (GetPlayer()->IsNonMeleeSpellCasted(false)) - GetPlayer()->InterruptNonMeleeSpells(false); -} - -void WorldSession::HandleLootReleaseOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_LOOT_RELEASE"); - - // cheaters can modify lguid to prevent correct apply loot release code and re-loot - // use internal stored guid - recv_data.read_skip(); // guid; - - if (uint64 lguid = GetPlayer()->GetLootGUID()) - DoLootRelease(lguid); -} - -void WorldSession::DoLootRelease(uint64 lguid) -{ - Player *player = GetPlayer(); - Loot *loot; - - player->SetLootGUID(0); - player->SendLootRelease(lguid); - - player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); - - if (!player->IsInWorld()) - return; - - if (IS_GAMEOBJECT_GUID(lguid)) - { - GameObject* go = GetPlayer()->GetMap()->GetGameObject(lguid); - - // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO - if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player, INTERACTION_DISTANCE))) - return; - - loot = &go->loot; - - if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR) - { - // locked doors are opened with spelleffect openlock, prevent remove its as looted - go->UseDoorOrButton(); - } - else if (loot->isLooted() || go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE) - { - // GO is mineral vein? so it is not removed after its looted - if (go->GetGoType() == GAMEOBJECT_TYPE_CHEST) - { - uint32 go_min = go->GetGOInfo()->chest.minSuccessOpens; - uint32 go_max = go->GetGOInfo()->chest.maxSuccessOpens; - - // only vein pass this check - if (go_min != 0 && go_max > go_min) - { - float amount_rate = sWorld->getRate(RATE_MINING_AMOUNT); - float min_amount = go_min*amount_rate; - float max_amount = go_max*amount_rate; - - go->AddUse(); - float uses = float(go->GetUseCount()); - - if (uses < max_amount) - { - if (uses >= min_amount) - { - float chance_rate = sWorld->getRate(RATE_MINING_NEXT); - - int32 ReqValue = 175; - LockEntry const* lockInfo = sLockStore.LookupEntry(go->GetGOInfo()->chest.lockId); - if (lockInfo) - ReqValue = lockInfo->Skill[0]; - float skill = float(player->GetSkillValue(SKILL_MINING))/(ReqValue+25); - double chance = pow(0.8*chance_rate, 4*(1/double(max_amount))*double(uses)); - if (roll_chance_f((float)(100*chance+skill))) - { - go->SetLootState(GO_READY); - } - else // not have more uses - go->SetLootState(GO_JUST_DEACTIVATED); - } - else // 100% chance until min uses - go->SetLootState(GO_READY); - } - else // max uses already - go->SetLootState(GO_JUST_DEACTIVATED); - } - else // not vein - go->SetLootState(GO_JUST_DEACTIVATED); - } - else if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGHOLE) - { // The fishing hole used once more - go->AddUse(); // if the max usage is reached, will be despawned in next tick - if (go->GetUseCount() >= urand(go->GetGOInfo()->fishinghole.minSuccessOpens, go->GetGOInfo()->fishinghole.maxSuccessOpens)) - { - go->SetLootState(GO_JUST_DEACTIVATED); - } - else - go->SetLootState(GO_READY); - } - else // not chest (or vein/herb/etc) - go->SetLootState(GO_JUST_DEACTIVATED); - - loot->clear(); - } - else - { - // not fully looted object - go->SetLootState(GO_ACTIVATED, player); - - // if the round robin player release, reset it. - if (player->GetGUID() == loot->roundRobinPlayer) - { - if (Group* group = player->GetGroup()) - { - if (group->GetLootMethod() != MASTER_LOOT) - { - loot->roundRobinPlayer = 0; - } - } - else - loot->roundRobinPlayer = 0; - } - } - } - else if (IS_CORPSE_GUID(lguid)) // ONLY remove insignia at BG - { - Corpse* corpse = ObjectAccessor::GetCorpse(*player, lguid); - if (!corpse || !corpse->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) - return; - - loot = &corpse->loot; - - if (loot->isLooted()) - { - loot->clear(); - corpse->RemoveFlag(CORPSE_FIELD_DYNAMIC_FLAGS, CORPSE_DYNFLAG_LOOTABLE); - } - } - else if (IS_ITEM_GUID(lguid)) - { - Item* pItem = player->GetItemByGuid(lguid); - if (!pItem) - return; - - ItemTemplate const* proto = pItem->GetTemplate(); - - // destroy only 5 items from stack in case prospecting and milling - if (proto->Flags & (ITEM_PROTO_FLAG_PROSPECTABLE | ITEM_PROTO_FLAG_MILLABLE)) - { - pItem->m_lootGenerated = false; - pItem->loot.clear(); - - uint32 count = pItem->GetCount(); - - // >=5 checked in spell code, but will work for cheating cases also with removing from another stacks. - if (count > 5) - count = 5; - - player->DestroyItemCount(pItem, count, true); - } - else - // FIXME: item must not be deleted in case not fully looted state. But this pre-request implement loot saving in DB at item save. Or cheating possible. - player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); - return; // item can be looted only single player - } - else - { - Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid); - - bool ok_loot = creature && creature->isAlive() == (player->getClass() == CLASS_ROGUE && creature->lootForPickPocketed); - if (!ok_loot || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) - return; - - loot = &creature->loot; - if (loot->isLooted()) - { - // skip pickpocketing loot for speed, skinning timer reduction is no-op in fact - if (!creature->isAlive()) - creature->AllLootRemovedFromCorpse(); - - creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); - loot->clear(); - } - else - { - // if the round robin player release, reset it. - if (player->GetGUID() == loot->roundRobinPlayer) - { - if (Group* group = player->GetGroup()) - { - if (group->GetLootMethod() != MASTER_LOOT) - { - loot->roundRobinPlayer = 0; - group->SendLooter(creature, NULL); - - // force update of dynamic flags, otherwise other group's players still not able to loot. - creature->ForceValuesUpdateAtIndex(UNIT_DYNAMIC_FLAGS); - } - } - else - loot->roundRobinPlayer = 0; - } - } - } - - //Player is not looking at loot list, he doesn't need to see updates on the loot list - loot->RemoveLooter(player->GetGUID()); -} - -void WorldSession::HandleLootMasterGiveOpcode(WorldPacket & recv_data) -{ - uint8 slotid; - uint64 lootguid, target_playerguid; - - recv_data >> lootguid >> slotid >> target_playerguid; - - if (!_player->GetGroup() || _player->GetGroup()->GetLooterGuid() != _player->GetGUID()) - { - _player->SendLootRelease(GetPlayer()->GetLootGUID()); - return; - } - - Player* target = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(target_playerguid, 0, HIGHGUID_PLAYER)); - if (!target) - return; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WorldSession::HandleLootMasterGiveOpcode (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = [%s].", target->GetName()); - - if (_player->GetLootGUID() != lootguid) - return; - - Loot* pLoot = NULL; - - if (IS_CRE_OR_VEH_GUID(GetPlayer()->GetLootGUID())) - { - Creature* creature = GetPlayer()->GetMap()->GetCreature(lootguid); - if (!creature) - return; - - pLoot = &creature->loot; - } - else if (IS_GAMEOBJECT_GUID(GetPlayer()->GetLootGUID())) - { - GameObject* pGO = GetPlayer()->GetMap()->GetGameObject(lootguid); - if (!pGO) - return; - - pLoot = &pGO->loot; - } - - if (!pLoot) - return; - - if (slotid > pLoot->items.size()) - { - sLog->outDebug(LOG_FILTER_LOOT, "MasterLootItem: Player %s might be using a hack! (slot %d, size %lu)", GetPlayer()->GetName(), slotid, (unsigned long)pLoot->items.size()); - return; - } - - LootItem& item = pLoot->items[slotid]; - - ItemPosCountVec dest; - InventoryResult msg = target->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.itemid, item.count); - if (msg != EQUIP_ERR_OK) - { - target->SendEquipError(msg, NULL, NULL, item.itemid); - // send duplicate of error massage to master looter - _player->SendEquipError(msg, NULL, NULL, item.itemid); - return; - } - - // list of players allowed to receive this item in trade - AllowedLooterSet looters = item.GetAllowedLooters(); - - // not move item from loot to target inventory - Item* newitem = target->StoreNewItem(dest, item.itemid, true, item.randomPropertyId, looters); - target->SendNewItem(newitem, uint32(item.count), false, false, true); - target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item.itemid, item.count); - target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, pLoot->loot_type, item.count); - target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item.itemid, item.count); - - // mark as looted - item.count=0; - item.is_looted=true; - - pLoot->NotifyItemRemoved(slotid); - --pLoot->unlootedCount; -} - diff --git a/src/server/game/Server/Protocol/Handlers/MailHandler.cpp b/src/server/game/Server/Protocol/Handlers/MailHandler.cpp deleted file mode 100755 index a8522bb2582..00000000000 --- a/src/server/game/Server/Protocol/Handlers/MailHandler.cpp +++ /dev/null @@ -1,773 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "DatabaseEnv.h" -#include "Mail.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Opcodes.h" -#include "Log.h" -#include "World.h" -#include "ObjectMgr.h" -#include "Player.h" -#include "Language.h" -#include "DBCStores.h" -#include "Item.h" -#include "AccountMgr.h" - -void WorldSession::HandleSendMail(WorldPacket & recv_data) -{ - uint64 mailbox, unk3; - std::string receiver, subject, body; - uint32 unk1, unk2, money, COD; - uint8 unk4; - recv_data >> mailbox; - recv_data >> receiver; - - recv_data >> subject; - - recv_data >> body; - - recv_data >> unk1; // stationery? - recv_data >> unk2; // 0x00000000 - - uint8 items_count; - recv_data >> items_count; // attached items count - - if (items_count > MAX_MAIL_ITEMS) // client limit - { - GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_TOO_MANY_ATTACHMENTS); - recv_data.rfinish(); // set to end to avoid warnings spam - return; - } - - uint64 itemGUIDs[MAX_MAIL_ITEMS]; - - for (uint8 i = 0; i < items_count; ++i) - { - recv_data.read_skip(); // item slot in mail, not used - recv_data >> itemGUIDs[i]; - } - - recv_data >> money >> COD; // money and cod - recv_data >> unk3; // const 0 - recv_data >> unk4; // const 0 - - // packet read complete, now do check - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) - return; - - if (receiver.empty()) - return; - - Player* player = _player; - - if (player->getLevel() < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)) - { - SendNotification(GetTrinityString(LANG_MAIL_SENDER_REQ), sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)); - return; - } - - uint64 rc = 0; - if (normalizePlayerName(receiver)) - rc = sObjectMgr->GetPlayerGUIDByName(receiver); - - if (!rc) - { - sLog->outDetail("Player %u is sending mail to %s (GUID: not existed!) with subject %s and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", - player->GetGUIDLow(), receiver.c_str(), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); - player->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_NOT_FOUND); - return; - } - - sLog->outDetail("Player %u is sending mail to %s (GUID: %u) with subject %s and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", player->GetGUIDLow(), receiver.c_str(), GUID_LOPART(rc), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); - - if (player->GetGUID() == rc) - { - player->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANNOT_SEND_TO_SELF); - return; - } - - uint32 cost = items_count ? 30 * items_count : 30; // price hardcoded in client - - uint32 reqmoney = cost + money; - - if (!player->HasEnoughMoney(reqmoney)) - { - player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY); - return; - } - - Player* receive = ObjectAccessor::FindPlayer(rc); - - uint32 rc_team = 0; - uint8 mails_count = 0; //do not allow to send to one player more than 100 mails - uint8 receiveLevel = 0; - - if (receive) - { - rc_team = receive->GetTeam(); - mails_count = receive->GetMailSize(); - receiveLevel = receive->getLevel(); - } - else - { - rc_team = sObjectMgr->GetPlayerTeamByGUID(rc); - if (QueryResult result = CharacterDatabase.PQuery("SELECT COUNT(*) FROM mail WHERE receiver = '%u'", GUID_LOPART(rc))) - { - Field* fields = result->Fetch(); - mails_count = fields[0].GetUInt32(); - } - if (QueryResult result = CharacterDatabase.PQuery("SELECT level FROM characters WHERE guid = '%u'", GUID_LOPART(rc))) - { - Field* fields = result->Fetch(); - receiveLevel = fields[0].GetUInt8(); - } - } - //do not allow to have more than 100 mails in mailbox.. mails count is in opcode uint8!!! - so max can be 255.. - if (mails_count > 100) - { - player->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_CAP_REACHED); - return; - } - // test the receiver's Faction... or all items are account bound - bool accountBound = items_count ? true : false; - for (uint8 i = 0; i < items_count; ++i) - { - Item* item = player->GetItemByGuid(itemGUIDs[i]); - if (item) - { - ItemTemplate const* itemProto = item->GetTemplate(); - if (!itemProto || !(itemProto->Flags & ITEM_PROTO_FLAG_BIND_TO_ACCOUNT)) - { - accountBound = false; - break; - } - } - } - - if (!accountBound && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL) && player->GetTeam() != rc_team && AccountMgr::IsPlayerAccount(GetSecurity())) - { - player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_YOUR_TEAM); - return; - } - - if (receiveLevel < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)) - { - SendNotification(GetTrinityString(LANG_MAIL_RECEIVER_REQ), sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)); - return; - } - - uint32 rc_account = receive - ? receive->GetSession()->GetAccountId() - : sObjectMgr->GetPlayerAccountIdByGUID(rc); - - Item* items[MAX_MAIL_ITEMS]; - - for (uint8 i = 0; i < items_count; ++i) - { - if (!itemGUIDs[i]) - { - player->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); - return; - } - - Item* item = player->GetItemByGuid(itemGUIDs[i]); - - // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail) - if (!item) - { - player->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); - return; - } - - if (!item->CanBeTraded(true)) - { - player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); - return; - } - - if (item->IsBoundAccountWide() && item->IsSoulBound() && player->GetSession()->GetAccountId() != rc_account) - { - player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_ARTEFACTS_ONLY_FOR_OWN_CHARACTERS); - return; - } - - if (item->GetTemplate()->Flags & ITEM_PROTO_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION)) - { - player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); - return; - } - - if (COD && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) - { - player->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD); - return; - } - - if (item->IsNotEmptyBag()) - { - player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS); - return; - } - - items[i] = item; - } - - player->SendMailResult(0, MAIL_SEND, MAIL_OK); - - player->ModifyMoney(-int32(reqmoney)); - player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL, cost); - - bool needItemDelay = false; - - MailDraft draft(subject, body); - - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - - if (items_count > 0 || money > 0) - { - if (items_count > 0) - { - for (uint8 i = 0; i < items_count; ++i) - { - Item* item = items[i]; - if (!AccountMgr::IsPlayerAccount(GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) - { - sLog->outCommand(GetAccountId(), "GM %s (Account: %u) mail item: %s (Entry: %u Count: %u) to player: %s (Account: %u)", - GetPlayerName(), GetAccountId(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount(), receiver.c_str(), rc_account); - } - - item->SetNotRefundable(GetPlayer()); // makes the item no longer refundable - player->MoveItemFromInventory(items[i]->GetBagSlot(), item->GetSlot(), true); - - item->DeleteFromInventoryDB(trans); // deletes item from character's inventory - item->SetOwnerGUID(rc); - item->SaveToDB(trans); // recursive and not have transaction guard into self, item not in inventory and can be save standalone - - draft.AddItem(item); - } - - // if item send to character at another account, then apply item delivery delay - needItemDelay = player->GetSession()->GetAccountId() != rc_account; - } - - if (money > 0 && !AccountMgr::IsPlayerAccount(GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) - { - sLog->outCommand(GetAccountId(), "GM %s (Account: %u) mail money: %u to player: %s (Account: %u)", - GetPlayerName(), GetAccountId(), money, receiver.c_str(), rc_account); - } - } - - // If theres is an item, there is a one hour delivery delay if sent to another account's character. - uint32 deliver_delay = needItemDelay ? sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY) : 0; - - // will delete item or place to receiver mail list - draft - .AddMoney(money) - .AddCOD(COD) - .SendMailTo(trans, MailReceiver(receive, GUID_LOPART(rc)), MailSender(player), body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay); - - player->SaveInventoryAndGoldToDB(trans); - CharacterDatabase.CommitTransaction(trans); -} - -//called when mail is read -void WorldSession::HandleMailMarkAsRead(WorldPacket & recv_data) -{ - uint64 mailbox; - uint32 mailId; - recv_data >> mailbox; - recv_data >> mailId; - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) - return; - - Player* player = _player; - Mail* m = player->GetMail(mailId); - if (m) - { - if (player->unReadMails) - --player->unReadMails; - m->checked = m->checked | MAIL_CHECK_MASK_READ; - player->m_mailsUpdated = true; - m->state = MAIL_STATE_CHANGED; - } -} - -//called when client deletes mail -void WorldSession::HandleMailDelete(WorldPacket & recv_data) -{ - uint64 mailbox; - uint32 mailId; - recv_data >> mailbox; - recv_data >> mailId; - recv_data.read_skip(); // mailTemplateId - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) - return; - - Mail* m = _player->GetMail(mailId); - Player* player = _player; - player->m_mailsUpdated = true; - if (m) - { - // delete shouldn't show up for COD mails - if (m->COD) - { - player->SendMailResult(mailId, MAIL_DELETED, MAIL_ERR_INTERNAL_ERROR); - return; - } - - m->state = MAIL_STATE_DELETED; - } - player->SendMailResult(mailId, MAIL_DELETED, MAIL_OK); -} - -void WorldSession::HandleMailReturnToSender(WorldPacket & recv_data) -{ - uint64 mailbox; - uint32 mailId; - recv_data >> mailbox; - recv_data >> mailId; - recv_data.read_skip(); // original sender GUID for return to, not used - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) - return; - - Player* player = _player; - Mail* m = player->GetMail(mailId); - if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) - { - player->SendMailResult(mailId, MAIL_RETURNED_TO_SENDER, MAIL_ERR_INTERNAL_ERROR); - return; - } - //we can return mail now - //so firstly delete the old one - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - trans->PAppend("DELETE FROM mail WHERE id = '%u'", mailId); // needed? - trans->PAppend("DELETE FROM mail_items WHERE mail_id = '%u'", mailId); - player->RemoveMail(mailId); - - // only return mail if the player exists (and delete if not existing) - if (m->messageType == MAIL_NORMAL && m->sender) - { - MailDraft draft(m->subject, m->body); - if (m->mailTemplateId) - draft = MailDraft(m->mailTemplateId, false); // items already included - - if (m->HasItems()) - { - for (MailItemInfoVec::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2) - { - Item* item = player->GetMItem(itr2->item_guid); - if (item) - draft.AddItem(item); - else - { - //WTF? - } - - player->RemoveMItem(itr2->item_guid); - } - } - draft.AddMoney(m->money).SendReturnToSender(GetAccountId(), m->receiver, m->sender, trans); - } - - CharacterDatabase.CommitTransaction(trans); - - delete m; //we can deallocate old mail - player->SendMailResult(mailId, MAIL_RETURNED_TO_SENDER, MAIL_OK); -} - -//called when player takes item attached in mail -void WorldSession::HandleMailTakeItem(WorldPacket & recv_data) -{ - uint64 mailbox; - uint32 mailId; - uint32 itemId; - recv_data >> mailbox; - recv_data >> mailId; - recv_data >> itemId; // item guid low - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) - return; - - Player* player = _player; - - Mail* m = player->GetMail(mailId); - if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) - { - player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR); - return; - } - - // prevent cheating with skip client money check - if (!player->HasEnoughMoney(m->COD)) - { - player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_NOT_ENOUGH_MONEY); - return; - } - - Item* it = player->GetMItem(itemId); - - ItemPosCountVec dest; - uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, it, false); - if (msg == EQUIP_ERR_OK) - { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - m->RemoveItem(itemId); - m->removedItems.push_back(itemId); - - if (m->COD > 0) //if there is COD, take COD money from player and send them to sender by mail - { - uint64 sender_guid = MAKE_NEW_GUID(m->sender, 0, HIGHGUID_PLAYER); - Player* receive = ObjectAccessor::FindPlayer(sender_guid); - - uint32 sender_accId = 0; - - if (!AccountMgr::IsPlayerAccount(GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) - { - std::string sender_name; - if (receive) - { - sender_accId = receive->GetSession()->GetAccountId(); - sender_name = receive->GetName(); - } - else - { - // can be calculated early - sender_accId = sObjectMgr->GetPlayerAccountIdByGUID(sender_guid); - - if (!sObjectMgr->GetPlayerNameByGUID(sender_guid, sender_name)) - sender_name = sObjectMgr->GetTrinityStringForDBCLocale(LANG_UNKNOWN); - } - sLog->outCommand(GetAccountId(), "GM %s (Account: %u) receive mail item: %s (Entry: %u Count: %u) and send COD money: %u to player: %s (Account: %u)", - GetPlayerName(), GetAccountId(), it->GetTemplate()->Name1.c_str(), it->GetEntry(), it->GetCount(), m->COD, sender_name.c_str(), sender_accId); - } - else if (!receive) - sender_accId = sObjectMgr->GetPlayerAccountIdByGUID(sender_guid); - - // check player existence - if (receive || sender_accId) - { - MailDraft(m->subject, "") - .AddMoney(m->COD) - .SendMailTo(trans, MailReceiver(receive, m->sender), MailSender(MAIL_NORMAL, m->receiver), MAIL_CHECK_MASK_COD_PAYMENT); - } - - player->ModifyMoney(-int32(m->COD)); - } - m->COD = 0; - m->state = MAIL_STATE_CHANGED; - player->m_mailsUpdated = true; - player->RemoveMItem(it->GetGUIDLow()); - - uint32 count = it->GetCount(); // save counts before store and possible merge with deleting - player->MoveItemToInventory(dest, it, true); - - player->SaveInventoryAndGoldToDB(trans); - player->_SaveMail(trans); - CharacterDatabase.CommitTransaction(trans); - - player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_OK, 0, itemId, count); - } - else - player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_EQUIP_ERROR, msg); -} - -void WorldSession::HandleMailTakeMoney(WorldPacket & recv_data) -{ - uint64 mailbox; - uint32 mailId; - recv_data >> mailbox; - recv_data >> mailId; - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) - return; - - Player* player = _player; - - Mail* m = player->GetMail(mailId); - if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) - { - player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_ERR_INTERNAL_ERROR); - return; - } - - player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_OK); - - player->ModifyMoney(m->money); - m->money = 0; - m->state = MAIL_STATE_CHANGED; - player->m_mailsUpdated = true; - - // save money and mail to prevent cheating - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - player->SaveGoldToDB(trans); - player->_SaveMail(trans); - CharacterDatabase.CommitTransaction(trans); -} - -//called when player lists his received mails -void WorldSession::HandleGetMailList(WorldPacket & recv_data) -{ - uint64 mailbox; - recv_data >> mailbox; - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) - return; - - Player* player = _player; - - //load players mails, and mailed items - if (!player->m_mailsLoaded) - player ->_LoadMail(); - - // client can't work with packets > max int16 value - const uint32 maxPacketSize = 32767; - - uint32 mailsCount = 0; // real send to client mails amount - uint32 realCount = 0; // real mails amount - - WorldPacket data(SMSG_MAIL_LIST_RESULT, (200)); // guess size - data << uint32(0); // real mail's count - data << uint8(0); // mail's count - time_t cur_time = time(NULL); - - for (PlayerMails::iterator itr = player->GetMailBegin(); itr != player->GetMailEnd(); ++itr) - { - // packet send mail count as uint8, prevent overflow - if (mailsCount >= 254) - { - realCount += 1; - continue; - } - - // skip deleted or not delivered (deliver delay not expired) mails - if ((*itr)->state == MAIL_STATE_DELETED || cur_time < (*itr)->deliver_time) - continue; - - uint8 item_count = (*itr)->items.size(); // max count is MAX_MAIL_ITEMS (12) - - size_t next_mail_size = 2+4+1+((*itr)->messageType == MAIL_NORMAL ? 8 : 4)+4*8+((*itr)->subject.size()+1)+((*itr)->body.size()+1)+1+item_count*(1+4+4+7*3*4+4+4+4+4+4+4+1); - - if (data.wpos()+next_mail_size > maxPacketSize) - { - realCount += 1; - continue; - } - - data << uint16(next_mail_size); // Message size - data << uint32((*itr)->messageID); // Message ID - data << uint8((*itr)->messageType); // Message Type - - switch ((*itr)->messageType) - { - case MAIL_NORMAL: // sender guid - data << uint64(MAKE_NEW_GUID((*itr)->sender, 0, HIGHGUID_PLAYER)); - break; - case MAIL_CREATURE: - case MAIL_GAMEOBJECT: - case MAIL_AUCTION: - data << uint32((*itr)->sender); // creature/gameobject entry, auction id - break; - case MAIL_ITEM: // item entry (?) sender = "Unknown", NYI - data << uint32(0); // item entry - break; - } - - data << uint32((*itr)->COD); // COD - data << uint32(0); // probably changed in 3.3.3 - data << uint32((*itr)->stationery); // stationery (Stationery.dbc) - data << uint32((*itr)->money); // Gold - data << uint32((*itr)->checked); // flags - data << float(((*itr)->expire_time-time(NULL))/DAY); // Time - data << uint32((*itr)->mailTemplateId); // mail template (MailTemplate.dbc) - data << (*itr)->subject; // Subject string - once 00, when mail type = 3, max 256 - data << (*itr)->body; // message? max 8000 - data << uint8(item_count); // client limit is 0x10 - - for (uint8 i = 0; i < item_count; ++i) - { - Item* item = player->GetMItem((*itr)->items[i].item_guid); - // item index (0-6?) - data << uint8(i); - // item guid low? - data << uint32((item ? item->GetGUIDLow() : 0)); - // entry - data << uint32((item ? item->GetEntry() : 0)); - for (uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; ++j) - { - data << uint32((item ? item->GetEnchantmentId((EnchantmentSlot)j) : 0)); - data << uint32((item ? item->GetEnchantmentDuration((EnchantmentSlot)j) : 0)); - data << uint32((item ? item->GetEnchantmentCharges((EnchantmentSlot)j) : 0)); - } - // can be negative - data << int32((item ? item->GetItemRandomPropertyId() : 0)); - // unk - data << uint32((item ? item->GetItemSuffixFactor() : 0)); - // stack count - data << uint32((item ? item->GetCount() : 0)); - // charges - data << uint32((item ? item->GetSpellCharges() : 0)); - // durability - data << uint32((item ? item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY) : 0)); - // durability - data << uint32((item ? item->GetUInt32Value(ITEM_FIELD_DURABILITY) : 0)); - // unknown wotlk - data << uint8(0); - } - - realCount += 1; - mailsCount += 1; - } - - data.put(0, realCount); // this will display warning about undelivered mail to player if realCount > mailsCount - data.put(4, mailsCount); // set real send mails to client - SendPacket(&data); - - // recalculate m_nextMailDelivereTime and unReadMails - _player->UpdateNextMailTimeAndUnreads(); -} - -//used when player copies mail body to his inventory -void WorldSession::HandleMailCreateTextItem(WorldPacket & recv_data) -{ - uint64 mailbox; - uint32 mailId; - - recv_data >> mailbox; - recv_data >> mailId; - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) - return; - - Player* player = _player; - - Mail* m = player->GetMail(mailId); - if (!m || (m->body.empty() && !m->mailTemplateId) || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) - { - player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR); - return; - } - - Item* bodyItem = new Item; // This is not bag and then can be used new Item. - if (!bodyItem->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_ITEM), MAIL_BODY_ITEM_TEMPLATE, player)) - { - delete bodyItem; - return; - } - - // in mail template case we need create new item text - if (m->mailTemplateId) - { - MailTemplateEntry const* mailTemplateEntry = sMailTemplateStore.LookupEntry(m->mailTemplateId); - if (!mailTemplateEntry) - { - player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR); - return; - } - - bodyItem->SetText(mailTemplateEntry->content[GetSessionDbcLocale()]); - } - else - bodyItem->SetText(m->body); - - bodyItem->SetUInt32Value(ITEM_FIELD_CREATOR, m->sender); - bodyItem->SetFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_MAIL_TEXT_MASK); - - sLog->outDetail("HandleMailCreateTextItem mailid=%u", mailId); - - ItemPosCountVec dest; - uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, bodyItem, false); - if (msg == EQUIP_ERR_OK) - { - m->checked = m->checked | MAIL_CHECK_MASK_COPIED; - m->state = MAIL_STATE_CHANGED; - player->m_mailsUpdated = true; - - player->StoreItem(dest, bodyItem, true); - player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_OK); - } - else - { - player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_EQUIP_ERROR, msg); - delete bodyItem; - } -} - -//TODO Fix me! ... this void has probably bad condition, but good data are sent -void WorldSession::HandleQueryNextMailTime(WorldPacket & /*recv_data*/) -{ - WorldPacket data(MSG_QUERY_NEXT_MAIL_TIME, 8); - - if (!_player->m_mailsLoaded) - _player->_LoadMail(); - - if (_player->unReadMails > 0) - { - data << uint32(0); // float - data << uint32(0); // count - - uint32 count = 0; - time_t now = time(NULL); - for (PlayerMails::iterator itr = _player->GetMailBegin(); itr != _player->GetMailEnd(); ++itr) - { - Mail* m = (*itr); - // must be not checked yet - if (m->checked & MAIL_CHECK_MASK_READ) - continue; - - // and already delivered - if (now < m->deliver_time) - continue; - - if (m->messageType) - data << uint64(m->sender); // player guid - else - data << uint32(m->sender); // creature entry - - switch (m->messageType) - { - case MAIL_AUCTION: - data << uint32(2); - data << uint32(2); - data << uint32(m->stationery); - break; - default: - data << uint32(0); - data << uint32(0); - data << uint32(m->stationery); - break; - } - data << uint32(0xC6000000); // float unk, time or something - - ++count; - if (count == 2) // do not display more than 2 mails - break; - } - data.put(4, count); - } - else - { - data << uint32(0xC7A8C000); - data << uint32(0x00000000); - } - SendPacket(&data); -} diff --git a/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp b/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp deleted file mode 100755 index d1227c9b7d7..00000000000 --- a/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp +++ /dev/null @@ -1,1729 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "Language.h" -#include "DatabaseEnv.h" -#include "WorldPacket.h" -#include "Opcodes.h" -#include "Log.h" -#include "Player.h" -#include "GossipDef.h" -#include "World.h" -#include "ObjectMgr.h" -#include "GuildMgr.h" -#include "WorldSession.h" -#include "BigNumber.h" -#include "SHA1.h" -#include "UpdateData.h" -#include "LootMgr.h" -#include "Chat.h" -#include "zlib.h" -#include "ObjectAccessor.h" -#include "Object.h" -#include "Battleground.h" -#include "OutdoorPvP.h" -#include "Pet.h" -#include "SocialMgr.h" -#include "CellImpl.h" -#include "AccountMgr.h" -#include "Vehicle.h" -#include "CreatureAI.h" -#include "DBCEnums.h" -#include "ScriptMgr.h" -#include "MapManager.h" -#include "InstanceScript.h" -#include "GameObjectAI.h" -#include "Group.h" -#include "AccountMgr.h" - -void WorldSession::HandleRepopRequestOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_REPOP_REQUEST Message"); - - recv_data.read_skip(); - - if (GetPlayer()->isAlive() || GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) - return; - - if (GetPlayer()->HasAuraType(SPELL_AURA_PREVENT_RESURRECTION)) - return; // silently return, client should display the error by itself - - // the world update order is sessions, players, creatures - // the netcode runs in parallel with all of these - // creatures can kill players - // so if the server is lagging enough the player can - // release spirit after he's killed but before he is updated - if (GetPlayer()->getDeathState() == JUST_DIED) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "HandleRepopRequestOpcode: got request after player %s(%d) was killed and before he was updated", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow()); - GetPlayer()->KillPlayer(); - } - - //this is spirit release confirm? - GetPlayer()->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true); - GetPlayer()->BuildPlayerRepop(); - GetPlayer()->RepopAtGraveyard(); -} - -void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_GOSSIP_SELECT_OPTION"); - - uint32 gossipListId; - uint32 menuId; - uint64 guid; - std::string code = ""; - - recv_data >> guid >> menuId >> gossipListId; - - if (_player->PlayerTalkClass->IsGossipOptionCoded(gossipListId)) - recv_data >> code; - - Creature* unit = NULL; - GameObject* go = NULL; - if (IS_CRE_OR_VEH_GUID(guid)) - { - unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); - if (!unit) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleGossipSelectOptionOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); - return; - } - } - else if (IS_GAMEOBJECT_GUID(guid)) - { - go = _player->GetMap()->GetGameObject(guid); - if (!go) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleGossipSelectOptionOpcode - GameObject (GUID: %u) not found.", uint32(GUID_LOPART(guid))); - return; - } - } - else - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleGossipSelectOptionOpcode - unsupported GUID type for highguid %u. lowpart %u.", uint32(GUID_HIPART(guid)), uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - if ((unit && unit->GetCreatureInfo()->ScriptID != unit->LastUsedScriptID) || (go && go->GetGOInfo()->ScriptId != go->LastUsedScriptID)) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleGossipSelectOptionOpcode - Script reloaded while in use, ignoring and set new scipt id"); - if (unit) - unit->LastUsedScriptID = unit->GetCreatureInfo()->ScriptID; - if (go) - go->LastUsedScriptID = go->GetGOInfo()->ScriptId; - _player->PlayerTalkClass->SendCloseGossip(); - return; - } - if (!code.empty()) - { - if (unit) - { - unit->AI()->sGossipSelectCode(_player, menuId, gossipListId, code.c_str()); - if (!sScriptMgr->OnGossipSelectCode(_player, unit, _player->PlayerTalkClass->GetGossipOptionSender(gossipListId), _player->PlayerTalkClass->GetGossipOptionAction(gossipListId), code.c_str())) - _player->OnGossipSelect(unit, gossipListId, menuId); - } - else - { - go->AI()->GossipSelectCode(_player, menuId, gossipListId, code.c_str()); - sScriptMgr->OnGossipSelectCode(_player, go, _player->PlayerTalkClass->GetGossipOptionSender(gossipListId), _player->PlayerTalkClass->GetGossipOptionAction(gossipListId), code.c_str()); - } - } - else - { - if (unit) - { - unit->AI()->sGossipSelect(_player, menuId, gossipListId); - if (!sScriptMgr->OnGossipSelect(_player, unit, _player->PlayerTalkClass->GetGossipOptionSender(gossipListId), _player->PlayerTalkClass->GetGossipOptionAction(gossipListId))) - _player->OnGossipSelect(unit, gossipListId, menuId); - } - else - { - go->AI()->GossipSelect(_player, menuId, gossipListId); - if (!sScriptMgr->OnGossipSelect(_player, go, _player->PlayerTalkClass->GetGossipOptionSender(gossipListId), _player->PlayerTalkClass->GetGossipOptionAction(gossipListId))) - _player->OnGossipSelect(go, gossipListId, menuId); - } - } -} - -void WorldSession::HandleWhoOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_WHO Message"); - - time_t now = time(NULL); - if (now - timeLastWhoCommand < 5) - return; - else timeLastWhoCommand = now; - - uint32 matchcount = 0; - - uint32 level_min, level_max, racemask, classmask, zones_count, str_count; - uint32 zoneids[10]; // 10 is client limit - std::string player_name, guild_name; - - recv_data >> level_min; // maximal player level, default 0 - recv_data >> level_max; // minimal player level, default 100 (MAX_LEVEL) - recv_data >> player_name; // player name, case sensitive... - - recv_data >> guild_name; // guild name, case sensitive... - - recv_data >> racemask; // race mask - recv_data >> classmask; // class mask - recv_data >> zones_count; // zones count, client limit = 10 (2.0.10) - - if (zones_count > 10) - return; // can't be received from real client or broken packet - - for (uint32 i = 0; i < zones_count; ++i) - { - uint32 temp; - recv_data >> temp; // zone id, 0 if zone is unknown... - zoneids[i] = temp; - sLog->outDebug(LOG_FILTER_NETWORKIO, "Zone %u: %u", i, zoneids[i]); - } - - recv_data >> str_count; // user entered strings count, client limit=4 (checked on 2.0.10) - - if (str_count > 4) - return; // can't be received from real client or broken packet - - sLog->outDebug(LOG_FILTER_NETWORKIO, "Minlvl %u, maxlvl %u, name %s, guild %s, racemask %u, classmask %u, zones %u, strings %u", level_min, level_max, player_name.c_str(), guild_name.c_str(), racemask, classmask, zones_count, str_count); - - std::wstring str[4]; // 4 is client limit - for (uint32 i = 0; i < str_count; ++i) - { - std::string temp; - recv_data >> temp; // user entered string, it used as universal search pattern(guild+player name)? - - if (!Utf8toWStr(temp, str[i])) - continue; - - wstrToLower(str[i]); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "String %u: %s", i, temp.c_str()); - } - - std::wstring wplayer_name; - std::wstring wguild_name; - if (!(Utf8toWStr(player_name, wplayer_name) && Utf8toWStr(guild_name, wguild_name))) - return; - wstrToLower(wplayer_name); - wstrToLower(wguild_name); - - // client send in case not set max level value 100 but Trinity supports 255 max level, - // update it to show GMs with characters after 100 level - if (level_max >= MAX_LEVEL) - level_max = STRONG_MAX_LEVEL; - - uint32 team = _player->GetTeam(); - uint32 security = GetSecurity(); - bool allowTwoSideWhoList = sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST); - uint32 gmLevelInWhoList = sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST); - uint32 displaycount = 0; - - WorldPacket data(SMSG_WHO, 50); // guess size - data << uint32(matchcount); // placeholder, count of players matching criteria - data << uint32(displaycount); // placeholder, count of players displayed - - TRINITY_READ_GUARD(HashMapHolder::LockType, *HashMapHolder::GetLock()); - HashMapHolder::MapType const& m = sObjectAccessor->GetPlayers(); - for (HashMapHolder::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr) - { - if (AccountMgr::IsPlayerAccount(security)) - { - // player can see member of other team only if CONFIG_ALLOW_TWO_SIDE_WHO_LIST - if (itr->second->GetTeam() != team && !allowTwoSideWhoList) - continue; - - // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST - if ((itr->second->GetSession()->GetSecurity() > AccountTypes(gmLevelInWhoList))) - continue; - } - - //do not process players which are not in world - if (!(itr->second->IsInWorld())) - continue; - - // check if target is globally visible for player - if (!(itr->second->IsVisibleGloballyFor(_player))) - continue; - - // check if target's level is in level range - uint8 lvl = itr->second->getLevel(); - if (lvl < level_min || lvl > level_max) - continue; - - // check if class matches classmask - uint32 class_ = itr->second->getClass(); - if (!(classmask & (1 << class_))) - continue; - - // check if race matches racemask - uint32 race = itr->second->getRace(); - if (!(racemask & (1 << race))) - continue; - - uint32 pzoneid = itr->second->GetZoneId(); - uint8 gender = itr->second->getGender(); - - bool z_show = true; - for (uint32 i = 0; i < zones_count; ++i) - { - if (zoneids[i] == pzoneid) - { - z_show = true; - break; - } - - z_show = false; - } - if (!z_show) - continue; - - std::string pname = itr->second->GetName(); - std::wstring wpname; - if (!Utf8toWStr(pname, wpname)) - continue; - wstrToLower(wpname); - - if (!(wplayer_name.empty() || wpname.find(wplayer_name) != std::wstring::npos)) - continue; - - std::string gname = sGuildMgr->GetGuildNameById(itr->second->GetGuildId()); - std::wstring wgname; - if (!Utf8toWStr(gname, wgname)) - continue; - wstrToLower(wgname); - - if (!(wguild_name.empty() || wgname.find(wguild_name) != std::wstring::npos)) - continue; - - std::string aname; - if (AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(itr->second->GetZoneId())) - aname = areaEntry->area_name[GetSessionDbcLocale()]; - - bool s_show = true; - for (uint32 i = 0; i < str_count; ++i) - { - if (!str[i].empty()) - { - if (wgname.find(str[i]) != std::wstring::npos || - wpname.find(str[i]) != std::wstring::npos || - Utf8FitTo(aname, str[i])) - { - s_show = true; - break; - } - s_show = false; - } - } - if (!s_show) - continue; - - // 49 is maximum player count sent to client - can be overridden - // through config, but is unstable - if ((matchcount++) >= sWorld->getIntConfig(CONFIG_MAX_WHO)) - continue; - - data << pname; // player name - data << gname; // guild name - data << uint32(lvl); // player level - data << uint32(class_); // player class - data << uint32(race); // player race - data << uint8(gender); // player gender - data << uint32(pzoneid); // player zone id - - ++displaycount; - } - - data.put(0, displaycount); // insert right count, count displayed - data.put(4, matchcount); // insert right count, count of matches - - SendPacket(&data); - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Send SMSG_WHO Message"); -} - -void WorldSession::HandleLogoutRequestOpcode(WorldPacket & /*recv_data*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_LOGOUT_REQUEST Message, security - %u", GetSecurity()); - - if (uint64 lguid = GetPlayer()->GetLootGUID()) - DoLootRelease(lguid); - - uint8 reason = 0; - - if (GetPlayer()->isInCombat()) - reason = 1; - else if (GetPlayer()->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_JUMPING | MOVEMENTFLAG_FALLING)) - reason = 3; // is jumping or falling - else if (GetPlayer()->duel || GetPlayer()->HasAura(9454)) // is dueling or frozen by GM via freeze command - reason = 2; // FIXME - Need the correct value - - if (reason) - { - WorldPacket data(SMSG_LOGOUT_RESPONSE, 1+4); - data << uint8(reason); - data << uint32(0); - SendPacket(&data); - LogoutRequest(0); - return; - } - - //instant logout in taverns/cities or on taxi or for admins, gm's, mod's if its enabled in worldserver.conf - if (GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) || GetPlayer()->isInFlight() || - GetSecurity() >= AccountTypes(sWorld->getIntConfig(CONFIG_INSTANT_LOGOUT))) - { - WorldPacket data(SMSG_LOGOUT_RESPONSE, 1+4); - data << uint8(0); - data << uint32(16777216); - SendPacket(&data); - LogoutPlayer(true); - return; - } - - // not set flags if player can't free move to prevent lost state at logout cancel - if (GetPlayer()->CanFreeMove()) - { - GetPlayer()->SetStandState(UNIT_STAND_STATE_SIT); - - WorldPacket data(SMSG_FORCE_MOVE_ROOT, (8+4)); // guess size - data.append(GetPlayer()->GetPackGUID()); - data << (uint32)2; - SendPacket(&data); - GetPlayer()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); - } - - WorldPacket data(SMSG_LOGOUT_RESPONSE, 1+4); - data << uint8(0); - data << uint32(0); - SendPacket(&data); - LogoutRequest(time(NULL)); -} - -void WorldSession::HandlePlayerLogoutOpcode(WorldPacket & /*recv_data*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_PLAYER_LOGOUT Message"); -} - -void WorldSession::HandleLogoutCancelOpcode(WorldPacket & /*recv_data*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_LOGOUT_CANCEL Message"); - - LogoutRequest(0); - - WorldPacket data(SMSG_LOGOUT_CANCEL_ACK, 0); - SendPacket(&data); - - // not remove flags if can't free move - its not set in Logout request code. - if (GetPlayer()->CanFreeMove()) - { - //!we can move again - data.Initialize(SMSG_FORCE_MOVE_UNROOT, 8); // guess size - data.append(GetPlayer()->GetPackGUID()); - data << uint32(0); - SendPacket(&data); - - //! Stand Up - GetPlayer()->SetStandState(UNIT_STAND_STATE_STAND); - - //! DISABLE_ROTATE - GetPlayer()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); - } - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_LOGOUT_CANCEL_ACK Message"); -} - -void WorldSession::HandleTogglePvP(WorldPacket & recv_data) -{ - // this opcode can be used in two ways: Either set explicit new status or toggle old status - if (recv_data.size() == 1) - { - bool newPvPStatus; - recv_data >> newPvPStatus; - GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP, newPvPStatus); - GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER, !newPvPStatus); - } - else - { - GetPlayer()->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP); - GetPlayer()->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_PVP_TIMER); - } - - if (GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP)) - { - if (!GetPlayer()->IsPvP() || GetPlayer()->pvpInfo.endTimer != 0) - GetPlayer()->UpdatePvP(true, true); - } - else - { - if (!GetPlayer()->pvpInfo.inHostileArea && GetPlayer()->IsPvP()) - GetPlayer()->pvpInfo.endTimer = time(NULL); // start toggle-off - } - - //if (OutdoorPvP* pvp = _player->GetOutdoorPvP()) - // pvp->HandlePlayerActivityChanged(_player); -} - -void WorldSession::HandleZoneUpdateOpcode(WorldPacket & recv_data) -{ - uint32 newZone; - recv_data >> newZone; - - sLog->outDetail("WORLD: Recvd ZONE_UPDATE: %u", newZone); - - // use server size data - uint32 newzone, newarea; - GetPlayer()->GetZoneAndAreaId(newzone, newarea); - GetPlayer()->UpdateZone(newzone, newarea); - //GetPlayer()->SendInitWorldStates(true, newZone); -} - -void WorldSession::HandleSetSelectionOpcode(WorldPacket & recv_data) -{ - uint64 guid; - recv_data >> guid; - - _player->SetSelection(guid); -} - -void WorldSession::HandleStandStateChangeOpcode(WorldPacket & recv_data) -{ - // sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: Received CMSG_STANDSTATECHANGE"); -- too many spam in log at lags/debug stop - uint32 animstate; - recv_data >> animstate; - - _player->SetStandState(animstate); -} - -void WorldSession::HandleContactListOpcode(WorldPacket & recv_data) -{ - uint32 unk; - recv_data >> unk; - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_CONTACT_LIST - Unk: %d", unk); - _player->GetSocial()->SendSocialList(_player); -} - -void WorldSession::HandleAddFriendOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_ADD_FRIEND"); - - std::string friendName = GetTrinityString(LANG_FRIEND_IGNORE_UNKNOWN); - std::string friendNote; - - recv_data >> friendName; - - recv_data >> friendNote; - - if (!normalizePlayerName(friendName)) - return; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: %s asked to add friend : '%s'", GetPlayer()->GetName(), friendName.c_str()); - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUID_RACE_ACC_BY_NAME); - - stmt->setString(0, friendName); - - _addFriendCallback.SetParam(friendNote); - _addFriendCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); -} - -void WorldSession::HandleAddFriendOpcodeCallBack(PreparedQueryResult result, std::string friendNote) -{ - if (!GetPlayer()) - return; - - uint64 friendGuid; - uint32 friendAccountId; - uint32 team; - FriendsResult friendResult; - - friendResult = FRIEND_NOT_FOUND; - friendGuid = 0; - - if (result) - { - Field* fields = result->Fetch(); - - friendGuid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); - team = Player::TeamForRace(fields[1].GetUInt8()); - friendAccountId = fields[2].GetUInt32(); - - if (!AccountMgr::IsPlayerAccount(GetSecurity()) || sWorld->getBoolConfig(CONFIG_ALLOW_GM_FRIEND) || AccountMgr::IsPlayerAccount(AccountMgr::GetSecurity(friendAccountId, realmID))) - { - if (friendGuid) - { - if (friendGuid == GetPlayer()->GetGUID()) - friendResult = FRIEND_SELF; - else if (GetPlayer()->GetTeam() != team && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND) && AccountMgr::IsPlayerAccount(GetSecurity())) - friendResult = FRIEND_ENEMY; - else if (GetPlayer()->GetSocial()->HasFriend(GUID_LOPART(friendGuid))) - friendResult = FRIEND_ALREADY; - else - { - Player* pFriend = ObjectAccessor::FindPlayer(friendGuid); - if (pFriend && pFriend->IsInWorld() && pFriend->IsVisibleGloballyFor(GetPlayer())) - friendResult = FRIEND_ADDED_ONLINE; - else - friendResult = FRIEND_ADDED_OFFLINE; - if (!GetPlayer()->GetSocial()->AddToSocialList(GUID_LOPART(friendGuid), false)) - { - friendResult = FRIEND_LIST_FULL; - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: %s's friend list is full.", GetPlayer()->GetName()); - } - } - GetPlayer()->GetSocial()->SetFriendNote(GUID_LOPART(friendGuid), friendNote); - } - } - } - - sSocialMgr->SendFriendStatus(GetPlayer(), friendResult, GUID_LOPART(friendGuid), false); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent (SMSG_FRIEND_STATUS)"); -} - -void WorldSession::HandleDelFriendOpcode(WorldPacket & recv_data) -{ - uint64 FriendGUID; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_DEL_FRIEND"); - - recv_data >> FriendGUID; - - _player->GetSocial()->RemoveFromSocialList(GUID_LOPART(FriendGUID), false); - - sSocialMgr->SendFriendStatus(GetPlayer(), FRIEND_REMOVED, GUID_LOPART(FriendGUID), false); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent motd (SMSG_FRIEND_STATUS)"); -} - -void WorldSession::HandleAddIgnoreOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_ADD_IGNORE"); - - std::string ignoreName = GetTrinityString(LANG_FRIEND_IGNORE_UNKNOWN); - - recv_data >> ignoreName; - - if (!normalizePlayerName(ignoreName)) - return; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: %s asked to Ignore: '%s'", - GetPlayer()->GetName(), ignoreName.c_str()); - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUID_BY_NAME); - - stmt->setString(0, ignoreName); - - _addIgnoreCallback = CharacterDatabase.AsyncQuery(stmt); -} - -void WorldSession::HandleAddIgnoreOpcodeCallBack(PreparedQueryResult result) -{ - if (!GetPlayer()) - return; - - uint64 IgnoreGuid; - FriendsResult ignoreResult; - - ignoreResult = FRIEND_IGNORE_NOT_FOUND; - IgnoreGuid = 0; - - if (result) - { - IgnoreGuid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER); - - if (IgnoreGuid) - { - if (IgnoreGuid == GetPlayer()->GetGUID()) //not add yourself - ignoreResult = FRIEND_IGNORE_SELF; - else if (GetPlayer()->GetSocial()->HasIgnore(GUID_LOPART(IgnoreGuid))) - ignoreResult = FRIEND_IGNORE_ALREADY; - else - { - ignoreResult = FRIEND_IGNORE_ADDED; - - // ignore list full - if (!GetPlayer()->GetSocial()->AddToSocialList(GUID_LOPART(IgnoreGuid), true)) - ignoreResult = FRIEND_IGNORE_FULL; - } - } - } - - sSocialMgr->SendFriendStatus(GetPlayer(), ignoreResult, GUID_LOPART(IgnoreGuid), false); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent (SMSG_FRIEND_STATUS)"); -} - -void WorldSession::HandleDelIgnoreOpcode(WorldPacket & recv_data) -{ - uint64 IgnoreGUID; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_DEL_IGNORE"); - - recv_data >> IgnoreGUID; - - _player->GetSocial()->RemoveFromSocialList(GUID_LOPART(IgnoreGUID), true); - - sSocialMgr->SendFriendStatus(GetPlayer(), FRIEND_IGNORE_REMOVED, GUID_LOPART(IgnoreGUID), false); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent motd (SMSG_FRIEND_STATUS)"); -} - -void WorldSession::HandleSetContactNotesOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_SET_CONTACT_NOTES"); - uint64 guid; - std::string note; - recv_data >> guid >> note; - _player->GetSocial()->SetFriendNote(GUID_LOPART(guid), note); -} - -void WorldSession::HandleBugOpcode(WorldPacket & recv_data) -{ - uint32 suggestion, contentlen, typelen; - std::string content, type; - - recv_data >> suggestion >> contentlen >> content; - - recv_data >> typelen >> type; - - if (suggestion == 0) - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_BUG [Bug Report]"); - else - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_BUG [Suggestion]"); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "%s", type.c_str()); - sLog->outDebug(LOG_FILTER_NETWORKIO, "%s", content.c_str()); - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_BUG_REPORT); - - stmt->setString(0, type); - stmt->setString(1, content); - - CharacterDatabase.Execute(stmt); -} - -void WorldSession::HandleReclaimCorpseOpcode(WorldPacket &recv_data) -{ - sLog->outDetail("WORLD: Received CMSG_RECLAIM_CORPSE"); - - uint64 guid; - recv_data >> guid; - - if (GetPlayer()->isAlive()) - return; - - // do not allow corpse reclaim in arena - if (GetPlayer()->InArena()) - return; - - // body not released yet - if (!GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) - return; - - Corpse* corpse = GetPlayer()->GetCorpse(); - - if (!corpse) - return; - - // prevent resurrect before 30-sec delay after body release not finished - if (time_t(corpse->GetGhostTime() + GetPlayer()->GetCorpseReclaimDelay(corpse->GetType() == CORPSE_RESURRECTABLE_PVP)) > time_t(time(NULL))) - return; - - if (!corpse->IsWithinDistInMap(GetPlayer(), CORPSE_RECLAIM_RADIUS, true)) - return; - - // resurrect - GetPlayer()->ResurrectPlayer(GetPlayer()->InBattleground() ? 1.0f : 0.5f); - - // spawn bones - GetPlayer()->SpawnCorpseBones(); -} - -void WorldSession::HandleResurrectResponseOpcode(WorldPacket & recv_data) -{ - sLog->outDetail("WORLD: Received CMSG_RESURRECT_RESPONSE"); - - uint64 guid; - uint8 status; - recv_data >> guid; - recv_data >> status; - - if (GetPlayer()->isAlive()) - return; - - if (status == 0) - { - GetPlayer()->clearResurrectRequestData(); // reject - return; - } - - if (!GetPlayer()->isRessurectRequestedBy(guid)) - return; - - GetPlayer()->ResurectUsingRequestData(); -} - -void WorldSession::SendAreaTriggerMessage(const char* Text, ...) -{ - va_list ap; - char szStr [1024]; - szStr[0] = '\0'; - - va_start(ap, Text); - vsnprintf(szStr, 1024, Text, ap); - va_end(ap); - - uint32 length = strlen(szStr)+1; - WorldPacket data(SMSG_AREA_TRIGGER_MESSAGE, 4+length); - data << length; - data << szStr; - SendPacket(&data); -} - -void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recv_data) -{ - uint32 triggerId; - recv_data >> triggerId; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_AREATRIGGER. Trigger ID: %u", triggerId); - - Player* player = GetPlayer(); - if (player->isInFlight()) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "Player '%s' (GUID: %u) in flight, ignore Area Trigger ID:%u", - player->GetName(), player->GetGUIDLow(), triggerId); - return; - } - - AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(triggerId); - if (!atEntry) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "Player '%s' (GUID: %u) send unknown (by DBC) Area Trigger ID:%u", - player->GetName(), player->GetGUIDLow(), triggerId); - return; - } - - if (player->GetMapId() != atEntry->mapid) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "Player '%s' (GUID: %u) too far (trigger map: %u player map: %u), ignore Area Trigger ID: %u", - player->GetName(), atEntry->mapid, player->GetMapId(), player->GetGUIDLow(), triggerId); - return; - } - - // delta is safe radius - const float delta = 5.0f; - - if (atEntry->radius > 0) - { - // if we have radius check it - float dist = player->GetDistance(atEntry->x, atEntry->y, atEntry->z); - if (dist > atEntry->radius + delta) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "Player '%s' (GUID: %u) too far (radius: %f distance: %f), ignore Area Trigger ID: %u", - player->GetName(), player->GetGUIDLow(), atEntry->radius, dist, triggerId); - return; - } - } - else - { - // we have only extent - - // rotate the players position instead of rotating the whole cube, that way we can make a simplified - // is-in-cube check and we have to calculate only one point instead of 4 - - // 2PI = 360°, keep in mind that ingame orientation is counter-clockwise - double rotation = 2 * M_PI - atEntry->box_orientation; - double sinVal = sin(rotation); - double cosVal = cos(rotation); - - float playerBoxDistX = player->GetPositionX() - atEntry->x; - float playerBoxDistY = player->GetPositionY() - atEntry->y; - - float rotPlayerX = float(atEntry->x + playerBoxDistX * cosVal - playerBoxDistY*sinVal); - float rotPlayerY = float(atEntry->y + playerBoxDistY * cosVal + playerBoxDistX*sinVal); - - // box edges are parallel to coordiante axis, so we can treat every dimension independently :D - float dz = player->GetPositionZ() - atEntry->z; - float dx = rotPlayerX - atEntry->x; - float dy = rotPlayerY - atEntry->y; - if ((fabs(dx) > atEntry->box_x / 2 + delta) || - (fabs(dy) > atEntry->box_y / 2 + delta) || - (fabs(dz) > atEntry->box_z / 2 + delta)) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "Player '%s' (GUID: %u) too far (1/2 box X: %f 1/2 box Y: %f 1/2 box Z: %f rotatedPlayerX: %f rotatedPlayerY: %f dZ:%f), ignore Area Trigger ID: %u", - player->GetName(), player->GetGUIDLow(), atEntry->box_x/2, atEntry->box_y/2, atEntry->box_z/2, rotPlayerX, rotPlayerY, dz, triggerId); - return; - } - } - - if (player->isDebugAreaTriggers) - ChatHandler(player).PSendSysMessage(LANG_DEBUG_AREATRIGGER_REACHED, triggerId); - - if (sScriptMgr->OnAreaTrigger(player, atEntry)) - return; - - if (player->isAlive()) - if (uint32 questId = sObjectMgr->GetQuestForAreaTrigger(triggerId)) - if (player->GetQuestStatus(questId) == QUEST_STATUS_INCOMPLETE) - player->AreaExploredOrEventHappens(questId); - - if (sObjectMgr->IsTavernAreaTrigger(triggerId)) - { - // set resting flag we are in the inn - player->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); - player->InnEnter(time(NULL), atEntry->mapid, atEntry->x, atEntry->y, atEntry->z); - player->SetRestType(REST_TYPE_IN_TAVERN); - - if (sWorld->IsFFAPvPRealm()) - player->RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); - - return; - } - - if (Battleground* bg = player->GetBattleground()) - if (bg->GetStatus() == STATUS_IN_PROGRESS) - { - bg->HandleAreaTrigger(player, triggerId); - return; - } - - if (OutdoorPvP* pvp = player->GetOutdoorPvP()) - if (pvp->HandleAreaTrigger(_player, triggerId)) - return; - - AreaTrigger const* at = sObjectMgr->GetAreaTrigger(triggerId); - if (!at) - return; - - bool teleported = false; - if (player->GetMapId() != at->target_mapId) - { - if (!sMapMgr->CanPlayerEnter(at->target_mapId, player, false)) - return; - - if (Group* group = player->GetGroup()) - if (group->isLFGGroup() && player->GetMap()->IsDungeon()) - teleported = player->TeleportToBGEntryPoint(); - } - - if (!teleported) - player->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, at->target_Orientation, TELE_TO_NOT_LEAVE_TRANSPORT); -} - -void WorldSession::HandleUpdateAccountData(WorldPacket &recv_data) -{ - sLog->outDetail("WORLD: Received CMSG_UPDATE_ACCOUNT_DATA"); - - uint32 type, timestamp, decompressedSize; - recv_data >> type >> timestamp >> decompressedSize; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "UAD: type %u, time %u, decompressedSize %u", type, timestamp, decompressedSize); - - if (type > NUM_ACCOUNT_DATA_TYPES) - return; - - if (decompressedSize == 0) // erase - { - SetAccountData(AccountDataType(type), 0, ""); - - WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA_COMPLETE, 4+4); - data << uint32(type); - data << uint32(0); - SendPacket(&data); - - return; - } - - if (decompressedSize > 0xFFFF) - { - recv_data.rfinish(); // unnneded warning spam in this case - sLog->outError("UAD: Account data packet too big, size %u", decompressedSize); - return; - } - - ByteBuffer dest; - dest.resize(decompressedSize); - - uLongf realSize = decompressedSize; - if (uncompress(const_cast(dest.contents()), &realSize, const_cast(recv_data.contents() + recv_data.rpos()), recv_data.size() - recv_data.rpos()) != Z_OK) - { - recv_data.rfinish(); // unnneded warning spam in this case - sLog->outError("UAD: Failed to decompress account data"); - return; - } - - recv_data.rfinish(); // uncompress read (recv_data.size() - recv_data.rpos()) - - std::string adata; - dest >> adata; - - SetAccountData(AccountDataType(type), timestamp, adata); - - WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA_COMPLETE, 4+4); - data << uint32(type); - data << uint32(0); - SendPacket(&data); -} - -void WorldSession::HandleRequestAccountData(WorldPacket& recv_data) -{ - sLog->outDetail("WORLD: Received CMSG_REQUEST_ACCOUNT_DATA"); - - uint32 type; - recv_data >> type; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "RAD: type %u", type); - - if (type > NUM_ACCOUNT_DATA_TYPES) - return; - - AccountData* adata = GetAccountData(AccountDataType(type)); - - uint32 size = adata->Data.size(); - - uLongf destSize = compressBound(size); - - ByteBuffer dest; - dest.resize(destSize); - - if (size && compress(const_cast(dest.contents()), &destSize, (uint8*)adata->Data.c_str(), size) != Z_OK) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "RAD: Failed to compress account data"); - return; - } - - dest.resize(destSize); - - WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA, 8+4+4+4+destSize); - data << uint64(_player ? _player->GetGUID() : 0); // player guid - data << uint32(type); // type (0-7) - data << uint32(adata->Time); // unix time - data << uint32(size); // decompressed length - data.append(dest); // compressed data - SendPacket(&data); -} - -void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_SET_ACTION_BUTTON"); - uint8 button; - uint32 packetData; - recv_data >> button >> packetData; - - uint32 action = ACTION_BUTTON_ACTION(packetData); - uint8 type = ACTION_BUTTON_TYPE(packetData); - - sLog->outDetail("BUTTON: %u ACTION: %u TYPE: %u", button, action, type); - if (!packetData) - { - sLog->outDetail("MISC: Remove action from button %u", button); - GetPlayer()->removeActionButton(button); - } - else - { - switch (type) - { - case ACTION_BUTTON_MACRO: - case ACTION_BUTTON_CMACRO: - sLog->outDetail("MISC: Added Macro %u into button %u", action, button); - break; - case ACTION_BUTTON_EQSET: - sLog->outDetail("MISC: Added EquipmentSet %u into button %u", action, button); - break; - case ACTION_BUTTON_SPELL: - sLog->outDetail("MISC: Added Spell %u into button %u", action, button); - break; - case ACTION_BUTTON_ITEM: - sLog->outDetail("MISC: Added Item %u into button %u", action, button); - break; - default: - sLog->outError("MISC: Unknown action button type %u for action %u into button %u", type, action, button); - return; - } - GetPlayer()->addActionButton(button, action, type); - } -} - -void WorldSession::HandleCompleteCinematic(WorldPacket & /*recv_data*/) -{ - sLog->outStaticDebug("WORLD: Player is watching cinema"); -} - -void WorldSession::HandleNextCinematicCamera(WorldPacket & /*recv_data*/) -{ - sLog->outStaticDebug("WORLD: Which movie to play"); -} - -void WorldSession::HandleMoveTimeSkippedOpcode(WorldPacket & recv_data) -{ - /* WorldSession::Update(getMSTime());*/ - sLog->outStaticDebug("WORLD: Time Lag/Synchronization Resent/Update"); - - uint64 guid; - recv_data.readPackGUID(guid); - recv_data.read_skip(); - /* - uint64 guid; - uint32 time_skipped; - recv_data >> guid; - recv_data >> time_skipped; - sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_MOVE_TIME_SKIPPED"); - - /// TODO - must be need use in Trinity - We substract server Lags to move time (AntiLags) - for exmaple - GetPlayer()->ModifyLastMoveTime(-int32(time_skipped)); - */ -} - -void WorldSession::HandleFeatherFallAck(WorldPacket &recv_data) -{ - sLog->outStaticDebug("WORLD: CMSG_MOVE_FEATHER_FALL_ACK"); - - // no used - recv_data.rfinish(); // prevent warnings spam -} - -void WorldSession::HandleMoveUnRootAck(WorldPacket& recv_data) -{ - // no used - recv_data.rfinish(); // prevent warnings spam -/* - uint64 guid; - recv_data >> guid; - - // now can skip not our packet - if (_player->GetGUID() != guid) - { - recv_data.rfinish(); // prevent warnings spam - return; - } - - sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_FORCE_MOVE_UNROOT_ACK"); - - recv_data.read_skip(); // unk - - MovementInfo movementInfo; - movementInfo.guid = guid; - ReadMovementInfo(recv_data, &movementInfo); - recv_data.read_skip(); // unk2 -*/ -} - -void WorldSession::HandleMoveRootAck(WorldPacket& recv_data) -{ - // no used - recv_data.rfinish(); // prevent warnings spam -/* - uint64 guid; - recv_data >> guid; - - // now can skip not our packet - if (_player->GetGUID() != guid) - { - recv_data.rfinish(); // prevent warnings spam - return; - } - - sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_FORCE_MOVE_ROOT_ACK"); - - recv_data.read_skip(); // unk - - MovementInfo movementInfo; - ReadMovementInfo(recv_data, &movementInfo); -*/ -} - -void WorldSession::HandleSetActionBarToggles(WorldPacket& recv_data) -{ - uint8 ActionBar; - - recv_data >> ActionBar; - - if (!GetPlayer()) // ignore until not logged (check needed because STATUS_AUTHED) - { - if (ActionBar != 0) - sLog->outError("WorldSession::HandleSetActionBarToggles in not logged state with value: %u, ignored", uint32(ActionBar)); - return; - } - - GetPlayer()->SetByteValue(PLAYER_FIELD_BYTES, 2, ActionBar); -} - -void WorldSession::HandleWardenDataOpcode(WorldPacket& recv_data) -{ - recv_data.read_skip(); - /* - uint8 tmp; - recv_data >> tmp; - sLog->outDebug("Received opcode CMSG_WARDEN_DATA, not resolve.uint8 = %u", tmp); - */ -} - -void WorldSession::HandlePlayedTime(WorldPacket& recv_data) -{ - uint8 unk1; - recv_data >> unk1; // 0 or 1 expected - - WorldPacket data(SMSG_PLAYED_TIME, 4 + 4 + 1); - data << uint32(_player->GetTotalPlayedTime()); - data << uint32(_player->GetLevelPlayedTime()); - data << uint8(unk1); // 0 - will not show in chat frame - SendPacket(&data); -} - -void WorldSession::HandleInspectOpcode(WorldPacket& recv_data) -{ - uint64 guid; - recv_data >> guid; - sLog->outStaticDebug("Inspected guid is " UI64FMTD, guid); - - _player->SetSelection(guid); - - Player* player = ObjectAccessor::FindPlayer(guid); - if (!player) // wrong player - return; - - uint32 talent_points = 0x47; - uint32 guid_size = player->GetPackGUID().wpos(); - WorldPacket data(SMSG_INSPECT_TALENT, guid_size+4+talent_points); - data.append(player->GetPackGUID()); - - if (sWorld->getBoolConfig(CONFIG_TALENTS_INSPECTING) || _player->isGameMaster()) - { - player->BuildPlayerTalentsInfoData(&data); - } - else - { - data << uint32(0); // unspentTalentPoints - data << uint8(0); // talentGroupCount - data << uint8(0); // talentGroupIndex - } - - player->BuildEnchantmentsInfoData(&data); - SendPacket(&data); -} - -void WorldSession::HandleInspectHonorStatsOpcode(WorldPacket& recv_data) -{ - uint64 guid; - recv_data >> guid; - - Player* player = ObjectAccessor::FindPlayer(guid); - - if (!player) - { - sLog->outError("InspectHonorStats: WTF, player not found..."); - return; - } - - WorldPacket data(MSG_INSPECT_HONOR_STATS, 8+1+4*4); - data << uint64(player->GetGUID()); - data << uint8(player->GetHonorPoints()); - data << uint32(player->GetUInt32Value(PLAYER_FIELD_KILLS)); - data << uint32(player->GetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION)); - data << uint32(player->GetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION)); - data << uint32(player->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS)); - SendPacket(&data); -} - -void WorldSession::HandleWorldTeleportOpcode(WorldPacket& recv_data) -{ - // write in client console: worldport 469 452 6454 2536 180 or /console worldport 469 452 6454 2536 180 - // Received opcode CMSG_WORLD_TELEPORT - // Time is ***, map=469, x=452.000000, y=6454.000000, z=2536.000000, orient=3.141593 - - uint32 time; - uint32 mapid; - float PositionX; - float PositionY; - float PositionZ; - float Orientation; - - recv_data >> time; // time in m.sec. - recv_data >> mapid; - recv_data >> PositionX; - recv_data >> PositionY; - recv_data >> PositionZ; - recv_data >> Orientation; // o (3.141593 = 180 degrees) - - //sLog->outDebug("Received opcode CMSG_WORLD_TELEPORT"); - if (GetPlayer()->isInFlight()) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "Player '%s' (GUID: %u) in flight, ignore worldport command.", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow()); - return; - } - - sLog->outStaticDebug("Time %u sec, map=%u, x=%f, y=%f, z=%f, orient=%f", time/1000, mapid, PositionX, PositionY, PositionZ, Orientation); - - if (AccountMgr::IsAdminAccount(GetSecurity())) - GetPlayer()->TeleportTo(mapid, PositionX, PositionY, PositionZ, Orientation); - else - SendNotification(LANG_YOU_NOT_HAVE_PERMISSION); - sLog->outDebug(LOG_FILTER_NETWORKIO, "Received worldport command from player %s", GetPlayer()->GetName()); -} - -void WorldSession::HandleWhoisOpcode(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode CMSG_WHOIS"); - std::string charname; - recv_data >> charname; - - if (!AccountMgr::IsAdminAccount(GetSecurity())) - { - SendNotification(LANG_YOU_NOT_HAVE_PERMISSION); - return; - } - - if (charname.empty() || !normalizePlayerName (charname)) - { - SendNotification(LANG_NEED_CHARACTER_NAME); - return; - } - - Player* player = sObjectAccessor->FindPlayerByName(charname.c_str()); - - if (!player) - { - SendNotification(LANG_PLAYER_NOT_EXIST_OR_OFFLINE, charname.c_str()); - return; - } - - uint32 accid = player->GetSession()->GetAccountId(); - - QueryResult result = LoginDatabase.PQuery("SELECT username, email, last_ip FROM account WHERE id=%u", accid); - if (!result) - { - SendNotification(LANG_ACCOUNT_FOR_PLAYER_NOT_FOUND, charname.c_str()); - return; - } - - Field* fields = result->Fetch(); - std::string acc = fields[0].GetString(); - if (acc.empty()) - acc = "Unknown"; - std::string email = fields[1].GetString(); - if (email.empty()) - email = "Unknown"; - std::string lastip = fields[2].GetString(); - if (lastip.empty()) - lastip = "Unknown"; - - std::string msg = charname + "'s " + "account is " + acc + ", e-mail: " + email + ", last ip: " + lastip; - - WorldPacket data(SMSG_WHOIS, msg.size()+1); - data << msg; - _player->GetSession()->SendPacket(&data); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "Received whois command from player %s for character %s", GetPlayer()->GetName(), charname.c_str()); -} - -void WorldSession::HandleComplainOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_COMPLAIN"); - - uint8 spam_type; // 0 - mail, 1 - chat - uint64 spammer_guid; - uint32 unk1 = 0; - uint32 unk2 = 0; - uint32 unk3 = 0; - uint32 unk4 = 0; - std::string description = ""; - recv_data >> spam_type; // unk 0x01 const, may be spam type (mail/chat) - recv_data >> spammer_guid; // player guid - switch (spam_type) - { - case 0: - recv_data >> unk1; // const 0 - recv_data >> unk2; // probably mail id - recv_data >> unk3; // const 0 - break; - case 1: - recv_data >> unk1; // probably language - recv_data >> unk2; // message type? - recv_data >> unk3; // probably channel id - recv_data >> unk4; // unk random value - recv_data >> description; // spam description string (messagetype, channel name, player name, message) - break; - } - - // NOTE: all chat messages from this spammer automatically ignored by spam reporter until logout in case chat spam. - // if it's mail spam - ALL mails from this spammer automatically removed by client - - // Complaint Received message - WorldPacket data(SMSG_COMPLAIN_RESULT, 1); - data << uint8(0); - SendPacket(&data); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "REPORT SPAM: type %u, guid %u, unk1 %u, unk2 %u, unk3 %u, unk4 %u, message %s", spam_type, GUID_LOPART(spammer_guid), unk1, unk2, unk3, unk4, description.c_str()); -} - -void WorldSession::HandleRealmSplitOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_REALM_SPLIT"); - - uint32 unk; - std::string split_date = "01/01/01"; - recv_data >> unk; - - WorldPacket data(SMSG_REALM_SPLIT, 4+4+split_date.size()+1); - data << unk; - data << uint32(0x00000000); // realm split state - // split states: - // 0x0 realm normal - // 0x1 realm split - // 0x2 realm split pending - data << split_date; - SendPacket(&data); - //sLog->outDebug("response sent %u", unk); -} - -void WorldSession::HandleFarSightOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_FAR_SIGHT"); - - uint8 apply; - recv_data >> apply; - - switch (apply) - { - case 0: - sLog->outDebug(LOG_FILTER_NETWORKIO, "Player %u set vision to self", _player->GetGUIDLow()); - _player->SetSeer(_player); - break; - case 1: - sLog->outDebug(LOG_FILTER_NETWORKIO, "Added FarSight " UI64FMTD " to player %u", _player->GetUInt64Value(PLAYER_FARSIGHT), _player->GetGUIDLow()); - if (WorldObject* target = _player->GetViewpoint()) - _player->SetSeer(target); - else - sLog->outError("Player %s requests non-existing seer " UI64FMTD, _player->GetName(), _player->GetUInt64Value(PLAYER_FARSIGHT)); - break; - default: - sLog->outDebug(LOG_FILTER_NETWORKIO, "Unhandled mode in CMSG_FAR_SIGHT: %u", apply); - return; - } - - GetPlayer()->UpdateVisibilityForPlayer(); -} - -void WorldSession::HandleSetTitleOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_SET_TITLE"); - - int32 title; - recv_data >> title; - - // -1 at none - if (title > 0 && title < MAX_TITLE_INDEX) - { - if (!GetPlayer()->HasTitle(title)) - return; - } - else - title = 0; - - GetPlayer()->SetUInt32Value(PLAYER_CHOSEN_TITLE, title); -} - -void WorldSession::HandleTimeSyncResp(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_TIME_SYNC_RESP"); - - uint32 counter, clientTicks; - recv_data >> counter >> clientTicks; - - if (counter != _player->m_timeSyncCounter - 1) - sLog->outDebug(LOG_FILTER_NETWORKIO, "Wrong time sync counter from player %s (cheater?)", _player->GetName()); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "Time sync received: counter %u, client ticks %u, time since last sync %u", counter, clientTicks, clientTicks - _player->m_timeSyncClient); - - uint32 ourTicks = clientTicks + (getMSTime() - _player->m_timeSyncServer); - - // diff should be small - sLog->outDebug(LOG_FILTER_NETWORKIO, "Our ticks: %u, diff %u, latency %u", ourTicks, ourTicks - clientTicks, GetLatency()); - - _player->m_timeSyncClient = clientTicks; -} - -void WorldSession::HandleResetInstancesOpcode(WorldPacket & /*recv_data*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_RESET_INSTANCES"); - Group* group = _player->GetGroup(); - if (group) - { - if (group->IsLeader(_player->GetGUID())) - { - group->ResetInstances(INSTANCE_RESET_ALL, false, _player); - group->ResetInstances(INSTANCE_RESET_ALL, true, _player); - } - } - else - { - _player->ResetInstances(INSTANCE_RESET_ALL, false); - _player->ResetInstances(INSTANCE_RESET_ALL, true); - } -} - -void WorldSession::HandleSetDungeonDifficultyOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "MSG_SET_DUNGEON_DIFFICULTY"); - - uint32 mode; - recv_data >> mode; - - if (mode >= MAX_DUNGEON_DIFFICULTY) - { - sLog->outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode); - return; - } - - if (Difficulty(mode) == _player->GetDungeonDifficulty()) - return; - - // cannot reset while in an instance - Map* map = _player->GetMap(); - if (map && map->IsDungeon()) - { - sLog->outError("WorldSession::HandleSetDungeonDifficultyOpcode: player (Name: %s, GUID: %u) tried to reset the instance while player is inside!", _player->GetName(), _player->GetGUIDLow()); - return; - } - - Group* group = _player->GetGroup(); - if (group) - { - if (group->IsLeader(_player->GetGUID())) - { - for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* pGroupGuy = itr->getSource(); - if (!pGroupGuy) - continue; - - if (!pGroupGuy->IsInMap(pGroupGuy)) - return; - - map = pGroupGuy->GetMap(); - if (map && map->IsNonRaidDungeon()) - { - sLog->outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d tried to reset the instance while group member (Name: %s, GUID: %u) is inside!", _player->GetGUIDLow(), pGroupGuy->GetName(), pGroupGuy->GetGUIDLow()); - return; - } - } - // the difficulty is set even if the instances can't be reset - //_player->SendDungeonDifficulty(true); - group->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, false, _player); - group->SetDungeonDifficulty(Difficulty(mode)); - } - } - else - { - _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, false); - _player->SetDungeonDifficulty(Difficulty(mode)); - } -} - -void WorldSession::HandleSetRaidDifficultyOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "MSG_SET_RAID_DIFFICULTY"); - - uint32 mode; - recv_data >> mode; - - if (mode >= MAX_RAID_DIFFICULTY) - { - sLog->outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode); - return; - } - - // cannot reset while in an instance - Map* map = _player->GetMap(); - if (map && map->IsDungeon()) - { - sLog->outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow()); - return; - } - - if (Difficulty(mode) == _player->GetRaidDifficulty()) - return; - - Group* group = _player->GetGroup(); - if (group) - { - if (group->IsLeader(_player->GetGUID())) - { - for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* pGroupGuy = itr->getSource(); - if (!pGroupGuy) - continue; - - if (!pGroupGuy->IsInMap(pGroupGuy)) - return; - - map = pGroupGuy->GetMap(); - if (map && map->IsRaid()) - { - sLog->outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow()); - return; - } - } - // the difficulty is set even if the instances can't be reset - //_player->SendDungeonDifficulty(true); - group->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true, _player); - group->SetRaidDifficulty(Difficulty(mode)); - } - } - else - { - _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true); - _player->SetRaidDifficulty(Difficulty(mode)); - } -} - -void WorldSession::HandleCancelMountAuraOpcode(WorldPacket & /*recv_data*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CANCEL_MOUNT_AURA"); - - //If player is not mounted, so go out :) - if (!_player->IsMounted()) // not blizz like; no any messages on blizz - { - ChatHandler(this).SendSysMessage(LANG_CHAR_NON_MOUNTED); - return; - } - - if (_player->isInFlight()) // not blizz like; no any messages on blizz - { - ChatHandler(this).SendSysMessage(LANG_YOU_IN_FLIGHT); - return; - } - - _player->Dismount(); - _player->RemoveAurasByType(SPELL_AURA_MOUNTED); -} - -void WorldSession::HandleMoveSetCanFlyAckOpcode(WorldPacket & recv_data) -{ - // fly mode on/off - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_MOVE_SET_CAN_FLY_ACK"); - - uint64 guid; // guid - unused - recv_data.readPackGUID(guid); - - recv_data.read_skip(); // unk - - MovementInfo movementInfo; - movementInfo.guid = guid; - ReadMovementInfo(recv_data, &movementInfo); - - recv_data.read_skip(); // unk2 - - _player->m_mover->m_movementInfo.flags = movementInfo.GetMovementFlags(); -} - -void WorldSession::HandleRequestPetInfoOpcode(WorldPacket & /*recv_data */) -{ - /* - sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_REQUEST_PET_INFO"); - recv_data.hexlike(); - */ -} - -void WorldSession::HandleSetTaxiBenchmarkOpcode(WorldPacket & recv_data) -{ - uint8 mode; - recv_data >> mode; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "Client used \"/timetest %d\" command", mode); -} - -void WorldSession::HandleQueryInspectAchievements(WorldPacket & recv_data) -{ - uint64 guid; - recv_data.readPackGUID(guid); - - Player* player = ObjectAccessor::FindPlayer(guid); - if (!player) - return; - - player->GetAchievementMgr().SendRespondInspectAchievements(_player); -} - -void WorldSession::HandleWorldStateUITimerUpdate(WorldPacket& /*recv_data*/) -{ - // empty opcode - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_WORLD_STATE_UI_TIMER_UPDATE"); - - WorldPacket data(SMSG_WORLD_STATE_UI_TIMER_UPDATE, 4); - data << uint32(time(NULL)); - SendPacket(&data); -} - -void WorldSession::HandleReadyForAccountDataTimes(WorldPacket& /*recv_data*/) -{ - // empty opcode - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_READY_FOR_ACCOUNT_DATA_TIMES"); - - SendAccountDataTimes(GLOBAL_CACHE_MASK); -} - -void WorldSession::SendSetPhaseShift(uint32 PhaseShift) -{ - WorldPacket data(SMSG_SET_PHASE_SHIFT, 4); - data << uint32(PhaseShift); - SendPacket(&data); -} - -void WorldSession::HandleHearthAndResurrect(WorldPacket& /*recv_data*/) -{ - if (_player->isInFlight()) - return; - - AreaTableEntry const* atEntry = GetAreaEntryByAreaID(_player->GetAreaId()); - if (!atEntry || !(atEntry->flags & AREA_FLAG_WINTERGRASP_2)) - return; - - _player->BuildPlayerRepop(); - _player->ResurrectPlayer(100); - _player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->GetOrientation()); -} - -void WorldSession::HandleInstanceLockResponse(WorldPacket& recvPacket) -{ - uint8 accept; - recvPacket >> accept; - - if (!_player->HasPendingBind()) - { - sLog->outDetail("InstanceLockResponse: Player %s (guid %u) tried to bind himself/teleport to graveyard without a pending bind!", _player->GetName(), _player->GetGUIDLow()); - return; - } - - if (accept) - _player->BindToInstance(); - else - _player->RepopAtGraveyard(); - - _player->SetPendingBind(0, 0); -} diff --git a/src/server/game/Server/Protocol/Handlers/MovementHandler.cpp b/src/server/game/Server/Protocol/Handlers/MovementHandler.cpp deleted file mode 100755 index 7d1233c8f70..00000000000 --- a/src/server/game/Server/Protocol/Handlers/MovementHandler.cpp +++ /dev/null @@ -1,573 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Opcodes.h" -#include "Log.h" -#include "Corpse.h" -#include "Player.h" -#include "SpellAuras.h" -#include "MapManager.h" -#include "Transport.h" -#include "Battleground.h" -#include "WaypointMovementGenerator.h" -#include "InstanceSaveMgr.h" -#include "ObjectMgr.h" - -void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket & /*recv_data*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: got MSG_MOVE_WORLDPORT_ACK."); - HandleMoveWorldportAckOpcode(); -} - -void WorldSession::HandleMoveWorldportAckOpcode() -{ - // ignore unexpected far teleports - if (!GetPlayer()->IsBeingTeleportedFar()) - return; - - GetPlayer()->SetSemaphoreTeleportFar(false); - - // get the teleport destination - WorldLocation &loc = GetPlayer()->GetTeleportDest(); - - // possible errors in the coordinate validity check - if (!MapManager::IsValidMapCoord(loc)) - { - LogoutPlayer(false); - return; - } - - // get the destination map entry, not the current one, this will fix homebind and reset greeting - MapEntry const* mEntry = sMapStore.LookupEntry(loc.GetMapId()); - InstanceTemplate const* mInstance = sObjectMgr->GetInstanceTemplate(loc.GetMapId()); - - // reset instance validity, except if going to an instance inside an instance - if (GetPlayer()->m_InstanceValid == false && !mInstance) - GetPlayer()->m_InstanceValid = true; - - Map* oldMap = GetPlayer()->GetMap(); - ASSERT(oldMap); - if (GetPlayer()->IsInWorld()) - { - sLog->outCrash("Player (Name %s) is still in world when teleported from map %u to new map %u", GetPlayer()->GetName(), oldMap->GetId(), loc.GetMapId()); - oldMap->RemovePlayerFromMap(GetPlayer(), false); - } - - // relocate the player to the teleport destination - Map* newMap = sMapMgr->CreateMap(loc.GetMapId(), GetPlayer()); - // the CanEnter checks are done in TeleporTo but conditions may change - // while the player is in transit, for example the map may get full - if (!newMap || !newMap->CanEnter(GetPlayer())) - { - sLog->outError("Map %d could not be created for player %d, porting player to homebind", loc.GetMapId(), GetPlayer()->GetGUIDLow()); - GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation()); - return; - } - else - GetPlayer()->Relocate(&loc); - - GetPlayer()->ResetMap(); - GetPlayer()->SetMap(newMap); - - GetPlayer()->SendInitialPacketsBeforeAddToMap(); - if (!GetPlayer()->GetMap()->AddPlayerToMap(GetPlayer())) - { - sLog->outError("WORLD: failed to teleport player %s (%d) to map %d because of unknown reason!", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), loc.GetMapId()); - GetPlayer()->ResetMap(); - GetPlayer()->SetMap(oldMap); - GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation()); - return; - } - - // battleground state prepare (in case join to BG), at relogin/tele player not invited - // only add to bg group and object, if the player was invited (else he entered through command) - if (_player->InBattleground()) - { - // cleanup setting if outdated - if (!mEntry->IsBattlegroundOrArena()) - { - // We're not in BG - _player->SetBattlegroundId(0, BATTLEGROUND_TYPE_NONE); - // reset destination bg team - _player->SetBGTeam(0); - } - // join to bg case - else if (Battleground* bg = _player->GetBattleground()) - { - if (_player->IsInvitedForBattlegroundInstance(_player->GetBattlegroundId())) - bg->AddPlayer(_player); - } - } - - GetPlayer()->SendInitialPacketsAfterAddToMap(); - - // flight fast teleport case - if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) - { - if (!_player->InBattleground()) - { - // short preparations to continue flight - FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top()); - flight->Initialize(*GetPlayer()); - return; - } - - // battleground state prepare, stop flight - GetPlayer()->GetMotionMaster()->MovementExpired(); - GetPlayer()->CleanupAfterTaxiFlight(); - } - - // resurrect character at enter into instance where his corpse exist after add to map - Corpse* corpse = GetPlayer()->GetCorpse(); - if (corpse && corpse->GetType() != CORPSE_BONES && corpse->GetMapId() == GetPlayer()->GetMapId()) - { - if (mEntry->IsDungeon()) - { - GetPlayer()->ResurrectPlayer(0.5f, false); - GetPlayer()->SpawnCorpseBones(); - } - } - - bool allowMount = !mEntry->IsDungeon() || mEntry->IsBattlegroundOrArena(); - if (mInstance) - { - Difficulty diff = GetPlayer()->GetDifficulty(mEntry->IsRaid()); - if (MapDifficulty const* mapDiff = GetMapDifficultyData(mEntry->MapID, diff)) - { - if (mapDiff->resetTime) - { - if (time_t timeReset = sInstanceSaveMgr->GetResetTimeFor(mEntry->MapID, diff)) - { - uint32 timeleft = uint32(timeReset - time(NULL)); - GetPlayer()->SendInstanceResetWarning(mEntry->MapID, diff, timeleft); - } - } - } - allowMount = mInstance->AllowMount; - } - - // mount allow check - if (!allowMount) - _player->RemoveAurasByType(SPELL_AURA_MOUNTED); - - // update zone immediately, otherwise leave channel will cause crash in mtmap - uint32 newzone, newarea; - GetPlayer()->GetZoneAndAreaId(newzone, newarea); - GetPlayer()->UpdateZone(newzone, newarea); - - // honorless target - if (GetPlayer()->pvpInfo.inHostileArea) - GetPlayer()->CastSpell(GetPlayer(), 2479, true); - - // in friendly area - else if (GetPlayer()->IsPvP() && !GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP)) - GetPlayer()->UpdatePvP(false, false); - - // resummon pet - GetPlayer()->ResummonPetTemporaryUnSummonedIfAny(); - - //lets process all delayed operations on successful teleport - GetPlayer()->ProcessDelayedOperations(); -} - -void WorldSession::HandleMoveTeleportAck(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "MSG_MOVE_TELEPORT_ACK"); - uint64 guid; - - recv_data.readPackGUID(guid); - - uint32 flags, time; - recv_data >> flags >> time; - sLog->outStaticDebug("Guid " UI64FMTD, guid); - sLog->outStaticDebug("Flags %u, time %u", flags, time/IN_MILLISECONDS); - - Unit* mover = _player->m_mover; - Player* plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; - - if (!plMover || !plMover->IsBeingTeleportedNear()) - return; - - if (guid != plMover->GetGUID()) - return; - - plMover->SetSemaphoreTeleportNear(false); - - uint32 old_zone = plMover->GetZoneId(); - - WorldLocation const& dest = plMover->GetTeleportDest(); - - plMover->UpdatePosition(dest, true); - - uint32 newzone, newarea; - plMover->GetZoneAndAreaId(newzone, newarea); - plMover->UpdateZone(newzone, newarea); - - // new zone - if (old_zone != newzone) - { - // honorless target - if (plMover->pvpInfo.inHostileArea) - plMover->CastSpell(plMover, 2479, true); - - // in friendly area - else if (plMover->IsPvP() && !plMover->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP)) - plMover->UpdatePvP(false, false); - } - - // resummon pet - GetPlayer()->ResummonPetTemporaryUnSummonedIfAny(); - - //lets process all delayed operations on successful teleport - GetPlayer()->ProcessDelayedOperations(); -} - -void WorldSession::HandleMovementOpcodes(WorldPacket & recv_data) -{ - uint16 opcode = recv_data.GetOpcode(); - - Unit* mover = _player->m_mover; - - ASSERT(mover != NULL); // there must always be a mover - - Player* plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; - - // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck - if (plMover && plMover->IsBeingTeleported()) - { - recv_data.rfinish(); // prevent warnings spam - return; - } - - /* extract packet */ - uint64 guid; - - recv_data.readPackGUID(guid); - - MovementInfo movementInfo; - movementInfo.guid = guid; - ReadMovementInfo(recv_data, &movementInfo); - - recv_data.rfinish(); // prevent warnings spam - - // prevent tampered movement data - if (guid != mover->GetGUID()) - return; - - if (!movementInfo.pos.IsPositionValid()) - { - recv_data.rfinish(); // prevent warnings spam - return; - } - - /* handle special cases */ - if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) - { - // transports size limited - // (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) - if (movementInfo.t_pos.GetPositionX() > 50 || movementInfo.t_pos.GetPositionY() > 50 || movementInfo.t_pos.GetPositionZ() > 50) - { - recv_data.rfinish(); // prevent warnings spam - return; - } - - if (!Trinity::IsValidMapCoord(movementInfo.pos.GetPositionX() + movementInfo.t_pos.GetPositionX(), movementInfo.pos.GetPositionY() + movementInfo.t_pos.GetPositionY(), - movementInfo.pos.GetPositionZ() + movementInfo.t_pos.GetPositionZ(), movementInfo.pos.GetOrientation() + movementInfo.t_pos.GetOrientation())) - { - recv_data.rfinish(); // prevent warnings spam - return; - } - - // if we boarded a transport, add us to it - if (plMover && !plMover->GetTransport()) - { - // elevators also cause the client to send MOVEMENTFLAG_ONTRANSPORT - just dismount if the guid can be found in the transport list - for (MapManager::TransportSet::const_iterator iter = sMapMgr->m_Transports.begin(); iter != sMapMgr->m_Transports.end(); ++iter) - { - if ((*iter)->GetGUID() == movementInfo.t_guid) - { - plMover->m_transport = (*iter); - (*iter)->AddPassenger(plMover); - break; - } - } - } - - if (!mover->GetTransport() && !mover->GetVehicle()) - { - GameObject* go = mover->GetMap()->GetGameObject(movementInfo.t_guid); - if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT) - movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; - } - } - else if (plMover && plMover->GetTransport()) // if we were on a transport, leave - { - plMover->m_transport->RemovePassenger(plMover); - plMover->m_transport = NULL; - movementInfo.t_pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f); - movementInfo.t_time = 0; - movementInfo.t_seat = -1; - } - - // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map). - if (opcode == MSG_MOVE_FALL_LAND && plMover && !plMover->isInFlight()) - plMover->HandleFall(movementInfo); - - if (plMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plMover->IsInWater()) - { - // now client not include swimming flag in case jumping under water - plMover->SetInWater(!plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ())); - } - - /*----------------------*/ - - /* process position-change */ - WorldPacket data(opcode, recv_data.size()); - movementInfo.time = getMSTime(); - movementInfo.guid = mover->GetGUID(); - WriteMovementInfo(&data, &movementInfo); - mover->SendMessageToSet(&data, _player); - - mover->m_movementInfo = movementInfo; - - // this is almost never true (not sure why it is sometimes, but it is), normally use mover->IsVehicle() - if (mover->GetVehicle()) - { - mover->SetOrientation(movementInfo.pos.GetOrientation()); - return; - } - - mover->UpdatePosition(movementInfo.pos); - - if (plMover) // nothing is charmed, or player charmed - { - plMover->UpdateFallInformationIfNeed(movementInfo, opcode); - - if (movementInfo.pos.GetPositionZ() < -500.0f) - { - if (!(plMover->InBattleground() - && plMover->GetBattleground() - && plMover->GetBattleground()->HandlePlayerUnderMap(_player))) - { - // NOTE: this is actually called many times while falling - // even after the player has been teleported away - // TODO: discard movement packets after the player is rooted - if (plMover->isAlive()) - { - plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); - // player can be alive if GM/etc - // change the death state to CORPSE to prevent the death timer from - // starting in the next player update - if (!plMover->isAlive()) - plMover->KillPlayer(); - } - } - } - } -} - -void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recv_data) -{ - uint32 opcode = recv_data.GetOpcode(); - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); - - /* extract packet */ - uint64 guid; - uint32 unk1; - float newspeed; - - recv_data.readPackGUID(guid); - - // now can skip not our packet - if (_player->GetGUID() != guid) - { - recv_data.rfinish(); // prevent warnings spam - return; - } - - // continue parse packet - - recv_data >> unk1; // counter or moveEvent - - MovementInfo movementInfo; - movementInfo.guid = guid; - ReadMovementInfo(recv_data, &movementInfo); - - recv_data >> newspeed; - /*----------------*/ - - // client ACK send one packet for mounted/run case and need skip all except last from its - // in other cases anti-cheat check can be fail in false case - UnitMoveType move_type; - UnitMoveType force_move_type; - - static char const* move_type_name[MAX_MOVE_TYPE] = { "Walk", "Run", "RunBack", "Swim", "SwimBack", "TurnRate", "Flight", "FlightBack", "PitchRate" }; - - switch (opcode) - { - case CMSG_FORCE_WALK_SPEED_CHANGE_ACK: move_type = MOVE_WALK; force_move_type = MOVE_WALK; break; - case CMSG_FORCE_RUN_SPEED_CHANGE_ACK: move_type = MOVE_RUN; force_move_type = MOVE_RUN; break; - case CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK: move_type = MOVE_RUN_BACK; force_move_type = MOVE_RUN_BACK; break; - case CMSG_FORCE_SWIM_SPEED_CHANGE_ACK: move_type = MOVE_SWIM; force_move_type = MOVE_SWIM; break; - case CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK: move_type = MOVE_SWIM_BACK; force_move_type = MOVE_SWIM_BACK; break; - case CMSG_FORCE_TURN_RATE_CHANGE_ACK: move_type = MOVE_TURN_RATE; force_move_type = MOVE_TURN_RATE; break; - case CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT; force_move_type = MOVE_FLIGHT; break; - case CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT_BACK; force_move_type = MOVE_FLIGHT_BACK; break; - case CMSG_FORCE_PITCH_RATE_CHANGE_ACK: move_type = MOVE_PITCH_RATE; force_move_type = MOVE_PITCH_RATE; break; - default: - sLog->outError("WorldSession::HandleForceSpeedChangeAck: Unknown move type opcode: %u", opcode); - return; - } - - // skip all forced speed changes except last and unexpected - // in run/mounted case used one ACK and it must be skipped.m_forced_speed_changes[MOVE_RUN} store both. - if (_player->m_forced_speed_changes[force_move_type] > 0) - { - --_player->m_forced_speed_changes[force_move_type]; - if (_player->m_forced_speed_changes[force_move_type] > 0) - return; - } - - if (!_player->GetTransport() && fabs(_player->GetSpeed(move_type) - newspeed) > 0.01f) - { - if (_player->GetSpeed(move_type) > newspeed) // must be greater - just correct - { - sLog->outError("%sSpeedChange player %s is NOT correct (must be %f instead %f), force set to correct value", - move_type_name[move_type], _player->GetName(), _player->GetSpeed(move_type), newspeed); - _player->SetSpeed(move_type, _player->GetSpeedRate(move_type), true); - } - else // must be lesser - cheating - { - sLog->outBasic("Player %s from account id %u kicked for incorrect speed (must be %f instead %f)", - _player->GetName(), _player->GetSession()->GetAccountId(), _player->GetSpeed(move_type), newspeed); - _player->GetSession()->KickPlayer(); - } - } -} - -void WorldSession::HandleSetActiveMoverOpcode(WorldPacket &recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_SET_ACTIVE_MOVER"); - - uint64 guid; - recv_data >> guid; - - if (GetPlayer()->IsInWorld()) - { - if (_player->m_mover->GetGUID() != guid) - sLog->outError("HandleSetActiveMoverOpcode: incorrect mover guid: mover is " UI64FMTD " (%s - Entry: %u) and should be " UI64FMTD, guid, GetLogNameForGuid(guid), GUID_ENPART(guid), _player->m_mover->GetGUID()); - } -} - -void WorldSession::HandleMoveNotActiveMover(WorldPacket &recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_MOVE_NOT_ACTIVE_MOVER"); - - uint64 old_mover_guid; - recv_data.readPackGUID(old_mover_guid); - - MovementInfo mi; - mi.guid = old_mover_guid; - ReadMovementInfo(recv_data, &mi); - - _player->m_movementInfo = mi; -} - -void WorldSession::HandleMountSpecialAnimOpcode(WorldPacket& /*recv_data*/) -{ - WorldPacket data(SMSG_MOUNTSPECIAL_ANIM, 8); - data << uint64(GetPlayer()->GetGUID()); - - GetPlayer()->SendMessageToSet(&data, false); -} - -void WorldSession::HandleMoveKnockBackAck(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_MOVE_KNOCK_BACK_ACK"); - - uint64 guid; - recv_data.readPackGUID(guid); - - if (_player->m_mover->GetGUID() != guid) - return; - - recv_data.read_skip(); // unk - - MovementInfo movementInfo; - ReadMovementInfo(recv_data, &movementInfo); - _player->m_movementInfo = movementInfo; - - WorldPacket data(MSG_MOVE_KNOCK_BACK, 66); - data.appendPackGUID(guid); - _player->BuildMovementPacket(&data); - - // knockback specific info - data << movementInfo.j_sinAngle; - data << movementInfo.j_cosAngle; - data << movementInfo.j_xyspeed; - data << movementInfo.j_zspeed; - - _player->SendMessageToSet(&data, false); -} - -void WorldSession::HandleMoveHoverAck(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_MOVE_HOVER_ACK"); - - uint64 guid; // guid - unused - recv_data.readPackGUID(guid); - - recv_data.read_skip(); // unk - - MovementInfo movementInfo; - ReadMovementInfo(recv_data, &movementInfo); - - recv_data.read_skip(); // unk2 -} - -void WorldSession::HandleMoveWaterWalkAck(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_MOVE_WATER_WALK_ACK"); - - uint64 guid; // guid - unused - recv_data.readPackGUID(guid); - - recv_data.read_skip(); // unk - - MovementInfo movementInfo; - ReadMovementInfo(recv_data, &movementInfo); - - recv_data.read_skip(); // unk2 -} - -void WorldSession::HandleSummonResponseOpcode(WorldPacket& recv_data) -{ - if (!_player->isAlive() || _player->isInCombat()) - return; - - uint64 summoner_guid; - bool agree; - recv_data >> summoner_guid; - recv_data >> agree; - - _player->SummonIfPossible(agree); -} - diff --git a/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp b/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp deleted file mode 100755 index ef49b337b44..00000000000 --- a/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp +++ /dev/null @@ -1,909 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "Language.h" -#include "DatabaseEnv.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Opcodes.h" -#include "Log.h" -#include "ObjectMgr.h" -#include "SpellMgr.h" -#include "Player.h" -#include "GossipDef.h" -#include "UpdateMask.h" -#include "ObjectAccessor.h" -#include "Creature.h" -#include "Pet.h" -#include "BattlegroundMgr.h" -#include "Battleground.h" -#include "ScriptMgr.h" -#include "CreatureAI.h" -#include "SpellInfo.h" - -enum StableResultCode -{ - STABLE_ERR_MONEY = 0x01, // "you don't have enough money" - STABLE_ERR_STABLE = 0x06, // currently used in most fail cases - STABLE_SUCCESS_STABLE = 0x08, // stable success - STABLE_SUCCESS_UNSTABLE = 0x09, // unstable/swap success - STABLE_SUCCESS_BUY_SLOT = 0x0A, // buy slot success - STABLE_ERR_EXOTIC = 0x0C, // "you are unable to control exotic creatures" -}; - -void WorldSession::HandleTabardVendorActivateOpcode(WorldPacket & recv_data) -{ - uint64 guid; - recv_data >> guid; - - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TABARDDESIGNER); - if (!unit) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleTabardVendorActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - SendTabardVendorActivate(guid); -} - -void WorldSession::SendTabardVendorActivate(uint64 guid) -{ - WorldPacket data(MSG_TABARDVENDOR_ACTIVATE, 8); - data << guid; - SendPacket(&data); -} - -void WorldSession::HandleBankerActivateOpcode(WorldPacket & recv_data) -{ - uint64 guid; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_BANKER_ACTIVATE"); - - recv_data >> guid; - - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_BANKER); - if (!unit) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleBankerActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - SendShowBank(guid); -} - -void WorldSession::SendShowBank(uint64 guid) -{ - WorldPacket data(SMSG_SHOW_BANK, 8); - data << guid; - SendPacket(&data); -} - -void WorldSession::HandleTrainerListOpcode(WorldPacket & recv_data) -{ - uint64 guid; - - recv_data >> guid; - SendTrainerList(guid); -} - -void WorldSession::SendTrainerList(uint64 guid) -{ - std::string str = GetTrinityString(LANG_NPC_TAINER_HELLO); - SendTrainerList(guid, str); -} - -void WorldSession::SendTrainerList(uint64 guid, const std::string& strTitle) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: SendTrainerList"); - - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER); - if (!unit) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: SendTrainerList - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - // trainer list loaded at check; - if (!unit->isCanTrainingOf(_player, true)) - return; - - CreatureTemplate const* ci = unit->GetCreatureInfo(); - - if (!ci) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: SendTrainerList - (GUID: %u) NO CREATUREINFO!", GUID_LOPART(guid)); - return; - } - - TrainerSpellData const* trainer_spells = unit->GetTrainerSpells(); - if (!trainer_spells) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: SendTrainerList - Training spells not found for creature (GUID: %u Entry: %u)", - GUID_LOPART(guid), unit->GetEntry()); - return; - } - - WorldPacket data(SMSG_TRAINER_LIST, 8+4+4+trainer_spells->spellList.size()*38 + strTitle.size()+1); - data << guid; - data << uint32(trainer_spells->trainerType); - - size_t count_pos = data.wpos(); - data << uint32(trainer_spells->spellList.size()); - - // reputation discount - float fDiscountMod = _player->GetReputationPriceDiscount(unit); - bool can_learn_primary_prof = GetPlayer()->GetFreePrimaryProfessionPoints() > 0; - - uint32 count = 0; - for (TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr) - { - TrainerSpell const* tSpell = &itr->second; - - bool valid = true; - bool primary_prof_first_rank = false; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS ; ++i) - { - if (!tSpell->learnedSpell[i]) - continue; - if (!_player->IsSpellFitByClassAndRace(tSpell->learnedSpell[i])) - { - valid = false; - break; - } - SpellInfo const* learnedSpellInfo = sSpellMgr->GetSpellInfo(tSpell->learnedSpell[i]); - if (learnedSpellInfo && learnedSpellInfo->IsPrimaryProfessionFirstRank()) - primary_prof_first_rank = true; - } - if (!valid) - continue; - - TrainerSpellState state = _player->GetTrainerSpellState(tSpell); - - data << uint32(tSpell->spell); // learned spell (or cast-spell in profession case) - data << uint8(state == TRAINER_SPELL_GREEN_DISABLED ? TRAINER_SPELL_GREEN : state); - data << uint32(floor(tSpell->spellCost * fDiscountMod)); - - data << uint32(primary_prof_first_rank && can_learn_primary_prof ? 1 : 0); - // primary prof. learn confirmation dialog - data << uint32(primary_prof_first_rank ? 1 : 0); // must be equal prev. field to have learn button in enabled state - data << uint8(tSpell->reqLevel); - data << uint32(tSpell->reqSkill); - data << uint32(tSpell->reqSkillValue); - //prev + req or req + 0 - uint8 maxReq = 0; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS ; ++i) - { - if (!tSpell->learnedSpell[i]) - continue; - if (uint32 prevSpellId = sSpellMgr->GetPrevSpellInChain(tSpell->learnedSpell[i])) - { - data << uint32(prevSpellId); - ++maxReq; - } - if (maxReq == 3) - break; - SpellsRequiringSpellMapBounds spellsRequired = sSpellMgr->GetSpellsRequiredForSpellBounds(tSpell->learnedSpell[i]); - for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequired.first; itr2 != spellsRequired.second && maxReq < 3; ++itr2) - { - data << uint32(itr2->second); - ++maxReq; - } - if (maxReq == 3) - break; - } - while (maxReq < 3) - { - data << uint32(0); - ++maxReq; - } - - ++count; - } - - data << strTitle; - - data.put(count_pos, count); - SendPacket(&data); -} - -void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket & recv_data) -{ - uint64 guid; - uint32 spellId = 0; - - recv_data >> guid >> spellId; - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_TRAINER_BUY_SPELL NpcGUID=%u, learn spell id is: %u", uint32(GUID_LOPART(guid)), spellId); - - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER); - if (!unit) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleTrainerBuySpellOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - if (!unit->isCanTrainingOf(_player, true)) - return; - - // check present spell in trainer spell list - TrainerSpellData const* trainer_spells = unit->GetTrainerSpells(); - if (!trainer_spells) - return; - - // not found, cheat? - TrainerSpell const* trainer_spell = trainer_spells->Find(spellId); - if (!trainer_spell) - return; - - // can't be learn, cheat? Or double learn with lags... - if (_player->GetTrainerSpellState(trainer_spell) != TRAINER_SPELL_GREEN) - return; - - // apply reputation discount - uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(unit))); - - // check money requirement - if (!_player->HasEnoughMoney(nSpellCost)) - return; - - _player->ModifyMoney(-int32(nSpellCost)); - - unit->SendPlaySpellVisual(179); // 53 SpellCastDirected - unit->SendPlaySpellImpact(_player->GetGUID(), 362); // 113 EmoteSalute - - // learn explicitly or cast explicitly - if (trainer_spell->IsCastable()) - _player->CastSpell(_player, trainer_spell->spell, true); - else - _player->learnSpell(spellId, false); - - WorldPacket data(SMSG_TRAINER_BUY_SUCCEEDED, 12); - data << uint64(guid); - data << uint32(spellId); // should be same as in packet from client - SendPacket(&data); -} - -void WorldSession::HandleGossipHelloOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_GOSSIP_HELLO"); - - uint64 guid; - recv_data >> guid; - - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); - if (!unit) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleGossipHelloOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // set faction visible if needed - if (FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->getFaction())) - _player->GetReputationMgr().SetVisible(factionTemplateEntry); - - GetPlayer()->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK); - // remove fake death - //if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - // GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - if (unit->isArmorer() || unit->isCivilian() || unit->isQuestGiver() || unit->isServiceProvider() || unit->isGuard()) - { - unit->StopMoving(); - } - - // If spiritguide, no need for gossip menu, just put player into resurrect queue - if (unit->isSpiritGuide()) - { - Battleground* bg = _player->GetBattleground(); - if (bg) - { - bg->AddPlayerToResurrectQueue(unit->GetGUID(), _player->GetGUID()); - sBattlegroundMgr->SendAreaSpiritHealerQueryOpcode(_player, bg, unit->GetGUID()); - return; - } - } - - if (!sScriptMgr->OnGossipHello(_player, unit)) - { -// _player->TalkedToCreature(unit->GetEntry(), unit->GetGUID()); - _player->PrepareGossipMenu(unit, unit->GetCreatureInfo()->GossipMenuId, true); - _player->SendPreparedGossip(unit); - } - unit->AI()->sGossipHello(_player); -} - -/*void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_GOSSIP_SELECT_OPTION"); - - uint32 option; - uint32 unk; - uint64 guid; - std::string code = ""; - - recv_data >> guid >> unk >> option; - - if (_player->PlayerTalkClass->GossipOptionCoded(option)) - { - sLog->outDebug(LOG_FILTER_PACKETIO, "reading string"); - recv_data >> code; - sLog->outDebug(LOG_FILTER_PACKETIO, "string read: %s", code.c_str()); - } - - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); - if (!unit) - { - sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: HandleGossipSelectOptionOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - if (!code.empty()) - { - if (!Script->GossipSelectWithCode(_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction(option), code.c_str())) - unit->OnGossipSelect (_player, option); - } - else - { - if (!Script->OnGossipSelect (_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction (option))) - unit->OnGossipSelect (_player, option); - } -}*/ - -void WorldSession::HandleSpiritHealerActivateOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_SPIRIT_HEALER_ACTIVATE"); - - uint64 guid; - - recv_data >> guid; - - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_SPIRITHEALER); - if (!unit) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleSpiritHealerActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - SendSpiritResurrect(); -} - -void WorldSession::SendSpiritResurrect() -{ - _player->ResurrectPlayer(0.5f, true); - - _player->DurabilityLossAll(0.25f, true); - - // get corpse nearest graveyard - WorldSafeLocsEntry const* corpseGrave = NULL; - Corpse* corpse = _player->GetCorpse(); - if (corpse) - corpseGrave = sObjectMgr->GetClosestGraveYard( - corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetMapId(), _player->GetTeam()); - - // now can spawn bones - _player->SpawnCorpseBones(); - - // teleport to nearest from corpse graveyard, if different from nearest to player ghost - if (corpseGrave) - { - WorldSafeLocsEntry const* ghostGrave = sObjectMgr->GetClosestGraveYard( - _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetMapId(), _player->GetTeam()); - - if (corpseGrave != ghostGrave) - _player->TeleportTo(corpseGrave->map_id, corpseGrave->x, corpseGrave->y, corpseGrave->z, _player->GetOrientation()); - // or update at original position - else - _player->UpdateObjectVisibility(); - } - // or update at original position - else - _player->UpdateObjectVisibility(); -} - -void WorldSession::HandleBinderActivateOpcode(WorldPacket & recv_data) -{ - uint64 npcGUID; - recv_data >> npcGUID; - - if (!GetPlayer()->IsInWorld() || !GetPlayer()->isAlive()) - return; - - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_INNKEEPER); - if (!unit) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleBinderActivateOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID))); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - SendBindPoint(unit); -} - -void WorldSession::SendBindPoint(Creature* npc) -{ - // prevent set homebind to instances in any case - if (GetPlayer()->GetMap()->Instanceable()) - return; - - uint32 bindspell = 3286; - - // update sql homebind - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PLAYER_HOMEBIND); - stmt->setUInt16(0, _player->GetMapId()); - stmt->setUInt16(1, _player->GetAreaId()); - stmt->setFloat (2, _player->GetPositionX()); - stmt->setFloat (3, _player->GetPositionY()); - stmt->setFloat (4, _player->GetPositionZ()); - stmt->setUInt32(5, _player->GetGUIDLow()); - CharacterDatabase.Execute(stmt); - - _player->m_homebindMapId = _player->GetMapId(); - _player->m_homebindAreaId = _player->GetAreaId(); - _player->m_homebindX = _player->GetPositionX(); - _player->m_homebindY = _player->GetPositionY(); - _player->m_homebindZ = _player->GetPositionZ(); - - // send spell for homebinding (3286) - npc->CastSpell(_player, bindspell, true); - - WorldPacket data(SMSG_TRAINER_BUY_SUCCEEDED, (8+4)); - data << uint64(npc->GetGUID()); - data << uint32(bindspell); - SendPacket(&data); - - _player->PlayerTalkClass->SendCloseGossip(); -} - -void WorldSession::HandleListStabledPetsOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recv MSG_LIST_STABLED_PETS"); - uint64 npcGUID; - - recv_data >> npcGUID; - - if (!CheckStableMaster(npcGUID)) - return; - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - // remove mounts this fix bug where getting pet from stable while mounted deletes pet. - if (GetPlayer()->IsMounted()) - GetPlayer()->RemoveAurasByType(SPELL_AURA_MOUNTED); - - SendStablePet(npcGUID); -} - -void WorldSession::SendStablePet(uint64 guid) -{ - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SLOTS_DETAIL); - - stmt->setUInt32(0, _player->GetGUIDLow()); - stmt->setUInt8(1, PET_SAVE_FIRST_STABLE_SLOT); - stmt->setUInt8(2, PET_SAVE_LAST_STABLE_SLOT); - - _sendStabledPetCallback.SetParam(guid); - _sendStabledPetCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); -} - -void WorldSession::SendStablePetCallback(PreparedQueryResult result, uint64 guid) -{ - if (!GetPlayer()) - return; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recv MSG_LIST_STABLED_PETS Send."); - - WorldPacket data(MSG_LIST_STABLED_PETS, 200); // guess size - - data << uint64 (guid); - - Pet* pet = _player->GetPet(); - - size_t wpos = data.wpos(); - data << uint8(0); // place holder for slot show number - - data << uint8(GetPlayer()->m_stableSlots); - - uint8 num = 0; // counter for place holder - - // not let move dead pet in slot - if (pet && pet->isAlive() && pet->getPetType() == HUNTER_PET) - { - data << uint32(pet->GetCharmInfo()->GetPetNumber()); - data << uint32(pet->GetEntry()); - data << uint32(pet->getLevel()); - data << pet->GetName(); // petname - data << uint8(1); // 1 = current, 2/3 = in stable (any from 4, 5, ... create problems with proper show) - ++num; - } - - if (result) - { - do - { - Field* fields = result->Fetch(); - - data << uint32(fields[1].GetUInt32()); // petnumber - data << uint32(fields[2].GetUInt32()); // creature entry - data << uint32(fields[3].GetUInt16()); // level - data << fields[4].GetString(); // name - data << uint8(2); // 1 = current, 2/3 = in stable (any from 4, 5, ... create problems with proper show) - - ++num; - } - while (result->NextRow()); - } - - data.put(wpos, num); // set real data to placeholder - SendPacket(&data); - -} - -void WorldSession::SendStableResult(uint8 res) -{ - WorldPacket data(SMSG_STABLE_RESULT, 1); - data << uint8(res); - SendPacket(&data); -} - -void WorldSession::HandleStablePet(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recv CMSG_STABLE_PET"); - uint64 npcGUID; - - recv_data >> npcGUID; - - if (!GetPlayer()->isAlive()) - { - SendStableResult(STABLE_ERR_STABLE); - return; - } - - if (!CheckStableMaster(npcGUID)) - { - SendStableResult(STABLE_ERR_STABLE); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - Pet* pet = _player->GetPet(); - - // can't place in stable dead pet - if (!pet||!pet->isAlive()||pet->getPetType() != HUNTER_PET) - { - SendStableResult(STABLE_ERR_STABLE); - return; - } - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SLOTS); - - stmt->setUInt32(0, _player->GetGUIDLow()); - stmt->setUInt8(1, PET_SAVE_FIRST_STABLE_SLOT); - stmt->setUInt8(2, PET_SAVE_LAST_STABLE_SLOT); - - _stablePetCallback = CharacterDatabase.AsyncQuery(stmt); -} - -void WorldSession::HandleStablePetCallback(PreparedQueryResult result) -{ - if (!GetPlayer()) - return; - - uint8 freeSlot = 1; - if (result) - { - do - { - Field* fields = result->Fetch(); - - uint8 slot = fields[1].GetUInt8(); - - // slots ordered in query, and if not equal then free - if (slot != freeSlot) - break; - - // this slot not free, skip - ++freeSlot; - } - while (result->NextRow()); - } - - WorldPacket data(SMSG_STABLE_RESULT, 1); - if (freeSlot > 0 && freeSlot <= GetPlayer()->m_stableSlots) - { - _player->RemovePet(_player->GetPet(), PetSaveMode(freeSlot)); - SendStableResult(STABLE_SUCCESS_STABLE); - } - else - SendStableResult(STABLE_ERR_STABLE); -} - -void WorldSession::HandleUnstablePet(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recv CMSG_UNSTABLE_PET."); - uint64 npcGUID; - uint32 petnumber; - - recv_data >> npcGUID >> petnumber; - - if (!CheckStableMaster(npcGUID)) - { - SendStableResult(STABLE_ERR_STABLE); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_ENTRY); - - stmt->setUInt32(0, _player->GetGUIDLow()); - stmt->setUInt32(1, petnumber); - stmt->setUInt8(2, PET_SAVE_FIRST_STABLE_SLOT); - stmt->setUInt8(3, PET_SAVE_LAST_STABLE_SLOT); - - _unstablePetCallback.SetParam(petnumber); - _unstablePetCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); -} - -void WorldSession::HandleUnstablePetCallback(PreparedQueryResult result, uint32 petId) -{ - if (!GetPlayer()) - return; - - uint32 petEntry = 0; - if (result) - { - Field* fields = result->Fetch(); - petEntry = fields[0].GetUInt32(); - } - - if (!petEntry) - { - SendStableResult(STABLE_ERR_STABLE); - return; - } - - CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(petEntry); - if (!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets())) - { - // if problem in exotic pet - if (creatureInfo && creatureInfo->isTameable(true)) - SendStableResult(STABLE_ERR_EXOTIC); - else - SendStableResult(STABLE_ERR_STABLE); - return; - } - - Pet* pet = _player->GetPet(); - if (pet && pet->isAlive()) - { - SendStableResult(STABLE_ERR_STABLE); - return; - } - - // delete dead pet - if (pet) - _player->RemovePet(pet, PET_SAVE_AS_DELETED); - - Pet* newPet = new Pet(_player, HUNTER_PET); - if (!newPet->LoadPetFromDB(_player, petEntry, petId)) - { - delete newPet; - newPet = NULL; - SendStableResult(STABLE_ERR_STABLE); - return; - } - - SendStableResult(STABLE_SUCCESS_UNSTABLE); -} - -void WorldSession::HandleBuyStableSlot(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recv CMSG_BUY_STABLE_SLOT."); - uint64 npcGUID; - - recv_data >> npcGUID; - - if (!CheckStableMaster(npcGUID)) - { - SendStableResult(STABLE_ERR_STABLE); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - if (GetPlayer()->m_stableSlots < MAX_PET_STABLES) - { - StableSlotPricesEntry const* SlotPrice = sStableSlotPricesStore.LookupEntry(GetPlayer()->m_stableSlots+1); - if (_player->HasEnoughMoney(SlotPrice->Price)) - { - ++GetPlayer()->m_stableSlots; - _player->ModifyMoney(-int32(SlotPrice->Price)); - SendStableResult(STABLE_SUCCESS_BUY_SLOT); - } - else - SendStableResult(STABLE_ERR_MONEY); - } - else - SendStableResult(STABLE_ERR_STABLE); -} - -void WorldSession::HandleStableRevivePet(WorldPacket &/* recv_data */) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "HandleStableRevivePet: Not implemented"); -} - -void WorldSession::HandleStableSwapPet(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recv CMSG_STABLE_SWAP_PET."); - uint64 npcGUID; - uint32 petId; - - recv_data >> npcGUID >> petId; - - if (!CheckStableMaster(npcGUID)) - { - SendStableResult(STABLE_ERR_STABLE); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - Pet* pet = _player->GetPet(); - - if (!pet || pet->getPetType() != HUNTER_PET) - { - SendStableResult(STABLE_ERR_STABLE); - return; - } - - // Find swapped pet slot in stable - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SLOT_BY_ID); - - stmt->setUInt32(0, _player->GetGUIDLow()); - stmt->setUInt32(1, petId); - - _stableSwapCallback.SetParam(petId); - _stableSwapCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); -} - -void WorldSession::HandleStableSwapPetCallback(PreparedQueryResult result, uint32 petId) -{ - if (!GetPlayer()) - return; - - if (!result) - { - SendStableResult(STABLE_ERR_STABLE); - return; - } - - Field* fields = result->Fetch(); - - uint32 slot = fields[0].GetUInt8(); - uint32 petEntry = fields[1].GetUInt32(); - - if (!petEntry) - { - SendStableResult(STABLE_ERR_STABLE); - return; - } - - CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(petEntry); - if (!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets())) - { - // if problem in exotic pet - if (creatureInfo && creatureInfo->isTameable(true)) - SendStableResult(STABLE_ERR_EXOTIC); - else - SendStableResult(STABLE_ERR_STABLE); - return; - } - - // move alive pet to slot or delete dead pet - Pet* pet = _player->GetPet(); - - _player->RemovePet(pet, pet->isAlive() ? PetSaveMode(slot) : PET_SAVE_AS_DELETED); - - // summon unstabled pet - Pet* newpet = new Pet(_player); - if (!newpet->LoadPetFromDB(_player, petEntry, petId)) - { - delete newpet; - SendStableResult(STABLE_ERR_STABLE); - } - else - SendStableResult(STABLE_SUCCESS_UNSTABLE); -} - -void WorldSession::HandleRepairItemOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_REPAIR_ITEM"); - - uint64 npcGUID, itemGUID; - uint8 guildBank; // new in 2.3.2, bool that means from guild bank money - - recv_data >> npcGUID >> itemGUID >> guildBank; - - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID, UNIT_NPC_FLAG_REPAIR); - if (!unit) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleRepairItemOpcode - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(npcGUID))); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - // reputation discount - float discountMod = _player->GetReputationPriceDiscount(unit); - - if (itemGUID) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "ITEM: Repair item, itemGUID = %u, npcGUID = %u", GUID_LOPART(itemGUID), GUID_LOPART(npcGUID)); - - Item* item = _player->GetItemByGuid(itemGUID); - if (item) - _player->DurabilityRepair(item->GetPos(), true, discountMod, guildBank); - } - else - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "ITEM: Repair all items, npcGUID = %u", GUID_LOPART(npcGUID)); - _player->DurabilityRepairAll(true, discountMod, guildBank); - } -} - diff --git a/src/server/game/Server/Protocol/Handlers/NPCHandler.h b/src/server/game/Server/Protocol/Handlers/NPCHandler.h deleted file mode 100755 index af84b71a74f..00000000000 --- a/src/server/game/Server/Protocol/Handlers/NPCHandler.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef __NPCHANDLER_H -#define __NPCHANDLER_H - -struct QEmote -{ - uint32 _Emote; - uint32 _Delay; -}; - -#define MAX_GOSSIP_TEXT_EMOTES 3 - -struct GossipTextOption -{ - std::string Text_0; - std::string Text_1; - uint32 Language; - float Probability; - QEmote Emotes[MAX_GOSSIP_TEXT_EMOTES]; -}; - -#define MAX_GOSSIP_TEXT_OPTIONS 8 - -struct GossipText -{ - GossipTextOption Options[MAX_GOSSIP_TEXT_OPTIONS]; -}; - -struct PageTextLocale -{ - StringVector Text; -}; - -struct NpcTextLocale -{ - NpcTextLocale() { Text_0.resize(8); Text_1.resize(8); } - - std::vector Text_0; - std::vector Text_1; -}; -#endif - diff --git a/src/server/game/Server/Protocol/Handlers/PetHandler.cpp b/src/server/game/Server/Protocol/Handlers/PetHandler.cpp deleted file mode 100755 index 68ce3153450..00000000000 --- a/src/server/game/Server/Protocol/Handlers/PetHandler.cpp +++ /dev/null @@ -1,879 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "ObjectMgr.h" -#include "SpellMgr.h" -#include "Log.h" -#include "Opcodes.h" -#include "Spell.h" -#include "ObjectAccessor.h" -#include "CreatureAI.h" -#include "Util.h" -#include "Pet.h" -#include "World.h" -#include "Group.h" -#include "SpellInfo.h" - -void WorldSession::HandleDismissCritter(WorldPacket &recv_data) -{ - uint64 guid; - recv_data >> guid; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_DISMISS_CRITTER for GUID " UI64FMTD, guid); - - Unit* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); - - if (!pet) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "Vanitypet (guid: %u) does not exist - player '%s' (guid: %u / account: %u) attempted to dismiss it (possibly lagged out)", - uint32(GUID_LOPART(guid)), GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), GetAccountId()); - return; - } - - if (_player->GetCritterGUID() == pet->GetGUID()) - { - if (pet->GetTypeId() == TYPEID_UNIT && pet->ToCreature()->isSummon()) - pet->ToTempSummon()->UnSummon(); - } -} - -void WorldSession::HandlePetAction(WorldPacket & recv_data) -{ - uint64 guid1; - uint32 data; - uint64 guid2; - recv_data >> guid1; //pet guid - recv_data >> data; - recv_data >> guid2; //tag guid - - uint32 spellid = UNIT_ACTION_BUTTON_ACTION(data); - uint8 flag = UNIT_ACTION_BUTTON_TYPE(data); //delete = 0x07 CastSpell = C1 - - // used also for charmed creature - Unit* pet= ObjectAccessor::GetUnit(*_player, guid1); - sLog->outDetail("HandlePetAction: Pet %u - flag: %u, spellid: %u, target: %u.", uint32(GUID_LOPART(guid1)), uint32(flag), spellid, uint32(GUID_LOPART(guid2))); - - if (!pet) - { - sLog->outError("HandlePetAction: Pet (GUID: %u) doesn't exist for player '%s'", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName()); - return; - } - - if (pet != GetPlayer()->GetFirstControlled()) - { - sLog->outError("HandlePetAction: Pet (GUID: %u) does not belong to player '%s'", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName()); - return; - } - - if (!pet->isAlive()) - { - SpellInfo const* spell = (flag == ACT_ENABLED || flag == ACT_PASSIVE) ? sSpellMgr->GetSpellInfo(spellid) : NULL; - if (!spell) - return; - if (!(spell->Attributes & SPELL_ATTR0_CASTABLE_WHILE_DEAD)) - return; - } - - //TODO: allow control charmed player? - if (pet->GetTypeId() == TYPEID_PLAYER && !(flag == ACT_COMMAND && spellid == COMMAND_ATTACK)) - return; - - if (GetPlayer()->m_Controlled.size() == 1) - HandlePetActionHelper(pet, guid1, spellid, flag, guid2); - else - { - //If a pet is dismissed, m_Controlled will change - std::vector controlled; - for (Unit::ControlList::iterator itr = GetPlayer()->m_Controlled.begin(); itr != GetPlayer()->m_Controlled.end(); ++itr) - if ((*itr)->GetEntry() == pet->GetEntry() && (*itr)->isAlive()) - controlled.push_back(*itr); - for (std::vector::iterator itr = controlled.begin(); itr != controlled.end(); ++itr) - HandlePetActionHelper(*itr, guid1, spellid, flag, guid2); - } -} - -void WorldSession::HandlePetStopAttack(WorldPacket &recv_data) -{ - uint64 guid; - recv_data >> guid; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_PET_STOP_ATTACK for GUID " UI64FMTD "", guid); - - Unit* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); - - if (!pet) - { - sLog->outError("HandlePetStopAttack: Pet %u does not exist", uint32(GUID_LOPART(guid))); - return; - } - - if (pet != GetPlayer()->GetPet() && pet != GetPlayer()->GetCharm()) - { - sLog->outError("HandlePetStopAttack: Pet GUID %u isn't a pet or charmed creature of player %s", uint32(GUID_LOPART(guid)), GetPlayer()->GetName()); - return; - } - - if (!pet->isAlive()) - return; - - pet->AttackStop(); -} - -void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint16 spellid, uint16 flag, uint64 guid2) -{ - CharmInfo* charmInfo = pet->GetCharmInfo(); - if (!charmInfo) - { - sLog->outError("WorldSession::HandlePetAction(petGuid: " UI64FMTD ", tagGuid: " UI64FMTD ", spellId: %u, flag: %u): object (entry: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", - guid1, guid2, spellid, flag, pet->GetGUIDLow(), pet->GetTypeId()); - return; - } - - switch (flag) - { - case ACT_COMMAND: //0x07 - switch (spellid) - { - case COMMAND_STAY: //flat=1792 //STAY - pet->AttackStop(); - pet->InterruptNonMeleeSpells(false); - pet->GetMotionMaster()->Clear(false); - pet->GetMotionMaster()->MoveIdle(); - charmInfo->SetCommandState(COMMAND_STAY); - - charmInfo->SetIsCommandAttack(false); - charmInfo->SetIsAtStay(true); - charmInfo->SetIsFollowing(false); - charmInfo->SetIsReturning(false); - charmInfo->SaveStayPosition(); - break; - case COMMAND_FOLLOW: //spellid=1792 //FOLLOW - pet->AttackStop(); - pet->InterruptNonMeleeSpells(false); - pet->GetMotionMaster()->MoveFollow(_player, PET_FOLLOW_DIST, pet->GetFollowAngle()); - charmInfo->SetCommandState(COMMAND_FOLLOW); - - charmInfo->SetIsCommandAttack(false); - charmInfo->SetIsAtStay(false); - charmInfo->SetIsReturning(true); - charmInfo->SetIsFollowing(false); - break; - case COMMAND_ATTACK: //spellid=1792 //ATTACK - { - // Can't attack if owner is pacified - if (_player->HasAuraType(SPELL_AURA_MOD_PACIFY)) - { - //pet->SendPetCastFail(spellid, SPELL_FAILED_PACIFIED); - //TODO: Send proper error message to client - return; - } - - // only place where pet can be player - Unit* TargetUnit = ObjectAccessor::GetUnit(*_player, guid2); - if (!TargetUnit) - return; - - if (Unit* owner = pet->GetOwner()) - if (!owner->IsValidAttackTarget(TargetUnit)) - return; - - // Not let attack through obstructions - if (sWorld->getBoolConfig(CONFIG_PET_LOS)) - { - if (!pet->IsWithinLOSInMap(TargetUnit)) - return; - } - - pet->ClearUnitState(UNIT_STAT_FOLLOW); - // This is true if pet has no target or has target but targets differs. - if (pet->getVictim() != TargetUnit || (pet->getVictim() == TargetUnit && !pet->GetCharmInfo()->IsCommandAttack())) - { - if (pet->getVictim()) - pet->AttackStop(); - - if (pet->GetTypeId() != TYPEID_PLAYER && pet->ToCreature()->IsAIEnabled) - { - charmInfo->SetIsCommandAttack(true); - charmInfo->SetIsAtStay(false); - charmInfo->SetIsFollowing(false); - charmInfo->SetIsReturning(false); - - pet->ToCreature()->AI()->AttackStart(TargetUnit); - - //10% chance to play special pet attack talk, else growl - if (pet->ToCreature()->isPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != TargetUnit && urand(0, 100) < 10) - pet->SendPetTalk((uint32)PET_TALK_ATTACK); - else - { - // 90% chance for pet and 100% chance for charmed creature - pet->SendPetAIReaction(guid1); - } - } - else // charmed player - { - if (pet->getVictim() && pet->getVictim() != TargetUnit) - pet->AttackStop(); - - charmInfo->SetIsCommandAttack(true); - charmInfo->SetIsAtStay(false); - charmInfo->SetIsFollowing(false); - charmInfo->SetIsReturning(false); - - pet->Attack(TargetUnit, true); - pet->SendPetAIReaction(guid1); - } - } - break; - } - case COMMAND_ABANDON: // abandon (hunter pet) or dismiss (summoned pet) - if (pet->GetCharmerGUID() == GetPlayer()->GetGUID()) - _player->StopCastingCharm(); - else if (pet->GetOwnerGUID() == GetPlayer()->GetGUID()) - { - ASSERT(pet->GetTypeId() == TYPEID_UNIT); - if (pet->isPet()) - { - if (((Pet*)pet)->getPetType() == HUNTER_PET) - GetPlayer()->RemovePet((Pet*)pet, PET_SAVE_AS_DELETED); - else - //dismissing a summoned pet is like killing them (this prevents returning a soulshard...) - pet->setDeathState(CORPSE); - } - else if (pet->HasUnitTypeMask(UNIT_MASK_MINION)) - { - ((Minion*)pet)->UnSummon(); - } - } - break; - default: - sLog->outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid); - } - break; - case ACT_REACTION: // 0x6 - switch (spellid) - { - case REACT_PASSIVE: //passive - pet->AttackStop(); - - case REACT_DEFENSIVE: //recovery - case REACT_AGGRESSIVE: //activete - if (pet->GetTypeId() == TYPEID_UNIT) - pet->ToCreature()->SetReactState(ReactStates(spellid)); - break; - } - break; - case ACT_DISABLED: // 0x81 spell (disabled), ignore - case ACT_PASSIVE: // 0x01 - case ACT_ENABLED: // 0xC1 spell - { - Unit* unit_target = NULL; - - if (guid2) - unit_target = ObjectAccessor::GetUnit(*_player, guid2); - - // do not cast unknown spells - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid); - if (!spellInfo) - { - sLog->outError("WORLD: unknown PET spell id %i", spellid); - return; - } - - if (spellInfo->StartRecoveryCategory > 0) - if (pet->GetCharmInfo() && pet->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) - return; - - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (spellInfo->Effects[i].TargetA.GetTarget() == TARGET_UNIT_SRC_AREA_ENEMY || spellInfo->Effects[i].TargetA.GetTarget() == TARGET_UNIT_DEST_AREA_ENEMY || spellInfo->Effects[i].TargetA.GetTarget() == TARGET_DEST_DYNOBJ_ENEMY) - return; - } - - // do not cast not learned spells - if (!pet->HasSpell(spellid) || spellInfo->IsPassive()) - return; - - // Clear the flags as if owner clicked 'attack'. AI will reset them - // after AttackStart, even if spell failed - if (pet->GetCharmInfo()) - { - pet->GetCharmInfo()->SetIsAtStay(false); - pet->GetCharmInfo()->SetIsCommandAttack(true); - pet->GetCharmInfo()->SetIsReturning(false); - pet->GetCharmInfo()->SetIsFollowing(false); - } - - Spell* spell = new Spell(pet, spellInfo, TRIGGERED_NONE); - - SpellCastResult result = spell->CheckPetCast(unit_target); - - //auto turn to target unless possessed - if (result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->isPossessed() && !pet->IsVehicle()) - { - if (unit_target) - { - pet->SetInFront(unit_target); - if (unit_target->GetTypeId() == TYPEID_PLAYER) - pet->SendUpdateToPlayer((Player*)unit_target); - } - else if (Unit* unit_target2 = spell->m_targets.GetUnitTarget()) - { - pet->SetInFront(unit_target2); - if (unit_target2->GetTypeId() == TYPEID_PLAYER) - pet->SendUpdateToPlayer((Player*)unit_target2); - } - if (Unit* powner = pet->GetCharmerOrOwner()) - if (powner->GetTypeId() == TYPEID_PLAYER) - pet->SendUpdateToPlayer(powner->ToPlayer()); - result = SPELL_CAST_OK; - } - - if (result == SPELL_CAST_OK) - { - pet->ToCreature()->AddCreatureSpellCooldown(spellid); - - unit_target = spell->m_targets.GetUnitTarget(); - - //10% chance to play special pet attack talk, else growl - //actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell - if (pet->ToCreature()->isPet() && (((Pet*)pet)->getPetType() == SUMMON_PET) && (pet != unit_target) && (urand(0, 100) < 10)) - pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL); - else - { - pet->SendPetAIReaction(guid1); - } - - if (unit_target && !GetPlayer()->IsFriendlyTo(unit_target) && !pet->isPossessed() && !pet->IsVehicle()) - { - // This is true if pet has no target or has target but targets differs. - if (pet->getVictim() != unit_target) - { - if (pet->getVictim()) - pet->AttackStop(); - pet->GetMotionMaster()->Clear(); - if (pet->ToCreature()->IsAIEnabled) - pet->ToCreature()->AI()->AttackStart(unit_target); - } - } - - spell->prepare(&(spell->m_targets)); - } - else - { - if (pet->isPossessed() || pet->IsVehicle()) - Spell::SendCastResult(GetPlayer(), spellInfo, 0, result); - else - pet->SendPetCastFail(spellid, result); - - if (!pet->ToCreature()->HasSpellCooldown(spellid)) - GetPlayer()->SendClearCooldown(spellid, pet); - - spell->finish(false); - delete spell; - - // reset specific flags in case of spell fail. AI will reset other flags - if (pet->GetCharmInfo()) - pet->GetCharmInfo()->SetIsCommandAttack(false); - } - break; - } - default: - sLog->outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid); - } -} - -void WorldSession::HandlePetNameQuery(WorldPacket & recv_data) -{ - sLog->outDetail("HandlePetNameQuery. CMSG_PET_NAME_QUERY"); - - uint32 petnumber; - uint64 petguid; - - recv_data >> petnumber; - recv_data >> petguid; - - SendPetNameQuery(petguid, petnumber); -} - -void WorldSession::SendPetNameQuery(uint64 petguid, uint32 petnumber) -{ - Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, petguid); - if (!pet) - { - WorldPacket data(SMSG_PET_NAME_QUERY_RESPONSE, (4+1+4+1)); - data << uint32(petnumber); - data << uint8(0); - data << uint32(0); - data << uint8(0); - _player->GetSession()->SendPacket(&data); - return; - } - - std::string name = pet->GetName(); - - WorldPacket data(SMSG_PET_NAME_QUERY_RESPONSE, (4+4+name.size()+1)); - data << uint32(petnumber); - data << name.c_str(); - data << uint32(pet->GetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP)); - - if (pet->isPet() && ((Pet*)pet)->GetDeclinedNames()) - { - data << uint8(1); - for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) - data << ((Pet*)pet)->GetDeclinedNames()->name[i]; - } - else - data << uint8(0); - - _player->GetSession()->SendPacket(&data); -} - -bool WorldSession::CheckStableMaster(uint64 guid) -{ - // spell case or GM - if (guid == GetPlayer()->GetGUID()) - { - if (!GetPlayer()->isGameMaster() && !GetPlayer()->HasAuraType(SPELL_AURA_OPEN_STABLE)) - { - sLog->outStaticDebug("Player (GUID:%u) attempt open stable in cheating way.", GUID_LOPART(guid)); - return false; - } - } - // stable master case - else - { - if (!GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_STABLEMASTER)) - { - sLog->outStaticDebug("Stablemaster (GUID:%u) not found or you can't interact with him.", GUID_LOPART(guid)); - return false; - } - } - return true; -} - -void WorldSession::HandlePetSetAction(WorldPacket & recv_data) -{ - sLog->outDetail("HandlePetSetAction. CMSG_PET_SET_ACTION"); - - uint64 petguid; - uint8 count; - - recv_data >> petguid; - - Unit* pet = ObjectAccessor::GetUnit(*_player, petguid); - - if (!pet || pet != _player->GetFirstControlled()) - { - sLog->outError("HandlePetSetAction: Unknown pet (GUID: %u) or pet owner (GUID: %u)", GUID_LOPART(petguid), _player->GetGUIDLow()); - return; - } - - CharmInfo* charmInfo = pet->GetCharmInfo(); - if (!charmInfo) - { - sLog->outError("WorldSession::HandlePetSetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId()); - return; - } - - count = (recv_data.size() == 24) ? 2 : 1; - - uint32 position[2]; - uint32 data[2]; - bool move_command = false; - - for (uint8 i = 0; i < count; ++i) - { - recv_data >> position[i]; - recv_data >> data[i]; - - uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data[i]); - - //ignore invalid position - if (position[i] >= MAX_UNIT_ACTION_BAR_INDEX) - return; - - // in the normal case, command and reaction buttons can only be moved, not removed - // at moving count == 2, at removing count == 1 - // ignore attempt to remove command|reaction buttons (not possible at normal case) - if (act_state == ACT_COMMAND || act_state == ACT_REACTION) - { - if (count == 1) - return; - - move_command = true; - } - } - - // check swap (at command->spell swap client remove spell first in another packet, so check only command move correctness) - if (move_command) - { - uint8 act_state_0 = UNIT_ACTION_BUTTON_TYPE(data[0]); - if (act_state_0 == ACT_COMMAND || act_state_0 == ACT_REACTION) - { - uint32 spell_id_0 = UNIT_ACTION_BUTTON_ACTION(data[0]); - UnitActionBarEntry const* actionEntry_1 = charmInfo->GetActionBarEntry(position[1]); - if (!actionEntry_1 || spell_id_0 != actionEntry_1->GetAction() || - act_state_0 != actionEntry_1->GetType()) - return; - } - - uint8 act_state_1 = UNIT_ACTION_BUTTON_TYPE(data[1]); - if (act_state_1 == ACT_COMMAND || act_state_1 == ACT_REACTION) - { - uint32 spell_id_1 = UNIT_ACTION_BUTTON_ACTION(data[1]); - UnitActionBarEntry const* actionEntry_0 = charmInfo->GetActionBarEntry(position[0]); - if (!actionEntry_0 || spell_id_1 != actionEntry_0->GetAction() || - act_state_1 != actionEntry_0->GetType()) - return; - } - } - - for (uint8 i = 0; i < count; ++i) - { - uint32 spell_id = UNIT_ACTION_BUTTON_ACTION(data[i]); - uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data[i]); - - sLog->outDetail("Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), position[i], spell_id, uint32(act_state)); - - //if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add - if (!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_PASSIVE) && spell_id && !pet->HasSpell(spell_id))) - { - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id)) - { - //sign for autocast - if (act_state == ACT_ENABLED) - { - if (pet->GetTypeId() == TYPEID_UNIT && pet->ToCreature()->isPet()) - ((Pet*)pet)->ToggleAutocast(spellInfo, true); - else - for (Unit::ControlList::iterator itr = GetPlayer()->m_Controlled.begin(); itr != GetPlayer()->m_Controlled.end(); ++itr) - if ((*itr)->GetEntry() == pet->GetEntry()) - (*itr)->GetCharmInfo()->ToggleCreatureAutocast(spellInfo, true); - } - //sign for no/turn off autocast - else if (act_state == ACT_DISABLED) - { - if (pet->GetTypeId() == TYPEID_UNIT && pet->ToCreature()->isPet()) - ((Pet*)pet)->ToggleAutocast(spellInfo, false); - else - for (Unit::ControlList::iterator itr = GetPlayer()->m_Controlled.begin(); itr != GetPlayer()->m_Controlled.end(); ++itr) - if ((*itr)->GetEntry() == pet->GetEntry()) - (*itr)->GetCharmInfo()->ToggleCreatureAutocast(spellInfo, false); - } - } - - charmInfo->SetActionBar(position[i], spell_id, ActiveStates(act_state)); - } - } -} - -void WorldSession::HandlePetRename(WorldPacket & recv_data) -{ - sLog->outDetail("HandlePetRename. CMSG_PET_RENAME"); - - uint64 petguid; - uint8 isdeclined; - - std::string name; - DeclinedName declinedname; - - recv_data >> petguid; - recv_data >> name; - recv_data >> isdeclined; - - Pet* pet = ObjectAccessor::FindPet(petguid); - // check it! - if (!pet || !pet->isPet() || ((Pet*)pet)->getPetType()!= HUNTER_PET || - !pet->HasByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED) || - pet->GetOwnerGUID() != _player->GetGUID() || !pet->GetCharmInfo()) - return; - - PetNameInvalidReason res = ObjectMgr::CheckPetName(name); - if (res != PET_NAME_SUCCESS) - { - SendPetNameInvalid(res, name, NULL); - return; - } - - if (sObjectMgr->IsReservedName(name)) - { - SendPetNameInvalid(PET_NAME_RESERVED, name, NULL); - return; - } - - pet->SetName(name); - - Unit* owner = pet->GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup()) - owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_NAME); - - pet->RemoveByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED); - - if (isdeclined) - { - for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) - { - recv_data >> declinedname.name[i]; - } - - std::wstring wname; - Utf8toWStr(name, wname); - if (!ObjectMgr::CheckDeclinedNames(wname, declinedname)) - { - SendPetNameInvalid(PET_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME, name, &declinedname); - return; - } - } - - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - if (isdeclined) - { - for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) - CharacterDatabase.EscapeString(declinedname.name[i]); - trans->PAppend("DELETE FROM character_pet_declinedname WHERE owner = '%u' AND id = '%u'", _player->GetGUIDLow(), pet->GetCharmInfo()->GetPetNumber()); - trans->PAppend("INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES ('%u', '%u', '%s', '%s', '%s', '%s', '%s')", - pet->GetCharmInfo()->GetPetNumber(), _player->GetGUIDLow(), declinedname.name[0].c_str(), declinedname.name[1].c_str(), declinedname.name[2].c_str(), declinedname.name[3].c_str(), declinedname.name[4].c_str()); - } - - CharacterDatabase.EscapeString(name); - trans->PAppend("UPDATE character_pet SET name = '%s', renamed = '1' WHERE owner = '%u' AND id = '%u'", name.c_str(), _player->GetGUIDLow(), pet->GetCharmInfo()->GetPetNumber()); - CharacterDatabase.CommitTransaction(trans); - - pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(NULL))); // cast can't be helped -} - -void WorldSession::HandlePetAbandon(WorldPacket & recv_data) -{ - uint64 guid; - recv_data >> guid; //pet guid - sLog->outDetail("HandlePetAbandon. CMSG_PET_ABANDON pet guid is %u", GUID_LOPART(guid)); - - if (!_player->IsInWorld()) - return; - - // pet/charmed - Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); - if (pet) - { - if (pet->isPet()) - { - if (pet->GetGUID() == _player->GetPetGUID()) - { - uint32 feelty = pet->GetPower(POWER_HAPPINESS); - pet->SetPower(POWER_HAPPINESS, feelty > 50000 ? (feelty-50000) : 0); - } - - _player->RemovePet((Pet*)pet, PET_SAVE_AS_DELETED); - } - else if (pet->GetGUID() == _player->GetCharmGUID()) - _player->StopCastingCharm(); - } -} - -void WorldSession::HandlePetSpellAutocastOpcode(WorldPacket& recvPacket) -{ - sLog->outDetail("CMSG_PET_SPELL_AUTOCAST"); - uint64 guid; - uint32 spellid; - uint8 state; //1 for on, 0 for off - recvPacket >> guid >> spellid >> state; - - if (!_player->GetGuardianPet() && !_player->GetCharm()) - return; - - if (ObjectAccessor::FindPlayer(guid)) - return; - - Creature* pet=ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); - - if (!pet || (pet != _player->GetGuardianPet() && pet != _player->GetCharm())) - { - sLog->outError("HandlePetSpellAutocastOpcode.Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)), GetPlayer()->GetName()); - return; - } - - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid); - // do not add not learned spells/ passive spells - if (!pet->HasSpell(spellid) || spellInfo->IsAutocastable()) - return; - - CharmInfo* charmInfo = pet->GetCharmInfo(); - if (!charmInfo) - { - sLog->outError("WorldSession::HandlePetSpellAutocastOpcod: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId()); - return; - } - - if (pet->isPet()) - ((Pet*)pet)->ToggleAutocast(spellInfo, state); - else - pet->GetCharmInfo()->ToggleCreatureAutocast(spellInfo, state); - - charmInfo->SetSpellAutocast(spellInfo, state); -} - -void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket) -{ - sLog->outDetail("WORLD: CMSG_PET_CAST_SPELL"); - - uint64 guid; - uint8 castCount; - uint32 spellId; - uint8 castFlags; - - recvPacket >> guid >> castCount >> spellId >> castFlags; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_PET_CAST_SPELL, guid: " UI64FMTD ", castCount: %u, spellId %u, castFlags %u", guid, castCount, spellId, castFlags); - - // This opcode is also sent from charmed and possessed units (players and creatures) - if (!_player->GetGuardianPet() && !_player->GetCharm()) - return; - - Unit* caster = ObjectAccessor::GetUnit(*_player, guid); - - if (!caster || (caster != _player->GetGuardianPet() && caster != _player->GetCharm())) - { - sLog->outError("HandlePetCastSpellOpcode: Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)), GetPlayer()->GetName()); - return; - } - - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); - if (!spellInfo) - { - sLog->outError("WORLD: unknown PET spell id %i", spellId); - return; - } - - if (spellInfo->StartRecoveryCategory > 0) // Check if spell is affected by GCD - if (caster->GetTypeId() == TYPEID_UNIT && caster->GetCharmInfo() && caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) - { - caster->SendPetCastFail(spellId, SPELL_FAILED_NOT_READY); - return; - } - - // do not cast not learned spells - if (!caster->HasSpell(spellId) || spellInfo->IsPassive()) - return; - - SpellCastTargets targets; - targets.Read(recvPacket, caster); - HandleClientCastFlags(recvPacket, castFlags, targets); - - caster->ClearUnitState(UNIT_STAT_FOLLOW); - - Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE); - spell->m_cast_count = castCount; // probably pending spell cast - spell->m_targets = targets; - - // TODO: need to check victim? - SpellCastResult result; - if (caster->m_movedPlayer) - result = spell->CheckPetCast(caster->m_movedPlayer->GetSelectedUnit()); - else - result = spell->CheckPetCast(NULL); - if (result == SPELL_CAST_OK) - { - if (caster->GetTypeId() == TYPEID_UNIT) - { - Creature* pet = caster->ToCreature(); - pet->AddCreatureSpellCooldown(spellId); - if (pet->isPet()) - { - Pet* p = (Pet*)pet; - // 10% chance to play special pet attack talk, else growl - // actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell - if (p->getPetType() == SUMMON_PET && (urand(0, 100) < 10)) - pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL); - else - pet->SendPetAIReaction(guid); - } - } - - spell->prepare(&(spell->m_targets)); - } - else - { - caster->SendPetCastFail(spellId, result); - if (caster->GetTypeId() == TYPEID_PLAYER) - { - if (!caster->ToPlayer()->HasSpellCooldown(spellId)) - GetPlayer()->SendClearCooldown(spellId, caster); - } - else - { - if (!caster->ToCreature()->HasSpellCooldown(spellId)) - GetPlayer()->SendClearCooldown(spellId, caster); - } - - spell->finish(false); - delete spell; - } -} - -void WorldSession::SendPetNameInvalid(uint32 error, const std::string& name, DeclinedName *declinedName) -{ - WorldPacket data(SMSG_PET_NAME_INVALID, 4 + name.size() + 1 + 1); - data << uint32(error); - data << name; - if (declinedName) - { - data << uint8(1); - for (uint32 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) - data << declinedName->name[i]; - } - else - data << uint8(0); - SendPacket(&data); -} - -void WorldSession::HandlePetLearnTalent(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_PET_LEARN_TALENT"); - - uint64 guid; - uint32 talent_id, requested_rank; - recv_data >> guid >> talent_id >> requested_rank; - - _player->LearnPetTalent(guid, talent_id, requested_rank); - _player->SendTalentsInfoData(true); -} - -void WorldSession::HandleLearnPreviewTalentsPet(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LEARN_PREVIEW_TALENTS_PET"); - - uint64 guid; - recv_data >> guid; - - uint32 talentsCount; - recv_data >> talentsCount; - - uint32 talentId, talentRank; - - for (uint32 i = 0; i < talentsCount; ++i) - { - recv_data >> talentId >> talentRank; - - _player->LearnPetTalent(guid, talentId, talentRank); - } - - _player->SendTalentsInfoData(true); -} diff --git a/src/server/game/Server/Protocol/Handlers/PetitionsHandler.cpp b/src/server/game/Server/Protocol/Handlers/PetitionsHandler.cpp deleted file mode 100755 index 26185d3376d..00000000000 --- a/src/server/game/Server/Protocol/Handlers/PetitionsHandler.cpp +++ /dev/null @@ -1,937 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "Language.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "World.h" -#include "ObjectMgr.h" -#include "ArenaTeamMgr.h" -#include "GuildMgr.h" -#include "Log.h" -#include "Opcodes.h" -#include "Guild.h" -#include "ArenaTeam.h" -#include "GossipDef.h" -#include "SocialMgr.h" - -#define CHARTER_DISPLAY_ID 16161 - -/*enum PetitionType // dbc data -{ - PETITION_TYPE_GUILD = 1, - PETITION_TYPE_ARENA_TEAM = 3 -};*/ - -// Charters ID in item_template -enum CharterItemIDs -{ - GUILD_CHARTER = 5863, - ARENA_TEAM_CHARTER_2v2 = 23560, - ARENA_TEAM_CHARTER_3v3 = 23561, - ARENA_TEAM_CHARTER_5v5 = 23562 -}; - -enum CharterCosts -{ - GUILD_CHARTER_COST = 1000, - ARENA_TEAM_CHARTER_2v2_COST = 800000, - ARENA_TEAM_CHARTER_3v3_COST = 1200000, - ARENA_TEAM_CHARTER_5v5_COST = 2000000 -}; - -void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode CMSG_PETITION_BUY"); - - uint64 guidNPC; - uint32 clientIndex; // 1 for guild and arenaslot+1 for arenas in client - std::string name; - - recv_data >> guidNPC; // NPC GUID - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - recv_data >> name; // name - recv_data.read_skip(); // some string - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - recv_data.read_skip(); // 0 - - for (int i = 0; i < 10; ++i) - recv_data.read_skip(); - - recv_data >> clientIndex; // index - recv_data.read_skip(); // 0 - - sLog->outDebug(LOG_FILTER_NETWORKIO, "Petitioner with GUID %u tried sell petition: name %s", GUID_LOPART(guidNPC), name.c_str()); - - // prevent cheating - Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guidNPC, UNIT_NPC_FLAG_PETITIONER); - if (!creature) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandlePetitionBuyOpcode - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(guidNPC)); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - uint32 charterid = 0; - uint32 cost = 0; - uint32 type = 0; - if (creature->isTabardDesigner()) - { - // if tabard designer, then trying to buy a guild charter. - // do not let if already in guild. - if (_player->GetGuildId()) - return; - - charterid = GUILD_CHARTER; - cost = GUILD_CHARTER_COST; - type = GUILD_CHARTER_TYPE; - } - else - { - // TODO: find correct opcode - if (_player->getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - SendNotification(LANG_ARENA_ONE_TOOLOW, sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)); - return; - } - - switch (clientIndex) // arenaSlot+1 as received from client (1 from 3 case) - { - case 1: - charterid = ARENA_TEAM_CHARTER_2v2; - cost = ARENA_TEAM_CHARTER_2v2_COST; - type = ARENA_TEAM_CHARTER_2v2_TYPE; - break; - case 2: - charterid = ARENA_TEAM_CHARTER_3v3; - cost = ARENA_TEAM_CHARTER_3v3_COST; - type = ARENA_TEAM_CHARTER_3v3_TYPE; - break; - case 3: - charterid = ARENA_TEAM_CHARTER_5v5; - cost = ARENA_TEAM_CHARTER_5v5_COST; - type = ARENA_TEAM_CHARTER_5v5_TYPE; - break; - default: - sLog->outDebug(LOG_FILTER_NETWORKIO, "unknown selection at buy arena petition: %u", clientIndex); - return; - } - - if (_player->GetArenaTeamId(clientIndex - 1)) // arenaSlot+1 as received from client - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM); - return; - } - } - - if (type == GUILD_CHARTER_TYPE) - { - if (sGuildMgr->GetGuildByName(name)) - { - Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NAME_EXISTS_S, name); - return; - } - if (sObjectMgr->IsReservedName(name) || !ObjectMgr::IsValidCharterName(name)) - { - Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NAME_INVALID, name); - return; - } - } - else - { - if (sArenaTeamMgr->GetArenaTeamByName(name)) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S); - return; - } - if (sObjectMgr->IsReservedName(name) || !ObjectMgr::IsValidCharterName(name)) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_INVALID); - return; - } - } - - ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(charterid); - if (!pProto) - { - _player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, NULL, charterid, 0); - return; - } - - if (!_player->HasEnoughMoney(cost)) - { //player hasn't got enough money - _player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, creature, charterid, 0); - return; - } - - ItemPosCountVec dest; - InventoryResult msg = _player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, charterid, pProto->BuyCount); - if (msg != EQUIP_ERR_OK) - { - _player->SendEquipError(msg, NULL, NULL, charterid); - return; - } - - _player->ModifyMoney(-(int32)cost); - Item* charter = _player->StoreNewItem(dest, charterid, true); - if (!charter) - return; - - charter->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1, charter->GetGUIDLow()); - // ITEM_FIELD_ENCHANTMENT_1_1 is guild/arenateam id - // ITEM_FIELD_ENCHANTMENT_1_1+1 is current signatures count (showed on item) - charter->SetState(ITEM_CHANGED, _player); - _player->SendNewItem(charter, 1, true, false); - - // a petition is invalid, if both the owner and the type matches - // we checked above, if this player is in an arenateam, so this must be - // datacorruption - QueryResult result = CharacterDatabase.PQuery("SELECT petitionguid FROM petition WHERE ownerguid = '%u' AND type = '%u'", _player->GetGUIDLow(), type); - - std::ostringstream ssInvalidPetitionGUIDs; - - if (result) - { - do - { - Field* fields = result->Fetch(); - ssInvalidPetitionGUIDs << '\'' << fields[0].GetUInt32() << "', "; - } while (result->NextRow()); - } - - // delete petitions with the same guid as this one - ssInvalidPetitionGUIDs << '\'' << charter->GetGUIDLow() << '\''; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "Invalid petition GUIDs: %s", ssInvalidPetitionGUIDs.str().c_str()); - CharacterDatabase.EscapeString(name); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - trans->PAppend("DELETE FROM petition WHERE petitionguid IN (%s)", ssInvalidPetitionGUIDs.str().c_str()); - trans->PAppend("DELETE FROM petition_sign WHERE petitionguid IN (%s)", ssInvalidPetitionGUIDs.str().c_str()); - trans->PAppend("INSERT INTO petition (ownerguid, petitionguid, name, type) VALUES ('%u', '%u', '%s', '%u')", - _player->GetGUIDLow(), charter->GetGUIDLow(), name.c_str(), type); - CharacterDatabase.CommitTransaction(trans); -} - -void WorldSession::HandlePetitionShowSignOpcode(WorldPacket & recv_data) -{ - // ok - sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode CMSG_PETITION_SHOW_SIGNATURES"); - - uint8 signs = 0; - uint64 petitionguid; - recv_data >> petitionguid; // petition guid - - // solve (possible) some strange compile problems with explicit use GUID_LOPART(petitionguid) at some GCC versions (wrong code optimization in compiler?) - uint32 petitionguid_low = GUID_LOPART(petitionguid); - - QueryResult result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", petitionguid_low); - if (!result) - { - sLog->outError("Petition %u is not found for player %u %s", GUID_LOPART(petitionguid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName()); - return; - } - Field* fields = result->Fetch(); - uint32 type = fields[0].GetUInt8(); - - // if guild petition and has guild => error, return; - if (type == GUILD_CHARTER_TYPE && _player->GetGuildId()) - return; - - result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", petitionguid_low); - - // result == NULL also correct in case no sign yet - if (result) - signs = uint8(result->GetRowCount()); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_PETITION_SHOW_SIGNATURES petition entry: '%u'", petitionguid_low); - - WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (8+8+4+1+signs*12)); - data << uint64(petitionguid); // petition guid - data << uint64(_player->GetGUID()); // owner guid - data << uint32(petitionguid_low); // guild guid - data << uint8(signs); // sign's count - - for (uint8 i = 1; i <= signs; ++i) - { - Field* fields2 = result->Fetch(); - uint64 plguid = fields2[0].GetUInt64(); - - data << uint64(plguid); // Player GUID - data << uint32(0); // there 0 ... - - result->NextRow(); - } - SendPacket(&data); -} - -void WorldSession::HandlePetitionQueryOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode CMSG_PETITION_QUERY"); // ok - - uint32 guildguid; - uint64 petitionguid; - recv_data >> guildguid; // in Trinity always same as GUID_LOPART(petitionguid) - recv_data >> petitionguid; // petition guid - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_PETITION_QUERY Petition GUID %u Guild GUID %u", GUID_LOPART(petitionguid), guildguid); - - SendPetitionQueryOpcode(petitionguid); -} - -void WorldSession::SendPetitionQueryOpcode(uint64 petitionguid) -{ - uint64 ownerguid = 0; - uint32 type; - std::string name = "NO_NAME_FOR_GUID"; - - // TODO: Use CHAR_LOAD_PETITION PS - QueryResult result = CharacterDatabase.PQuery("SELECT ownerguid, name, type " - "FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); - - if (result) - { - Field* fields = result->Fetch(); - ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); - name = fields[1].GetString(); - type = fields[2].GetUInt32(); - } - else - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid)); - return; - } - - WorldPacket data(SMSG_PETITION_QUERY_RESPONSE, (4+8+name.size()+1+1+4*12+2+10)); - data << uint32(GUID_LOPART(petitionguid)); // guild/team guid (in Trinity always same as GUID_LOPART(petition guid) - data << uint64(ownerguid); // charter owner guid - data << name; // name (guild/arena team) - data << uint8(0); // some string - if (type == GUILD_CHARTER_TYPE) - { - data << uint32(9); - data << uint32(9); - data << uint32(0); // bypass client - side limitation, a different value is needed here for each petition - } - else - { - data << uint32(type-1); - data << uint32(type-1); - data << uint32(type); // bypass client - side limitation, a different value is needed here for each petition - } - data << uint32(0); // 5 - data << uint32(0); // 6 - data << uint32(0); // 7 - data << uint32(0); // 8 - data << uint16(0); // 9 2 bytes field - data << uint32(0); // 10 - data << uint32(0); // 11 - data << uint32(0); // 13 count of next strings? - - for (int i = 0; i < 10; ++i) - data << uint8(0); // some string - - data << uint32(0); // 14 - - if (type == GUILD_CHARTER_TYPE) - data << uint32(0); // 15 0 - guild, 1 - arena team - else - data << uint32(1); - - SendPacket(&data); -} - -void WorldSession::HandlePetitionRenameOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode MSG_PETITION_RENAME"); // ok - - uint64 petitionGuid; - uint32 type; - std::string newName; - - recv_data >> petitionGuid; // guid - recv_data >> newName; // new name - - Item* item = _player->GetItemByGuid(petitionGuid); - if (!item) - return; - - QueryResult result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionGuid)); - - if (result) - { - Field* fields = result->Fetch(); - type = fields[0].GetUInt8(); - } - else - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionGuid)); - return; - } - - if (type == GUILD_CHARTER_TYPE) - { - if (sGuildMgr->GetGuildByName(newName)) - { - Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NAME_EXISTS_S, newName); - return; - } - if (sObjectMgr->IsReservedName(newName) || !ObjectMgr::IsValidCharterName(newName)) - { - Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NAME_INVALID, newName); - return; - } - } - else - { - if (sArenaTeamMgr->GetArenaTeamByName(newName)) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newName, "", ERR_ARENA_TEAM_NAME_EXISTS_S); - return; - } - if (sObjectMgr->IsReservedName(newName) || !ObjectMgr::IsValidCharterName(newName)) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newName, "", ERR_ARENA_TEAM_NAME_INVALID); - return; - } - } - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PETITION_NAME); - - stmt->setString(0, newName); - stmt->setUInt32(1, GUID_LOPART(petitionGuid)); - - CharacterDatabase.Execute(stmt); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "Petition (GUID: %u) renamed to '%s'", GUID_LOPART(petitionGuid), newName.c_str()); - WorldPacket data(MSG_PETITION_RENAME, (8+newName.size()+1)); - data << uint64(petitionGuid); - data << newName; - SendPacket(&data); -} - -void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode CMSG_PETITION_SIGN"); // ok - - Field* fields; - uint64 petitionGuid; - uint8 unk; - recv_data >> petitionGuid; // petition guid - recv_data >> unk; - - QueryResult result = CharacterDatabase.PQuery( - "SELECT ownerguid, " - " (SELECT COUNT(playerguid) FROM petition_sign WHERE petition_sign.petitionguid = '%u') AS signs, " - " type " - "FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionGuid), GUID_LOPART(petitionGuid)); - - if (!result) - { - sLog->outError("Petition %u is not found for player %u %s", GUID_LOPART(petitionGuid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName()); - return; - } - - fields = result->Fetch(); - uint64 ownerGuid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); - uint8 signs = fields[1].GetUInt8(); - uint32 type = fields[2].GetUInt32(); - - uint32 playerGuid = _player->GetGUIDLow(); - if (GUID_LOPART(ownerGuid) == playerGuid) - return; - - // not let enemies sign guild charter - if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != sObjectMgr->GetPlayerTeamByGUID(ownerGuid)) - { - if (type != GUILD_CHARTER_TYPE) - SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); - else - Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NOT_ALLIED); - return; - } - - if (type != GUILD_CHARTER_TYPE) - { - if (_player->getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", _player->GetName(), ERR_ARENA_TEAM_TARGET_TOO_LOW_S); - return; - } - - uint8 slot = ArenaTeam::GetSlotByType(type); - if (slot >= MAX_ARENA_SLOT) - return; - - if (_player->GetArenaTeamId(slot)) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_IN_ARENA_TEAM_S); - return; - } - - if (_player->GetArenaTeamIdInvited()) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S); - return; - } - } - else - { - if (_player->GetGuildId()) - { - Guild::SendCommandResult(this, GUILD_INVITE_S, ERR_ALREADY_IN_GUILD_S, _player->GetName()); - return; - } - if (_player->GetGuildIdInvited()) - { - Guild::SendCommandResult(this, GUILD_INVITE_S, ERR_ALREADY_INVITED_TO_GUILD_S, _player->GetName()); - return; - } - } - - if (++signs > type) // client signs maximum - return; - - //client doesn't allow to sign petition two times by one character, but not check sign by another character from same account - //not allow sign another player from already sign player account - result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE player_account = '%u' AND petitionguid = '%u'", GetAccountId(), GUID_LOPART(petitionGuid)); - - if (result) - { - WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4)); - data << uint64(petitionGuid); - data << uint64(_player->GetGUID()); - data << (uint32)PETITION_SIGN_ALREADY_SIGNED; - - // close at signer side - SendPacket(&data); - - // update for owner if online - if (Player* owner = ObjectAccessor::FindPlayer(ownerGuid)) - owner->GetSession()->SendPacket(&data); - return; - } - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PETITION_SIGNATURE); - - stmt->setUInt32(0, GUID_LOPART(ownerGuid)); - stmt->setUInt32(1, GUID_LOPART(petitionGuid)); - stmt->setUInt32(2, playerGuid); - stmt->setUInt32(3, GetAccountId()); - - CharacterDatabase.Execute(stmt); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "PETITION SIGN: GUID %u by player: %s (GUID: %u Account: %u)", GUID_LOPART(petitionGuid), _player->GetName(), playerGuid, GetAccountId()); - - WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4)); - data << uint64(petitionGuid); - data << uint64(_player->GetGUID()); - data << uint32(PETITION_SIGN_OK); - - // close at signer side - SendPacket(&data); - - // update signs count on charter, required testing... - //Item* item = _player->GetItemByGuid(petitionguid)); - //if (item) - // item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1+1, signs); - - // update for owner if online - if (Player* owner = ObjectAccessor::FindPlayer(ownerGuid)) - owner->GetSession()->SendPacket(&data); -} - -void WorldSession::HandlePetitionDeclineOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode MSG_PETITION_DECLINE"); // ok - - uint64 petitionguid; - uint64 ownerguid; - recv_data >> petitionguid; // petition guid - sLog->outDebug(LOG_FILTER_NETWORKIO, "Petition %u declined by %u", GUID_LOPART(petitionguid), _player->GetGUIDLow()); - - QueryResult result = CharacterDatabase.PQuery("SELECT ownerguid FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); - if (!result) - return; - - Field* fields = result->Fetch(); - ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); - - Player* owner = ObjectAccessor::FindPlayer(ownerguid); - if (owner) // petition owner online - { - WorldPacket data(MSG_PETITION_DECLINE, 8); - data << uint64(_player->GetGUID()); - owner->GetSession()->SendPacket(&data); - } -} - -void WorldSession::HandleOfferPetitionOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode CMSG_OFFER_PETITION"); // ok - - uint8 signs = 0; - uint64 petitionguid, plguid; - uint32 type, junk; - Player* player; - recv_data >> junk; // this is not petition type! - recv_data >> petitionguid; // petition guid - recv_data >> plguid; // player guid - - player = ObjectAccessor::FindPlayer(plguid); - if (!player) - return; - - QueryResult result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); - if (!result) - return; - - Field* fields = result->Fetch(); - type = fields[0].GetUInt8(); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "OFFER PETITION: type %u, GUID1 %u, to player id: %u", type, GUID_LOPART(petitionguid), GUID_LOPART(plguid)); - - if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != player->GetTeam()) - { - if (type != GUILD_CHARTER_TYPE) - SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); - else - Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NOT_ALLIED); - return; - } - - if (type != GUILD_CHARTER_TYPE) - { - if (player->getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - // player is too low level to join an arena team - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, player->GetName(), "", ERR_ARENA_TEAM_TARGET_TOO_LOW_S); - return; - } - - uint8 slot = ArenaTeam::GetSlotByType(type); - if (slot >= MAX_ARENA_SLOT) - return; - - if (player->GetArenaTeamId(slot)) - { - // player is already in an arena team - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, player->GetName(), "", ERR_ALREADY_IN_ARENA_TEAM_S); - return; - } - - if (player->GetArenaTeamIdInvited()) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", _player->GetName(), ERR_ALREADY_INVITED_TO_ARENA_TEAM_S); - return; - } - } - else - { - if (player->GetGuildId()) - { - Guild::SendCommandResult(this, GUILD_INVITE_S, ERR_ALREADY_IN_GUILD_S, _player->GetName()); - return; - } - - if (player->GetGuildIdInvited()) - { - Guild::SendCommandResult(this, GUILD_INVITE_S, ERR_ALREADY_INVITED_TO_GUILD_S, _player->GetName()); - return; - } - } - - result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); - // result == NULL also correct charter without signs - if (result) - signs = uint8(result->GetRowCount()); - - WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (8+8+4+signs+signs*12)); - data << uint64(petitionguid); // petition guid - data << uint64(_player->GetGUID()); // owner guid - data << uint32(GUID_LOPART(petitionguid)); // guild guid - data << uint8(signs); // sign's count - - for (uint8 i = 1; i <= signs; ++i) - { - Field* fields2 = result->Fetch(); - plguid = fields2[0].GetUInt64(); - - data << uint64(plguid); // Player GUID - data << uint32(0); // there 0 ... - - result->NextRow(); - } - - player->GetSession()->SendPacket(&data); -} - -void WorldSession::HandleTurnInPetitionOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode CMSG_TURN_IN_PETITION"); - - // Get petition guid from packet - WorldPacket data; - uint64 petitionGuid; - - recv_data >> petitionGuid; - - // Check if player really has the required petition charter - Item* item = _player->GetItemByGuid(petitionGuid); - if (!item) - return; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "Petition %u turned in by %u", GUID_LOPART(petitionGuid), _player->GetGUIDLow()); - - // Get petition data from db - uint32 ownerguidlo; - uint32 type; - std::string name; - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION); - stmt->setUInt32(0, GUID_LOPART(petitionGuid)); - PreparedQueryResult result = CharacterDatabase.Query(stmt); - - if (result) - { - Field* fields = result->Fetch(); - ownerguidlo = fields[0].GetUInt32(); - name = fields[1].GetString(); - type = fields[2].GetUInt8(); - } - else - { - sLog->outError("Player %s (guid: %u) tried to turn in petition (guid: %u) that is not present in the database", _player->GetName(), _player->GetGUIDLow(), GUID_LOPART(petitionGuid)); - return; - } - - // Only the petition owner can turn in the petition - if (_player->GetGUIDLow() != ownerguidlo) - return; - - // Petition type (guild/arena) specific checks - if (type == GUILD_CHARTER_TYPE) - { - // Check if player is already in a guild - if (_player->GetGuildId()) - { - data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); - data << (uint32)PETITION_TURN_ALREADY_IN_GUILD; - _player->GetSession()->SendPacket(&data); - return; - } - - // Check if guild name is already taken - if (sGuildMgr->GetGuildByName(name)) - { - Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NAME_EXISTS_S, name); - return; - } - } - else - { - // Check for valid arena bracket (2v2, 3v3, 5v5) - uint8 slot = ArenaTeam::GetSlotByType(type); - if (slot >= MAX_ARENA_SLOT) - return; - - // Check if player is already in an arena team - if (_player->GetArenaTeamId(slot)) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM); - return; - } - - // Check if arena team name is already taken - if (sArenaTeamMgr->GetArenaTeamByName(name)) - { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S); - return; - } - } - - // Get petition signatures from db - uint8 signatures; - - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_SIGNATURE); - stmt->setUInt32(0, GUID_LOPART(petitionGuid)); - result = CharacterDatabase.Query(stmt); - - if (result) - signatures = uint8(result->GetRowCount()); - else - signatures = 0; - - uint32 requiredSignatures; - if (type == GUILD_CHARTER_TYPE) - requiredSignatures = sWorld->getIntConfig(CONFIG_MIN_PETITION_SIGNS); - else - requiredSignatures = type-1; - - // Notify player if signatures are missing - if (signatures < requiredSignatures) - { - data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); - data << (uint32)PETITION_TURN_NEED_MORE_SIGNATURES; - SendPacket(&data); - return; - } - - // Proceed with guild/arena team creation - - // Delete charter item - _player->DestroyItem(item->GetBagSlot(), item->GetSlot(), true); - - if (type == GUILD_CHARTER_TYPE) - { - // Create guild - Guild* guild = new Guild; - - if (!guild->Create(_player, name)) - { - delete guild; - return; - } - - // Register guild and add guild master - sGuildMgr->AddGuild(guild); - - // Add members from signatures - for (uint8 i = 0; i < signatures; ++i) - { - Field* fields = result->Fetch(); - guild->AddMember(MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER)); - result->NextRow(); - } - } - else - { - // Receive the rest of the packet in arena team creation case - uint32 background, icon, iconcolor, border, bordercolor; - recv_data >> background >> icon >> iconcolor >> border >> bordercolor; - - // Create arena team - ArenaTeam* arenaTeam = new ArenaTeam(); - - if (!arenaTeam->Create(_player->GetGUID(), type, name, background, icon, iconcolor, border, bordercolor)) - { - delete arenaTeam; - return; - } - - // Register arena team - sArenaTeamMgr->AddArenaTeam(arenaTeam); - sLog->outDebug(LOG_FILTER_NETWORKIO, "PetitonsHandler: Arena team (guid: %u) added to ObjectMgr", arenaTeam->GetId()); - - // Add members - for (uint8 i = 0; i < signatures; ++i) - { - Field* fields = result->Fetch(); - uint32 memberGUID = fields[0].GetUInt32(); - sLog->outDebug(LOG_FILTER_NETWORKIO, "PetitionsHandler: Adding arena team (guid: %u) member %u", arenaTeam->GetId(), memberGUID); - arenaTeam->AddMember(MAKE_NEW_GUID(memberGUID, 0, HIGHGUID_PLAYER)); - result->NextRow(); - } - } - - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - trans->PAppend("DELETE FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionGuid)); - trans->PAppend("DELETE FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionGuid)); - CharacterDatabase.CommitTransaction(trans); - - // created - sLog->outDebug(LOG_FILTER_NETWORKIO, "TURN IN PETITION GUID %u", GUID_LOPART(petitionGuid)); - - data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); - data << (uint32)PETITION_TURN_OK; - SendPacket(&data); -} - -void WorldSession::HandlePetitionShowListOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "Received CMSG_PETITION_SHOWLIST"); - - uint64 guid; - recv_data >> guid; - - SendPetitionShowList(guid); -} - -void WorldSession::SendPetitionShowList(uint64 guid) -{ - Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_PETITIONER); - if (!creature) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandlePetitionShowListOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - WorldPacket data(SMSG_PETITION_SHOWLIST, 8+1+4*6); - data << guid; // npc guid - - if (creature->isTabardDesigner()) - { - data << uint8(1); // count - data << uint32(1); // index - data << uint32(GUILD_CHARTER); // charter entry - data << uint32(CHARTER_DISPLAY_ID); // charter display id - data << uint32(GUILD_CHARTER_COST); // charter cost - data << uint32(0); // unknown - data << uint32(9); // required signs? - } - else - { - data << uint8(3); // count - // 2v2 - data << uint32(1); // index - data << uint32(ARENA_TEAM_CHARTER_2v2); // charter entry - data << uint32(CHARTER_DISPLAY_ID); // charter display id - data << uint32(ARENA_TEAM_CHARTER_2v2_COST); // charter cost - data << uint32(2); // unknown - data << uint32(2); // required signs? - // 3v3 - data << uint32(2); // index - data << uint32(ARENA_TEAM_CHARTER_3v3); // charter entry - data << uint32(CHARTER_DISPLAY_ID); // charter display id - data << uint32(ARENA_TEAM_CHARTER_3v3_COST); // charter cost - data << uint32(3); // unknown - data << uint32(3); // required signs? - // 5v5 - data << uint32(3); // index - data << uint32(ARENA_TEAM_CHARTER_5v5); // charter entry - data << uint32(CHARTER_DISPLAY_ID); // charter display id - data << uint32(ARENA_TEAM_CHARTER_5v5_COST); // charter cost - data << uint32(5); // unknown - data << uint32(5); // required signs? - } - - SendPacket(&data); - sLog->outDebug(LOG_FILTER_NETWORKIO, "Sent SMSG_PETITION_SHOWLIST"); -} diff --git a/src/server/game/Server/Protocol/Handlers/QueryHandler.cpp b/src/server/game/Server/Protocol/Handlers/QueryHandler.cpp deleted file mode 100755 index 5702eefffec..00000000000 --- a/src/server/game/Server/Protocol/Handlers/QueryHandler.cpp +++ /dev/null @@ -1,477 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "Language.h" -#include "DatabaseEnv.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Opcodes.h" -#include "Log.h" -#include "World.h" -#include "ObjectMgr.h" -#include "Player.h" -#include "UpdateMask.h" -#include "NPCHandler.h" -#include "Pet.h" -#include "MapManager.h" - -void WorldSession::SendNameQueryOpcode(uint64 guid) -{ - Player* player = NULL; - const CharacterNameData* nameData = sWorld->GetCharacterNameData(GUID_LOPART(guid)); - if (nameData) - player = ObjectAccessor::FindPlayer(guid); - - // guess size - WorldPacket data(SMSG_NAME_QUERY_RESPONSE, (8+1+1+1+1+1+10)); - data.appendPackGUID(guid); - data << uint8(0); // added in 3.1 - if (nameData) - { - data << nameData->m_name; // played name - data << uint8(0); // realm name for cross realm BG usage - data << uint8(nameData->m_race); - data << uint8(nameData->m_gender); - data << uint8(nameData->m_class); - } - else - { - data << std::string(GetTrinityString(LANG_NON_EXIST_CHARACTER)); - data << uint32(0); - } - - if (player) - { - if (DeclinedName const* names = player->GetDeclinedNames()) - { - data << uint8(1); // is declined - for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i) - data << names->name[i]; - } - else - data << uint8(0); // is not declined - } - else //TODO: decline names may also need to be stored in char name data - data << uint8(0); - - SendPacket(&data); -} - -void WorldSession::HandleNameQueryOpcode(WorldPacket& recv_data) -{ - uint64 guid; - - recv_data >> guid; - - // This is disable by default to prevent lots of console spam - // sLog->outString("HandleNameQueryOpcode %u", guid); - - SendNameQueryOpcode(guid); -} - -void WorldSession::HandleQueryTimeOpcode(WorldPacket & /*recv_data*/) -{ - SendQueryTimeResponse(); -} - -void WorldSession::SendQueryTimeResponse() -{ - WorldPacket data(SMSG_QUERY_TIME_RESPONSE, 4+4); - data << uint32(time(NULL)); - data << uint32(sWorld->GetNextDailyQuestsResetTime() - time(NULL)); - SendPacket(&data); -} - -/// Only _static_ data is sent in this packet !!! -void WorldSession::HandleCreatureQueryOpcode(WorldPacket & recv_data) -{ - uint32 entry; - recv_data >> entry; - uint64 guid; - recv_data >> guid; - - CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(entry); - if (ci) - { - - std::string Name, SubName; - Name = ci->Name; - SubName = ci->SubName; - - int loc_idx = GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - if (CreatureLocale const* cl = sObjectMgr->GetCreatureLocale(entry)) - { - ObjectMgr::GetLocaleString(cl->Name, loc_idx, Name); - ObjectMgr::GetLocaleString(cl->SubName, loc_idx, SubName); - } - } - sLog->outDetail("WORLD: CMSG_CREATURE_QUERY '%s' - Entry: %u.", ci->Name.c_str(), entry); - // guess size - WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 100); - data << uint32(entry); // creature entry - data << Name; - data << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4, always empty - data << SubName; - data << ci->IconName; // "Directions" for guard, string for Icons 2.3.0 - data << uint32(ci->type_flags); // flags - data << uint32(ci->type); // CreatureType.dbc - data << uint32(ci->family); // CreatureFamily.dbc - data << uint32(ci->rank); // Creature Rank (elite, boss, etc) - data << uint32(ci->KillCredit[0]); // new in 3.1, kill credit - data << uint32(ci->KillCredit[1]); // new in 3.1, kill credit - data << uint32(ci->Modelid1); // Modelid1 - data << uint32(ci->Modelid2); // Modelid2 - data << uint32(ci->Modelid3); // Modelid3 - data << uint32(ci->Modelid4); // Modelid4 - data << float(ci->ModHealth); // dmg/hp modifier - data << float(ci->ModMana); // dmg/mana modifier - data << uint8(ci->RacialLeader); - for (uint32 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i) - data << uint32(ci->questItems[i]); // itemId[6], quest drop - data << uint32(ci->movementId); // CreatureMovementInfo.dbc - SendPacket(&data); - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE"); - } - else - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CREATURE_QUERY - NO CREATURE INFO! (GUID: %u, ENTRY: %u)", - GUID_LOPART(guid), entry); - WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 4); - data << uint32(entry | 0x80000000); - SendPacket(&data); - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE"); - } -} - -/// Only _static_ data is sent in this packet !!! -void WorldSession::HandleGameObjectQueryOpcode(WorldPacket & recv_data) -{ - uint32 entry; - recv_data >> entry; - uint64 guid; - recv_data >> guid; - - const GameObjectTemplate* info = sObjectMgr->GetGameObjectTemplate(entry); - if (info) - { - std::string Name; - std::string IconName; - std::string CastBarCaption; - - Name = info->name; - IconName = info->IconName; - CastBarCaption = info->castBarCaption; - - int loc_idx = GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - if (GameObjectLocale const* gl = sObjectMgr->GetGameObjectLocale(entry)) - { - ObjectMgr::GetLocaleString(gl->Name, loc_idx, Name); - ObjectMgr::GetLocaleString(gl->CastBarCaption, loc_idx, CastBarCaption); - } - } - sLog->outDetail("WORLD: CMSG_GAMEOBJECT_QUERY '%s' - Entry: %u. ", info->name.c_str(), entry); - WorldPacket data (SMSG_GAMEOBJECT_QUERY_RESPONSE, 150); - data << uint32(entry); - data << uint32(info->type); - data << uint32(info->displayId); - data << Name; - data << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4 - data << IconName; // 2.0.3, string. Icon name to use instead of default icon for go's (ex: "Attack" makes sword) - data << CastBarCaption; // 2.0.3, string. Text will appear in Cast Bar when using GO (ex: "Collecting") - data << info->unk1; // 2.0.3, string - data.append(info->raw.data, 24); - data << float(info->size); // go size - for (uint32 i = 0; i < MAX_GAMEOBJECT_QUEST_ITEMS; ++i) - data << uint32(info->questItems[i]); // itemId[6], quest drop - SendPacket(&data); - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE"); - } - else - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_GAMEOBJECT_QUERY - Missing gameobject info for (GUID: %u, ENTRY: %u)", - GUID_LOPART(guid), entry); - WorldPacket data (SMSG_GAMEOBJECT_QUERY_RESPONSE, 4); - data << uint32(entry | 0x80000000); - SendPacket(&data); - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE"); - } -} - -void WorldSession::HandleCorpseQueryOpcode(WorldPacket & /*recv_data*/) -{ - sLog->outDetail("WORLD: Received MSG_CORPSE_QUERY"); - - Corpse* corpse = GetPlayer()->GetCorpse(); - - if (!corpse) - { - WorldPacket data(MSG_CORPSE_QUERY, 1); - data << uint8(0); // corpse not found - SendPacket(&data); - return; - } - - uint32 mapid = corpse->GetMapId(); - float x = corpse->GetPositionX(); - float y = corpse->GetPositionY(); - float z = corpse->GetPositionZ(); - uint32 corpsemapid = mapid; - - // if corpse at different map - if (mapid != _player->GetMapId()) - { - // search entrance map for proper show entrance - if (MapEntry const* corpseMapEntry = sMapStore.LookupEntry(mapid)) - { - if (corpseMapEntry->IsDungeon() && corpseMapEntry->entrance_map >= 0) - { - // if corpse map have entrance - if (Map const* entranceMap = sMapMgr->CreateBaseMap(corpseMapEntry->entrance_map)) - { - mapid = corpseMapEntry->entrance_map; - x = corpseMapEntry->entrance_x; - y = corpseMapEntry->entrance_y; - z = entranceMap->GetHeight(x, y, MAX_HEIGHT); - } - } - } - } - - WorldPacket data(MSG_CORPSE_QUERY, 1+(6*4)); - data << uint8(1); // corpse found - data << int32(mapid); - data << float(x); - data << float(y); - data << float(z); - data << int32(corpsemapid); - data << uint32(0); // unknown - SendPacket(&data); -} - -void WorldSession::HandleNpcTextQueryOpcode(WorldPacket & recv_data) -{ - uint32 textID; - uint64 guid; - - recv_data >> textID; - sLog->outDetail("WORLD: CMSG_NPC_TEXT_QUERY ID '%u'", textID); - - recv_data >> guid; - GetPlayer()->SetSelection(guid); - - GossipText const* pGossip = sObjectMgr->GetGossipText(textID); - - WorldPacket data(SMSG_NPC_TEXT_UPDATE, 100); // guess size - data << textID; - - if (!pGossip) - { - for (uint32 i = 0; i < MAX_GOSSIP_TEXT_OPTIONS; ++i) - { - data << float(0); - data << "Greetings $N"; - data << "Greetings $N"; - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - } - } - else - { - std::string Text_0[MAX_LOCALES], Text_1[MAX_LOCALES]; - for (int i = 0; i < MAX_GOSSIP_TEXT_OPTIONS; ++i) - { - Text_0[i]=pGossip->Options[i].Text_0; - Text_1[i]=pGossip->Options[i].Text_1; - } - - int loc_idx = GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - { - if (NpcTextLocale const* nl = sObjectMgr->GetNpcTextLocale(textID)) - { - for (int i = 0; i < MAX_LOCALES; ++i) - { - ObjectMgr::GetLocaleString(nl->Text_0[i], loc_idx, Text_0[i]); - ObjectMgr::GetLocaleString(nl->Text_1[i], loc_idx, Text_1[i]); - } - } - } - - for (int i = 0; i < MAX_GOSSIP_TEXT_OPTIONS; ++i) - { - data << pGossip->Options[i].Probability; - - if (Text_0[i].empty()) - data << Text_1[i]; - else - data << Text_0[i]; - - if (Text_1[i].empty()) - data << Text_0[i]; - else - data << Text_1[i]; - - data << pGossip->Options[i].Language; - - for (int j = 0; j < MAX_GOSSIP_TEXT_EMOTES; ++j) - { - data << pGossip->Options[i].Emotes[j]._Delay; - data << pGossip->Options[i].Emotes[j]._Emote; - } - } - } - - SendPacket(&data); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_NPC_TEXT_UPDATE"); -} - -/// Only _static_ data is sent in this packet !!! -void WorldSession::HandlePageTextQueryOpcode(WorldPacket & recv_data) -{ - sLog->outDetail("WORLD: Received CMSG_PAGE_TEXT_QUERY"); - - uint32 pageID; - recv_data >> pageID; - recv_data.read_skip(); // guid - - while (pageID) - { - PageText const* pageText = sObjectMgr->GetPageText(pageID); - // guess size - WorldPacket data(SMSG_PAGE_TEXT_QUERY_RESPONSE, 50); - data << pageID; - - if (!pageText) - { - data << "Item page missing."; - data << uint32(0); - pageID = 0; - } - else - { - std::string Text = pageText->Text; - - int loc_idx = GetSessionDbLocaleIndex(); - if (loc_idx >= 0) - if (PageTextLocale const* player = sObjectMgr->GetPageTextLocale(pageID)) - ObjectMgr::GetLocaleString(player->Text, loc_idx, Text); - - data << Text; - data << uint32(pageText->NextPage); - pageID = pageText->NextPage; - } - SendPacket(&data); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_PAGE_TEXT_QUERY_RESPONSE"); - } -} - -void WorldSession::HandleCorpseMapPositionQuery(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recv CMSG_CORPSE_MAP_POSITION_QUERY"); - - uint32 unk; - recv_data >> unk; - - WorldPacket data(SMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE, 4+4+4+4); - data << float(0); - data << float(0); - data << float(0); - data << float(0); - SendPacket(&data); -} - -void WorldSession::HandleQuestPOIQuery(WorldPacket& recv_data) -{ - uint32 count; - recv_data >> count; // quest count, max=25 - - if (count >= MAX_QUEST_LOG_SIZE) - { - recv_data.rfinish(); - return; - } - - WorldPacket data(SMSG_QUEST_POI_QUERY_RESPONSE, 4+(4+4)*count); - data << uint32(count); // count - - for (uint32 i = 0; i < count; ++i) - { - uint32 questId; - recv_data >> questId; // quest id - - bool questOk = false; - - uint16 questSlot = _player->FindQuestSlot(questId); - - if (questSlot != MAX_QUEST_LOG_SIZE) - questOk =_player->GetQuestSlotQuestId(questSlot) == questId; - - if (questOk) - { - QuestPOIVector const* POI = sObjectMgr->GetQuestPOIVector(questId); - - if (POI) - { - data << uint32(questId); // quest ID - data << uint32(POI->size()); // POI count - - for (QuestPOIVector::const_iterator itr = POI->begin(); itr != POI->end(); ++itr) - { - data << uint32(itr->Id); // POI index - data << int32(itr->ObjectiveIndex); // objective index - data << uint32(itr->MapId); // mapid - data << uint32(itr->AreaId); // areaid - data << uint32(itr->Unk2); // unknown - data << uint32(itr->Unk3); // unknown - data << uint32(itr->Unk4); // unknown - data << uint32(itr->points.size()); // POI points count - - for (std::vector::const_iterator itr2 = itr->points.begin(); itr2 != itr->points.end(); ++itr2) - { - data << int32(itr2->x); // POI point x - data << int32(itr2->y); // POI point y - } - } - } - else - { - data << uint32(questId); // quest ID - data << uint32(0); // POI count - } - } - else - { - data << uint32(questId); // quest ID - data << uint32(0); // POI count - } - } - - SendPacket(&data); -} diff --git a/src/server/game/Server/Protocol/Handlers/QuestHandler.cpp b/src/server/game/Server/Protocol/Handlers/QuestHandler.cpp deleted file mode 100755 index 7e80c780369..00000000000 --- a/src/server/game/Server/Protocol/Handlers/QuestHandler.cpp +++ /dev/null @@ -1,779 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "Log.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Opcodes.h" -#include "World.h" -#include "ObjectMgr.h" -#include "Player.h" -#include "GossipDef.h" -#include "QuestDef.h" -#include "ObjectAccessor.h" -#include "Group.h" -#include "Battleground.h" -#include "BattlegroundAV.h" -#include "ScriptMgr.h" -#include "GameObjectAI.h" - -void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPacket & recv_data) -{ - uint64 guid; - recv_data >> guid; - uint8 questStatus = DIALOG_STATUS_NONE; - uint8 defstatus = DIALOG_STATUS_NONE; - - Object* questgiver = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); - if (!questgiver) - { - sLog->outDetail("Error in CMSG_QUESTGIVER_STATUS_QUERY, called for not found questgiver (Typeid: %u GUID: %u)", GuidHigh2TypeId(GUID_HIPART(guid)), GUID_LOPART(guid)); - return; - } - - switch (questgiver->GetTypeId()) - { - case TYPEID_UNIT: - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for npc, guid = %u", uint32(GUID_LOPART(guid))); - Creature* cr_questgiver=questgiver->ToCreature(); - if (!cr_questgiver->IsHostileTo(_player)) // not show quest status to enemies - { - questStatus = sScriptMgr->GetDialogStatus(_player, cr_questgiver); - if (questStatus > 6) - questStatus = getDialogStatus(_player, cr_questgiver, defstatus); - } - break; - } - case TYPEID_GAMEOBJECT: - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for GameObject guid = %u", uint32(GUID_LOPART(guid))); - GameObject* go_questgiver=(GameObject*)questgiver; - questStatus = sScriptMgr->GetDialogStatus(_player, go_questgiver); - if (questStatus > 6) - questStatus = getDialogStatus(_player, go_questgiver, defstatus); - break; - } - default: - sLog->outError("QuestGiver called for unexpected type %u", questgiver->GetTypeId()); - break; - } - - //inform client about status of quest - _player->PlayerTalkClass->SendQuestGiverStatus(questStatus, guid); -} - -void WorldSession::HandleQuestgiverHelloOpcode(WorldPacket & recv_data) -{ - uint64 guid; - recv_data >> guid; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_HELLO npc = %u", GUID_LOPART(guid)); - - Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); - if (!creature) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleQuestgiverHelloOpcode - Unit (GUID: %u) not found or you can't interact with him.", - GUID_LOPART(guid)); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - // Stop the npc if moving - creature->StopMoving(); - - if (sScriptMgr->OnGossipHello(_player, creature)) - return; - - _player->PrepareGossipMenu(creature, creature->GetCreatureInfo()->GossipMenuId, true); - _player->SendPreparedGossip(creature); - - creature->AI()->sGossipHello(_player); -} - -void WorldSession::HandleQuestgiverAcceptQuestOpcode(WorldPacket & recv_data) -{ - uint64 guid; - uint32 quest; - uint32 unk1; - recv_data >> guid >> quest >> unk1; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_ACCEPT_QUEST npc = %u, quest = %u, unk1 = %u", uint32(GUID_LOPART(guid)), quest, unk1); - - Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT|TYPEMASK_ITEM|TYPEMASK_PLAYER); - - // no or incorrect quest giver - if (!pObject || (pObject->GetTypeId() != TYPEID_PLAYER && !pObject->hasQuest(quest)) || - (pObject->GetTypeId() == TYPEID_PLAYER && !pObject->ToPlayer()->CanShareQuest(quest))) - { - _player->PlayerTalkClass->SendCloseGossip(); - _player->SetDivider(0); - return; - } - - // some kind of WPE protection - if (!_player->CanInteractWithQuestGiver(pObject)) - return; - - Quest const* qInfo = sObjectMgr->GetQuestTemplate(quest); - if (qInfo) - { - // prevent cheating - if (!GetPlayer()->CanTakeQuest(qInfo, true)) - { - _player->PlayerTalkClass->SendCloseGossip(); - _player->SetDivider(0); - return; - } - - if (_player->GetDivider() != 0) - { - Player* player = ObjectAccessor::FindPlayer(_player->GetDivider()); - if (player) - { - player->SendPushToPartyResponse(_player, QUEST_PARTY_MSG_ACCEPT_QUEST); - _player->SetDivider(0); - } - } - - if (_player->CanAddQuest(qInfo, true)) - { - _player->AddQuest(qInfo, pObject); - - if (qInfo->HasFlag(QUEST_FLAGS_PARTY_ACCEPT)) - { - if (Group* group = _player->GetGroup()) - { - for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* player = itr->getSource(); - - if (!player || player == _player) // not self - continue; - - if (player->CanTakeQuest(qInfo, true)) - { - player->SetDivider(_player->GetGUID()); - - //need confirmation that any gossip window will close - player->PlayerTalkClass->SendCloseGossip(); - - _player->SendQuestConfirmAccept(qInfo, player); - } - } - } - } - - if (_player->CanCompleteQuest(quest)) - _player->CompleteQuest(quest); - - switch (pObject->GetTypeId()) - { - case TYPEID_UNIT: - sScriptMgr->OnQuestAccept(_player, (pObject->ToCreature()), qInfo); - (pObject->ToCreature())->AI()->sQuestAccept(_player, qInfo); - break; - case TYPEID_ITEM: - case TYPEID_CONTAINER: - { - sScriptMgr->OnQuestAccept(_player, ((Item*)pObject), qInfo); - - // destroy not required for quest finish quest starting item - bool destroyItem = true; - for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) - { - if ((qInfo->RequiredItemId[i] == ((Item*)pObject)->GetEntry()) && (((Item*)pObject)->GetTemplate()->MaxCount > 0)) - { - destroyItem = false; - break; - } - } - - if (destroyItem) - _player->DestroyItem(((Item*)pObject)->GetBagSlot(), ((Item*)pObject)->GetSlot(), true); - - break; - } - case TYPEID_GAMEOBJECT: - sScriptMgr->OnQuestAccept(_player, ((GameObject*)pObject), qInfo); - (pObject->ToGameObject())->AI()->QuestAccept(_player, qInfo); - break; - default: - break; - } - _player->PlayerTalkClass->SendCloseGossip(); - - if (qInfo->GetSrcSpell() > 0) - _player->CastSpell(_player, qInfo->GetSrcSpell(), true); - - return; - } - } - - _player->PlayerTalkClass->SendCloseGossip(); -} - -void WorldSession::HandleQuestgiverQueryQuestOpcode(WorldPacket & recv_data) -{ - uint64 guid; - uint32 questId; - uint8 unk1; - recv_data >> guid >> questId >> unk1; - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_QUERY_QUEST npc = %u, quest = %u, unk1 = %u", uint32(GUID_LOPART(guid)), questId, unk1); - - // Verify that the guid is valid and is a questgiver or involved in the requested quest - Object* object = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT | TYPEMASK_ITEM); - if (!object || (!object->hasQuest(questId) && !object->hasInvolvedQuest(questId))) - { - _player->PlayerTalkClass->SendCloseGossip(); - return; - } - - Quest const* quest = sObjectMgr->GetQuestTemplate(questId); - if (quest) - { - // not sure here what should happen to quests with QUEST_FLAGS_AUTOCOMPLETE - // if this breaks them, add && object->GetTypeId() == TYPEID_ITEM to this check - // item-started quests never have that flag - if (!_player->CanTakeQuest(quest, true)) - return; - - if (quest->IsAutoAccept() && _player->CanAddQuest(quest, true)) - { - _player->AddQuest(quest, object); - if (_player->CanCompleteQuest(questId)) - _player->CompleteQuest(questId); - } - - if (quest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE)) - _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, object->GetGUID(), _player->CanCompleteQuest(quest->GetQuestId()), true); - else - _player->PlayerTalkClass->SendQuestGiverQuestDetails(quest, object->GetGUID(), true); - } -} - -void WorldSession::HandleQuestQueryOpcode(WorldPacket & recv_data) -{ - if (!_player) - return; - - uint32 quest; - recv_data >> quest; - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUEST_QUERY quest = %u", quest); - - Quest const* pQuest = sObjectMgr->GetQuestTemplate(quest); - if (pQuest) - { - _player->PlayerTalkClass->SendQuestQueryResponse(pQuest); - } -} - -void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket & recv_data) -{ - uint32 questId, reward; - uint64 guid; - recv_data >> guid >> questId >> reward; - - if (reward >= QUEST_REWARD_CHOICES_COUNT) - { - sLog->outError("Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player %s (guid %d) tried to get invalid reward (%u) (probably packet hacking)", _player->GetName(), _player->GetGUIDLow(), reward); - return; - } - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_CHOOSE_REWARD npc = %u, quest = %u, reward = %u", uint32(GUID_LOPART(guid)), questId, reward); - - Object* object = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); - if (!object || !object->hasInvolvedQuest(questId)) - return; - - // some kind of WPE protection - if (!_player->CanInteractWithQuestGiver(object)) - return; - - if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId)) - { - if ((!_player->CanSeeStartQuest(quest) && _player->GetQuestStatus(questId) == QUEST_STATUS_NONE) || - (_player->GetQuestStatus(questId) != QUEST_STATUS_COMPLETE && !quest->IsAutoComplete())) - { - sLog->outError("HACK ALERT: Player %s (guid: %u) is trying to complete quest (id: %u) but he has no right to do it!", - _player->GetName(), _player->GetGUIDLow(), questId); - return; - } - if (_player->CanRewardQuest(quest, reward, true)) - { - _player->RewardQuest(quest, reward, object); - - switch (object->GetTypeId()) - { - case TYPEID_UNIT: - if (!(sScriptMgr->OnQuestReward(_player, (object->ToCreature()), quest, reward))) - { - // Send next quest - if (Quest const* nextQuest = _player->GetNextQuest(guid, quest)) - { - if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true) && _player->CanTakeQuest(quest, true)) - { - _player->AddQuest(nextQuest, object); - if (_player->CanCompleteQuest(nextQuest->GetQuestId())) - _player->CompleteQuest(nextQuest->GetQuestId()); - } - - _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true); - } - - (object->ToCreature())->AI()->sQuestReward(_player, quest, reward); - } - break; - case TYPEID_GAMEOBJECT: - if (!sScriptMgr->OnQuestReward(_player, ((GameObject*)object), quest, reward)) - { - // Send next quest - if (Quest const* nextQuest = _player->GetNextQuest(guid, quest)) - { - if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true) && _player->CanTakeQuest(quest, true)) - { - _player->AddQuest(nextQuest, object); - if (_player->CanCompleteQuest(nextQuest->GetQuestId())) - _player->CompleteQuest(nextQuest->GetQuestId()); - } - - _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true); - } - - object->ToGameObject()->AI()->QuestReward(_player, quest, reward); - } - break; - default: - break; - } - } - else - _player->PlayerTalkClass->SendQuestGiverOfferReward(quest, guid, true); - } -} - -void WorldSession::HandleQuestgiverRequestRewardOpcode(WorldPacket & recv_data) -{ - uint32 quest; - uint64 guid; - recv_data >> guid >> quest; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_REQUEST_REWARD npc = %u, quest = %u", uint32(GUID_LOPART(guid)), quest); - - Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); - if (!pObject || !pObject->hasInvolvedQuest(quest)) - return; - - // some kind of WPE protection - if (!_player->CanInteractWithQuestGiver(pObject)) - return; - - if (_player->CanCompleteQuest(quest)) - _player->CompleteQuest(quest); - - if (_player->GetQuestStatus(quest) != QUEST_STATUS_COMPLETE) - return; - - if (Quest const* pQuest = sObjectMgr->GetQuestTemplate(quest)) - _player->PlayerTalkClass->SendQuestGiverOfferReward(pQuest, guid, true); -} - -void WorldSession::HandleQuestgiverCancel(WorldPacket& /*recv_data*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_CANCEL"); - - _player->PlayerTalkClass->SendCloseGossip(); -} - -void WorldSession::HandleQuestLogSwapQuest(WorldPacket& recv_data) -{ - uint8 slot1, slot2; - recv_data >> slot1 >> slot2; - - if (slot1 == slot2 || slot1 >= MAX_QUEST_LOG_SIZE || slot2 >= MAX_QUEST_LOG_SIZE) - return; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTLOG_SWAP_QUEST slot 1 = %u, slot 2 = %u", slot1, slot2); - - GetPlayer()->SwapQuestSlot(slot1, slot2); -} - -void WorldSession::HandleQuestLogRemoveQuest(WorldPacket& recv_data) -{ - uint8 slot; - recv_data >> slot; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTLOG_REMOVE_QUEST slot = %u", slot); - - if (slot < MAX_QUEST_LOG_SIZE) - { - if (uint32 quest = _player->GetQuestSlotQuestId(slot)) - { - if (!_player->TakeQuestSourceItem(quest, true)) - return; // can't un-equip some items, reject quest cancel - - if (const Quest *pQuest = sObjectMgr->GetQuestTemplate(quest)) - { - if (pQuest->HasFlag(QUEST_TRINITY_FLAGS_TIMED)) - _player->RemoveTimedQuest(quest); - } - - _player->TakeQuestSourceItem(quest, true); // remove quest src item from player - _player->RemoveActiveQuest(quest); - _player->GetAchievementMgr().RemoveTimedAchievement(ACHIEVEMENT_TIMED_TYPE_QUEST, quest); - - sLog->outDetail("Player %u abandoned quest %u", _player->GetGUIDLow(), quest); - } - - _player->SetQuestSlot(slot, 0); - - _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED, 1); - } -} - -void WorldSession::HandleQuestConfirmAccept(WorldPacket& recv_data) -{ - uint32 quest; - recv_data >> quest; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUEST_CONFIRM_ACCEPT quest = %u", quest); - - if (const Quest* pQuest = sObjectMgr->GetQuestTemplate(quest)) - { - if (!pQuest->HasFlag(QUEST_FLAGS_PARTY_ACCEPT)) - return; - - Player* pOriginalPlayer = ObjectAccessor::FindPlayer(_player->GetDivider()); - - if (!pOriginalPlayer) - return; - - if (pQuest->IsRaidQuest()) - { - if (!_player->IsInSameRaidWith(pOriginalPlayer)) - return; - } - else - { - if (!_player->IsInSameGroupWith(pOriginalPlayer)) - return; - } - - if (_player->CanAddQuest(pQuest, true)) - _player->AddQuest(pQuest, NULL); // NULL, this prevent DB script from duplicate running - - _player->SetDivider(0); - } -} - -void WorldSession::HandleQuestgiverCompleteQuest(WorldPacket& recv_data) -{ - uint32 quest; - uint64 guid; - recv_data >> guid >> quest; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_COMPLETE_QUEST npc = %u, quest = %u", uint32(GUID_LOPART(guid)), quest); - - Object* pObject = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT); - if (!pObject || !pObject->hasInvolvedQuest(quest)) - return; - - // some kind of WPE protection - if (!_player->CanInteractWithQuestGiver(pObject)) - return; - - Quest const* pQuest = sObjectMgr->GetQuestTemplate(quest); - if (pQuest) - { - if (!_player->CanSeeStartQuest(pQuest) && _player->GetQuestStatus(quest)==QUEST_STATUS_NONE) - { - sLog->outError("Possible hacking attempt: Player %s [guid: %u] tried to complete quest [entry: %u] without being in possession of the quest!", - _player->GetName(), _player->GetGUIDLow(), quest); - return; - } - // TODO: need a virtual function - if (_player->InBattleground()) - if (Battleground* bg = _player->GetBattleground()) - if (bg->GetTypeID() == BATTLEGROUND_AV) - ((BattlegroundAV*)bg)->HandleQuestComplete(quest, _player); - - if (_player->GetQuestStatus(quest) != QUEST_STATUS_COMPLETE) - { - if (pQuest->IsRepeatable()) - _player->PlayerTalkClass->SendQuestGiverRequestItems(pQuest, guid, _player->CanCompleteRepeatableQuest(pQuest), false); - else - _player->PlayerTalkClass->SendQuestGiverRequestItems(pQuest, guid, _player->CanRewardQuest(pQuest, false), false); - } - else - { - if (pQuest->GetReqItemsCount()) // some items required - _player->PlayerTalkClass->SendQuestGiverRequestItems(pQuest, guid, _player->CanRewardQuest(pQuest, false), false); - else // no items required - _player->PlayerTalkClass->SendQuestGiverOfferReward(pQuest, guid, true); - } - } -} - -void WorldSession::HandleQuestgiverQuestAutoLaunch(WorldPacket& /*recvPacket*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_QUEST_AUTOLAUNCH"); -} - -void WorldSession::HandlePushQuestToParty(WorldPacket& recvPacket) -{ - uint32 questId; - recvPacket >> questId; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_PUSHQUESTTOPARTY quest = %u", questId); - - if (Quest const* pQuest = sObjectMgr->GetQuestTemplate(questId)) - { - if (Group* group = _player->GetGroup()) - { - for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* player = itr->getSource(); - - if (!player || player == _player) // skip self - continue; - - _player->SendPushToPartyResponse(player, QUEST_PARTY_MSG_SHARING_QUEST); - - if (!player->SatisfyQuestStatus(pQuest, false)) - { - _player->SendPushToPartyResponse(player, QUEST_PARTY_MSG_HAVE_QUEST); - continue; - } - - if (player->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE) - { - _player->SendPushToPartyResponse(player, QUEST_PARTY_MSG_FINISH_QUEST); - continue; - } - - if (!player->CanTakeQuest(pQuest, false)) - { - _player->SendPushToPartyResponse(player, QUEST_PARTY_MSG_CANT_TAKE_QUEST); - continue; - } - - if (!player->SatisfyQuestLog(false)) - { - _player->SendPushToPartyResponse(player, QUEST_PARTY_MSG_LOG_FULL); - continue; - } - - if (player->GetDivider() != 0) - { - _player->SendPushToPartyResponse(player, QUEST_PARTY_MSG_BUSY); - continue; - } - - player->PlayerTalkClass->SendQuestGiverQuestDetails(pQuest, _player->GetGUID(), true); - player->SetDivider(_player->GetGUID()); - } - } - } -} - -void WorldSession::HandleQuestPushResult(WorldPacket& recvPacket) -{ - uint64 guid; - uint8 msg; - recvPacket >> guid >> msg; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received MSG_QUEST_PUSH_RESULT"); - - if (_player->GetDivider() != 0) - { - Player* player = ObjectAccessor::FindPlayer(_player->GetDivider()); - if (player) - { - WorldPacket data(MSG_QUEST_PUSH_RESULT, (8+1)); - data << uint64(guid); - data << uint8(msg); // valid values: 0-8 - player->GetSession()->SendPacket(&data); - _player->SetDivider(0); - } - } -} - -uint32 WorldSession::getDialogStatus(Player* player, Object* questgiver, uint32 defstatus) -{ - uint32 result = defstatus; - - QuestRelationBounds qr; - QuestRelationBounds qir; - - switch (questgiver->GetTypeId()) - { - case TYPEID_GAMEOBJECT: - { - qr = sObjectMgr->GetGOQuestRelationBounds(questgiver->GetEntry()); - qir = sObjectMgr->GetGOQuestInvolvedRelationBounds(questgiver->GetEntry()); - break; - } - case TYPEID_UNIT: - { - qr = sObjectMgr->GetCreatureQuestRelationBounds(questgiver->GetEntry()); - qir = sObjectMgr->GetCreatureQuestInvolvedRelationBounds(questgiver->GetEntry()); - break; - } - default: - //its imposible, but check ^) - sLog->outError("Warning: GetDialogStatus called for unexpected type %u", questgiver->GetTypeId()); - return DIALOG_STATUS_NONE; - } - - for (QuestRelations::const_iterator i = qir.first; i != qir.second; ++i) - { - uint32 result2 = 0; - uint32 quest_id = i->second; - Quest const* pQuest = sObjectMgr->GetQuestTemplate(quest_id); - if (!pQuest) continue; - - ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_QUEST_SHOW_MARK, pQuest->GetQuestId()); - if (!sConditionMgr->IsPlayerMeetToConditions(player, conditions)) - continue; - - QuestStatus status = player->GetQuestStatus(quest_id); - if ((status == QUEST_STATUS_COMPLETE && !player->GetQuestRewardStatus(quest_id)) || - (pQuest->IsAutoComplete() && player->CanTakeQuest(pQuest, false))) - { - if (pQuest->IsAutoComplete() && pQuest->IsRepeatable()) - result2 = DIALOG_STATUS_REWARD_REP; - else - result2 = DIALOG_STATUS_REWARD; - } - else if (status == QUEST_STATUS_INCOMPLETE) - result2 = DIALOG_STATUS_INCOMPLETE; - - if (result2 > result) - result = result2; - } - - for (QuestRelations::const_iterator i = qr.first; i != qr.second; ++i) - { - uint32 result2 = 0; - uint32 quest_id = i->second; - Quest const* pQuest = sObjectMgr->GetQuestTemplate(quest_id); - if (!pQuest) - continue; - - ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_QUEST_SHOW_MARK, pQuest->GetQuestId()); - if (!sConditionMgr->IsPlayerMeetToConditions(player, conditions)) - continue; - - QuestStatus status = player->GetQuestStatus(quest_id); - if (status == QUEST_STATUS_NONE) - { - if (player->CanSeeStartQuest(pQuest)) - { - if (player->SatisfyQuestLevel(pQuest, false)) - { - if (pQuest->IsAutoComplete() || (pQuest->IsRepeatable() && player->IsQuestRewarded(quest_id))) - result2 = DIALOG_STATUS_REWARD_REP; - else if (player->getLevel() <= ((player->GetQuestLevel(pQuest) == -1) ? player->getLevel() : player->GetQuestLevel(pQuest) + sWorld->getIntConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF))) - { - if (pQuest->HasFlag(QUEST_FLAGS_DAILY) || pQuest->HasFlag(QUEST_FLAGS_WEEKLY)) - result2 = DIALOG_STATUS_AVAILABLE_REP; - else - result2 = DIALOG_STATUS_AVAILABLE; - } - else - result2 = DIALOG_STATUS_LOW_LEVEL_AVAILABLE; - } - else - result2 = DIALOG_STATUS_UNAVAILABLE; - } - } - - if (result2 > result) - result = result2; - } - - return result; -} - -void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY"); - - uint32 count = 0; - - WorldPacket data(SMSG_QUESTGIVER_STATUS_MULTIPLE, 4); - data << uint32(count); // placeholder - - for (Player::ClientGUIDs::const_iterator itr = _player->m_clientGUIDs.begin(); itr != _player->m_clientGUIDs.end(); ++itr) - { - uint8 questStatus = DIALOG_STATUS_NONE; - uint8 defstatus = DIALOG_STATUS_NONE; - - if (IS_CRE_OR_VEH_OR_PET_GUID(*itr)) - { - // need also pet quests case support - Creature* questgiver = ObjectAccessor::GetCreatureOrPetOrVehicle(*GetPlayer(), *itr); - if (!questgiver || questgiver->IsHostileTo(_player)) - continue; - if (!questgiver->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER)) - continue; - questStatus = sScriptMgr->GetDialogStatus(_player, questgiver); - if (questStatus > 6) - questStatus = getDialogStatus(_player, questgiver, defstatus); - - data << uint64(questgiver->GetGUID()); - data << uint8(questStatus); - ++count; - } - else if (IS_GAMEOBJECT_GUID(*itr)) - { - GameObject* questgiver = GetPlayer()->GetMap()->GetGameObject(*itr); - if (!questgiver) - continue; - if (questgiver->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER) - continue; - questStatus = sScriptMgr->GetDialogStatus(_player, questgiver); - if (questStatus > 6) - questStatus = getDialogStatus(_player, questgiver, defstatus); - - data << uint64(questgiver->GetGUID()); - data << uint8(questStatus); - ++count; - } - } - - data.put(0, count); // write real count - SendPacket(&data); -} - -void WorldSession::HandleQueryQuestsCompleted(WorldPacket & /*recv_data*/) -{ - size_t rew_count = _player->GetRewardedQuestCount(); - - WorldPacket data(SMSG_QUERY_QUESTS_COMPLETED_RESPONSE, 4 + 4 * rew_count); - data << uint32(rew_count); - - const RewardedQuestSet &rewQuests = _player->getRewardedQuests(); - for (RewardedQuestSet::const_iterator itr = rewQuests.begin(); itr != rewQuests.end(); ++itr) - data << uint32(*itr); - - SendPacket(&data); -} diff --git a/src/server/game/Server/Protocol/Handlers/ReferAFriendHandler.cpp b/src/server/game/Server/Protocol/Handlers/ReferAFriendHandler.cpp deleted file mode 100644 index 58d425ddf98..00000000000 --- a/src/server/game/Server/Protocol/Handlers/ReferAFriendHandler.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2011 TrinityCore - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "WorldSession.h" -#include "Player.h" -#include "ObjectMgr.h" -#include "Opcodes.h" -#include "Log.h" - -void WorldSession::HandleGrantLevel(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_GRANT_LEVEL"); - - uint64 guid; - recv_data.readPackGUID(guid); - - Player* target = ObjectAccessor::GetObjectInWorld(guid, _player); - - // check cheating - uint8 levels = _player->GetGrantableLevels(); - uint8 error = 0; - if (!target) - error = ERR_REFER_A_FRIEND_NO_TARGET; - else if (levels == 0) - error = ERR_REFER_A_FRIEND_INSUFFICIENT_GRANTABLE_LEVELS; - else if (GetRecruiterId() != target->GetSession()->GetAccountId()) - error = ERR_REFER_A_FRIEND_NOT_REFERRED_BY; - else if (target->GetTeamId() != _player->GetTeamId()) - error = ERR_REFER_A_FRIEND_DIFFERENT_FACTION; - else if (target->getLevel() >= _player->getLevel()) - error = ERR_REFER_A_FRIEND_TARGET_TOO_HIGH; - else if (target->getLevel() >= sWorld->getIntConfig(CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL)) - error = ERR_REFER_A_FRIEND_GRANT_LEVEL_MAX_I; - else if (target->GetGroup() != _player->GetGroup()) - error = ERR_REFER_A_FRIEND_NOT_IN_GROUP; - - if (error) { - WorldPacket data(SMSG_REFER_A_FRIEND_FAILURE, 24); - data << uint32(error); - if (error == ERR_REFER_A_FRIEND_NOT_IN_GROUP) - data << target->GetName(); - - SendPacket(&data); - return; - } - - WorldPacket data2(SMSG_PROPOSE_LEVEL_GRANT, 8); - data2.append(_player->GetPackGUID()); - target->GetSession()->SendPacket(&data2); -} - -void WorldSession::HandleAcceptGrantLevel(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_ACCEPT_LEVEL_GRANT"); - - uint64 guid; - recv_data.readPackGUID(guid); - - Player* other = ObjectAccessor::GetObjectInWorld(guid, _player); - if (!(other && other->GetSession())) - return; - - if (GetAccountId() != other->GetSession()->GetRecruiterId()) - return; - - if (other->GetGrantableLevels()) - other->SetGrantableLevels(other->GetGrantableLevels() - 1); - else - return; - - _player->GiveLevel(_player->getLevel() + 1); -} diff --git a/src/server/game/Server/Protocol/Handlers/SkillHandler.cpp b/src/server/game/Server/Protocol/Handlers/SkillHandler.cpp deleted file mode 100755 index 520cd89e7d5..00000000000 --- a/src/server/game/Server/Protocol/Handlers/SkillHandler.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "DatabaseEnv.h" -#include "Opcodes.h" -#include "Log.h" -#include "Player.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "ObjectAccessor.h" -#include "UpdateMask.h" - -void WorldSession::HandleLearnTalentOpcode(WorldPacket & recv_data) -{ - uint32 talent_id, requested_rank; - recv_data >> talent_id >> requested_rank; - - _player->LearnTalent(talent_id, requested_rank); - _player->SendTalentsInfoData(false); -} - -void WorldSession::HandleLearnPreviewTalents(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LEARN_PREVIEW_TALENTS"); - - uint32 talentsCount; - recvPacket >> talentsCount; - - uint32 talentId, talentRank; - - for (uint32 i = 0; i < talentsCount; ++i) - { - recvPacket >> talentId >> talentRank; - - _player->LearnTalent(talentId, talentRank); - } - - _player->SendTalentsInfoData(false); -} - -void WorldSession::HandleTalentWipeConfirmOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "MSG_TALENT_WIPE_CONFIRM"); - uint64 guid; - recv_data >> guid; - - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER); - if (!unit) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleTalentWipeConfirmOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - if (!(_player->resetTalents())) - { - WorldPacket data(MSG_TALENT_WIPE_CONFIRM, 8+4); //you have not any talent - data << uint64(0); - data << uint32(0); - SendPacket(&data); - return; - } - - _player->SendTalentsInfoData(false); - unit->CastSpell(_player, 14867, true); //spell: "Untalent Visual Effect" -} - -void WorldSession::HandleUnlearnSkillOpcode(WorldPacket & recv_data) -{ - uint32 skill_id; - recv_data >> skill_id; - GetPlayer()->SetSkill(skill_id, 0, 0, 0); -} - diff --git a/src/server/game/Server/Protocol/Handlers/SpellHandler.cpp b/src/server/game/Server/Protocol/Handlers/SpellHandler.cpp deleted file mode 100755 index b8908d0f9f9..00000000000 --- a/src/server/game/Server/Protocol/Handlers/SpellHandler.cpp +++ /dev/null @@ -1,686 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "DBCStores.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "ObjectMgr.h" -#include "SpellMgr.h" -#include "Log.h" -#include "Opcodes.h" -#include "Spell.h" -#include "Totem.h" -#include "TemporarySummon.h" -#include "SpellAuras.h" -#include "CreatureAI.h" -#include "ScriptMgr.h" -#include "GameObjectAI.h" -#include "SpellAuraEffects.h" - -void WorldSession::HandleClientCastFlags(WorldPacket& recvPacket, uint8 castFlags, SpellCastTargets& targets) -{ - // some spell cast packet including more data (for projectiles?) - if (castFlags & 0x02) - { - // not sure about these two - float elevation, speed; - recvPacket >> elevation; - recvPacket >> speed; - - targets.SetElevation(elevation); - targets.SetSpeed(speed); - - uint8 hasMovementData; - recvPacket >> hasMovementData; - if (hasMovementData) - { - recvPacket.rfinish(); - // movement packet for caster of the spell - /*recvPacket.read_skip(); // MSG_MOVE_STOP - hardcoded in client - uint64 guid; - recvPacket.readPackGUID(guid); - - MovementInfo movementInfo; - movementInfo.guid = guid; - ReadMovementInfo(recvPacket, &movementInfo);*/ - } - } -} - -void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) -{ - // TODO: add targets.read() check - Player* pUser = _player; - - // ignore for remote control state - if (pUser->m_mover != pUser) - return; - - uint8 bagIndex, slot, castFlags; - uint8 castCount; // next cast if exists (single or not) - uint64 itemGUID; - uint32 glyphIndex; // something to do with glyphs? - uint32 spellId; // casted spell id - - recvPacket >> bagIndex >> slot >> castCount >> spellId >> itemGUID >> glyphIndex >> castFlags; - - if (glyphIndex >= MAX_GLYPH_SLOT_INDEX) - { - pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } - - Item* pItem = pUser->GetUseableItemByPos(bagIndex, slot); - if (!pItem) - { - pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } - - if (pItem->GetGUID() != itemGUID) - { - pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } - - sLog->outDetail("WORLD: CMSG_USE_ITEM packet, bagIndex: %u, slot: %u, castCount: %u, spellId: %u, Item: %u, glyphIndex: %u, data length = %i", bagIndex, slot, castCount, spellId, pItem->GetEntry(), glyphIndex, (uint32)recvPacket.size()); - - ItemTemplate const* proto = pItem->GetTemplate(); - if (!proto) - { - pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL); - return; - } - - // some item classes can be used only in equipped state - if (proto->InventoryType != INVTYPE_NON_EQUIP && !pItem->IsEquipped()) - { - pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL); - return; - } - - InventoryResult msg = pUser->CanUseItem(pItem); - if (msg != EQUIP_ERR_OK) - { - pUser->SendEquipError(msg, pItem, NULL); - return; - } - - // only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB) - if (proto->Class == ITEM_CLASS_CONSUMABLE && !(proto->Flags & ITEM_PROTO_FLAG_USEABLE_IN_ARENA) && pUser->InArena()) - { - pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH, pItem, NULL); - return; - } - - // don't allow items banned in arena - if (proto->Flags & ITEM_PROTO_FLAG_NOT_USEABLE_IN_ARENA && pUser->InArena()) - { - pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH, pItem, NULL); - return; - } - - if (pUser->isInCombat()) - { - for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) - { - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(proto->Spells[i].SpellId)) - { - if (!spellInfo->CanBeUsedInCombat()) - { - pUser->SendEquipError(EQUIP_ERR_NOT_IN_COMBAT, pItem, NULL); - return; - } - } - } - } - - // check also BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory) - if (pItem->GetTemplate()->Bonding == BIND_WHEN_USE || pItem->GetTemplate()->Bonding == BIND_WHEN_PICKED_UP || pItem->GetTemplate()->Bonding == BIND_QUEST_ITEM) - { - if (!pItem->IsSoulBound()) - { - pItem->SetState(ITEM_CHANGED, pUser); - pItem->SetBinding(true); - } - } - - SpellCastTargets targets; - targets.Read(recvPacket, pUser); - HandleClientCastFlags(recvPacket, castFlags, targets); - - if (!pItem->IsTargetValidForItemUse(targets.GetUnitTarget())) - { - // free gray item after use fail - pUser->SendEquipError(EQUIP_ERR_NONE, pItem, NULL); - - // send spell error - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId)) - { - // for implicit area/coord target spells - if (!targets.GetUnitTarget()) - Spell::SendCastResult(_player, spellInfo, castCount, SPELL_FAILED_NO_VALID_TARGETS); - // for explicit target spells - else - Spell::SendCastResult(_player, spellInfo, castCount, SPELL_FAILED_BAD_TARGETS); - } - return; - } - - // Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state. - if (!sScriptMgr->OnItemUse(pUser, pItem, targets)) - { - // no script or script not process request by self - pUser->CastItemUseSpell(pItem, targets, castCount, glyphIndex); - } -} - -#define OPEN_CHEST 11437 -#define OPEN_SAFE 11535 -#define OPEN_CAGE 11792 -#define OPEN_BOOTY_CHEST 5107 -#define OPEN_STRONGBOX 8517 - -void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket) -{ - sLog->outDetail("WORLD: CMSG_OPEN_ITEM packet, data length = %i", (uint32)recvPacket.size()); - - Player* pUser = _player; - - // ignore for remote control state - if (pUser->m_mover != pUser) - return; - - uint8 bagIndex, slot; - - recvPacket >> bagIndex >> slot; - - sLog->outDetail("bagIndex: %u, slot: %u", bagIndex, slot); - - Item* item = pUser->GetItemByPos(bagIndex, slot); - if (!item) - { - pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; - } - - ItemTemplate const* proto = item->GetTemplate(); - if (!proto) - { - pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, item, NULL); - return; - } - - // Verify that the bag is an actual bag or wrapped item that can be used "normally" - if (!(proto->Flags & ITEM_PROTO_FLAG_OPENABLE) && !item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) - { - pUser->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, item, NULL); - sLog->outError("Possible hacking attempt: Player %s [guid: %u] tried to open item [guid: %u, entry: %u] which is not openable!", - pUser->GetName(), pUser->GetGUIDLow(), item->GetGUIDLow(), proto->ItemId); - return; - } - - // locked item - uint32 lockId = proto->LockID; - if (lockId) - { - LockEntry const* lockInfo = sLockStore.LookupEntry(lockId); - - if (!lockInfo) - { - pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, item, NULL); - sLog->outError("WORLD::OpenItem: item [guid = %u] has an unknown lockId: %u!", item->GetGUIDLow(), lockId); - return; - } - - // was not unlocked yet - if (item->IsLocked()) - { - pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, item, NULL); - return; - } - } - - if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED))// wrapped? - { - QueryResult result = CharacterDatabase.PQuery("SELECT entry, flags FROM character_gifts WHERE item_guid = '%u'", item->GetGUIDLow()); - if (result) - { - Field* fields = result->Fetch(); - uint32 entry = fields[0].GetUInt32(); - uint32 flags = fields[1].GetUInt32(); - - item->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, 0); - item->SetEntry(entry); - item->SetUInt32Value(ITEM_FIELD_FLAGS, flags); - item->SetState(ITEM_CHANGED, pUser); - } - else - { - sLog->outError("Wrapped item %u don't have record in character_gifts table and will deleted", item->GetGUIDLow()); - pUser->DestroyItem(item->GetBagSlot(), item->GetSlot(), true); - return; - } - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GIFT); - - stmt->setUInt32(0, item->GetGUIDLow()); - - CharacterDatabase.Execute(stmt); - } - else - pUser->SendLoot(item->GetGUID(), LOOT_CORPSE); -} - -void WorldSession::HandleGameObjectUseOpcode(WorldPacket & recv_data) -{ - uint64 guid; - - recv_data >> guid; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_GAMEOBJ_USE Message [guid=%u]", GUID_LOPART(guid)); - - // ignore for remote control state - if (_player->m_mover != _player) - return; - - if (GameObject* obj = GetPlayer()->GetMap()->GetGameObject(guid)) - obj->Use(_player); -} - -void WorldSession::HandleGameobjectReportUse(WorldPacket& recvPacket) -{ - uint64 guid; - recvPacket >> guid; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_GAMEOBJ_REPORT_USE Message [in game guid: %u]", GUID_LOPART(guid)); - - // ignore for remote control state - if (_player->m_mover != _player) - return; - - GameObject* go = GetPlayer()->GetMap()->GetGameObject(guid); - if (!go) - return; - - if (!go->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) - return; - - go->AI()->GossipHello(_player); - - _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT, go->GetEntry()); -} - -void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) -{ - uint32 spellId; - uint8 castCount, castFlags; - recvPacket >> castCount >> spellId >> castFlags; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: got cast spell packet, castCount: %u, spellId: %u, castFlags: %u, data length = %u", castCount, spellId, castFlags, (uint32)recvPacket.size()); - - // ignore for remote control state (for player case) - Unit* mover = _player->m_mover; - if (mover != _player && mover->GetTypeId() == TYPEID_PLAYER) - { - recvPacket.rfinish(); // prevent spam at ignore packet - return; - } - - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); - - if (!spellInfo) - { - sLog->outError("WORLD: unknown spell id %u", spellId); - recvPacket.rfinish(); // prevent spam at ignore packet - return; - } - - if (mover->GetTypeId() == TYPEID_PLAYER) - { - // not have spell in spellbook or spell passive and not casted by client - if (!mover->ToPlayer()->HasActiveSpell (spellId) || spellInfo->IsPassive()) - { - //cheater? kick? ban? - recvPacket.rfinish(); // prevent spam at ignore packet - return; - } - } - else - { - // not have spell in spellbook or spell passive and not casted by client - if ((mover->GetTypeId() == TYPEID_UNIT && !mover->ToCreature()->HasSpell(spellId)) || spellInfo->IsPassive()) - { - //cheater? kick? ban? - recvPacket.rfinish(); // prevent spam at ignore packet - return; - } - } - - // Client is resending autoshot cast opcode when other spell is casted during shoot rotation - // Skip it to prevent "interrupt" message - if (spellInfo->IsAutoRepeatRangedSpell() && _player->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL) - && _player->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL)->m_spellInfo == spellInfo) - { - recvPacket.rfinish(); - return; - } - - // can't use our own spells when we're in possession of another unit, - if (_player->isPossessing()) - { - recvPacket.rfinish(); // prevent spam at ignore packet - return; - } - - // client provided targets - SpellCastTargets targets; - targets.Read(recvPacket, mover); - HandleClientCastFlags(recvPacket, castFlags, targets); - - // auto-selection buff level base at target level (in spellInfo) - if (targets.GetUnitTarget()) - { - SpellInfo const* actualSpellInfo = spellInfo->GetAuraRankForLevel(targets.GetUnitTarget()->getLevel()); - - // if rank not found then function return NULL but in explicit cast case original spell can be casted and later failed with appropriate error message - if (actualSpellInfo) - spellInfo = actualSpellInfo; - } - - Spell* spell = new Spell(mover, spellInfo, TRIGGERED_NONE, 0, false); - spell->m_cast_count = castCount; // set count of casts - spell->prepare(&targets); -} - -void WorldSession::HandleCancelCastOpcode(WorldPacket& recvPacket) -{ - uint32 spellId; - - recvPacket.read_skip(); // counter, increments with every CANCEL packet, don't use for now - recvPacket >> spellId; - - if (_player->IsNonMeleeSpellCasted(false)) - _player->InterruptNonMeleeSpells(false, spellId, false); -} - -void WorldSession::HandleCancelAuraOpcode(WorldPacket& recvPacket) -{ - uint32 spellId; - recvPacket >> spellId; - - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); - if (!spellInfo) - return; - - // not allow remove spells with attr SPELL_ATTR0_CANT_CANCEL - if (spellInfo->Attributes & SPELL_ATTR0_CANT_CANCEL) - return; - - // channeled spell case (it currently casted then) - if (spellInfo->IsChanneled()) - { - if (Spell* curSpell = _player->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) - if (curSpell->m_spellInfo->Id == spellId) - _player->InterruptSpell(CURRENT_CHANNELED_SPELL); - return; - } - - // non channeled case: - // don't allow remove non positive spells - // don't allow cancelling passive auras (some of them are visible) - if (!spellInfo->IsPositive() || spellInfo->IsPassive()) - return; - - // maybe should only remove one buff when there are multiple? - _player->RemoveOwnedAura(spellId, 0, 0, AURA_REMOVE_BY_CANCEL); -} - -void WorldSession::HandlePetCancelAuraOpcode(WorldPacket& recvPacket) -{ - uint64 guid; - uint32 spellId; - - recvPacket >> guid; - recvPacket >> spellId; - - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); - if (!spellInfo) - { - sLog->outError("WORLD: unknown PET spell id %u", spellId); - return; - } - - Creature* pet=ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); - - if (!pet) - { - sLog->outError("HandlePetCancelAura: Attempt to cancel an aura for non-existant pet %u by player '%s'", uint32(GUID_LOPART(guid)), GetPlayer()->GetName()); - return; - } - - if (pet != GetPlayer()->GetGuardianPet() && pet != GetPlayer()->GetCharm()) - { - sLog->outError("HandlePetCancelAura: Pet %u is not a pet of player '%s'", uint32(GUID_LOPART(guid)), GetPlayer()->GetName()); - return; - } - - if (!pet->isAlive()) - { - pet->SendPetActionFeedback(FEEDBACK_PET_DEAD); - return; - } - - pet->RemoveOwnedAura(spellId, 0, 0, AURA_REMOVE_BY_CANCEL); - - pet->AddCreatureSpellCooldown(spellId); -} - -void WorldSession::HandleCancelGrowthAuraOpcode(WorldPacket& /*recvPacket*/) -{ -} - -void WorldSession::HandleCancelAutoRepeatSpellOpcode(WorldPacket& /*recvPacket*/) -{ - // may be better send SMSG_CANCEL_AUTO_REPEAT? - // cancel and prepare for deleting - _player->InterruptSpell(CURRENT_AUTOREPEAT_SPELL); -} - -void WorldSession::HandleCancelChanneling(WorldPacket & recv_data) -{ - recv_data.read_skip(); // spellid, not used - - // ignore for remote control state (for player case) - Unit* mover = _player->m_mover; - if (mover != _player && mover->GetTypeId() == TYPEID_PLAYER) - return; - - mover->InterruptSpell(CURRENT_CHANNELED_SPELL); -} - -void WorldSession::HandleTotemDestroyed(WorldPacket& recvPacket) -{ - // ignore for remote control state - if (_player->m_mover != _player) - return; - - uint8 slotId; - - recvPacket >> slotId; - - ++slotId; - if (slotId >= MAX_TOTEM_SLOT) - return; - - if (!_player->m_SummonSlot[slotId]) - return; - - Creature* totem = GetPlayer()->GetMap()->GetCreature(_player->m_SummonSlot[slotId]); - // Don't unsummon sentry totem - if (totem && totem->isTotem() && totem->GetEntry() != SENTRY_TOTEM_ENTRY) - totem->ToTotem()->UnSummon(); -} - -void WorldSession::HandleSelfResOpcode(WorldPacket & /*recv_data*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_SELF_RES"); // empty opcode - - if (_player->HasAuraType(SPELL_AURA_PREVENT_RESURRECTION)) - return; // silent return, client should display error by itself and not send this opcode - - if (_player->GetUInt32Value(PLAYER_SELF_RES_SPELL)) - { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(_player->GetUInt32Value(PLAYER_SELF_RES_SPELL)); - if (spellInfo) - _player->CastSpell(_player, spellInfo, false, 0); - - _player->SetUInt32Value(PLAYER_SELF_RES_SPELL, 0); - } -} - -void WorldSession::HandleSpellClick(WorldPacket& recv_data) -{ - uint64 guid; - recv_data >> guid; - - // this will get something not in world. crash - Creature* unit = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); - - if (!unit) - return; - - // TODO: Unit::SetCharmedBy: 28782 is not in world but 0 is trying to charm it! -> crash - if (!unit->IsInWorld()) - return; - - unit->HandleSpellClick(_player); -} - -void WorldSession::HandleMirrorImageDataRequest(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_GET_MIRRORIMAGE_DATA"); - uint64 guid; - recv_data >> guid; - - // Get unit for which data is needed by client - Unit* unit = ObjectAccessor::GetObjectInWorld(guid, (Unit*)NULL); - if (!unit) - return; - - if (!unit->HasAuraType(SPELL_AURA_CLONE_CASTER)) - return; - - // Get creator of the unit (SPELL_AURA_CLONE_CASTER does not stack) - Unit* creator = unit->GetAuraEffectsByType(SPELL_AURA_CLONE_CASTER).front()->GetCaster(); - if (!creator) - return; - - WorldPacket data(SMSG_MIRRORIMAGE_DATA, 68); - data << uint64(guid); - data << uint32(creator->GetDisplayId()); - data << uint8(creator->getRace()); - data << uint8(creator->getGender()); - data << uint8(creator->getClass()); - - if (creator->GetTypeId() == TYPEID_PLAYER) - { - Player* player = creator->ToPlayer(); - data << uint8(player->GetByteValue(PLAYER_BYTES, 0)); // skin - data << uint8(player->GetByteValue(PLAYER_BYTES, 1)); // face - data << uint8(player->GetByteValue(PLAYER_BYTES, 2)); // hair - data << uint8(player->GetByteValue(PLAYER_BYTES, 3)); // haircolor - data << uint8(player->GetByteValue(PLAYER_BYTES_2, 0)); // facialhair - data << uint32(player->GetGuildId()); // unk - - static EquipmentSlots const itemSlots[] = - { - EQUIPMENT_SLOT_HEAD, - EQUIPMENT_SLOT_SHOULDERS, - EQUIPMENT_SLOT_BODY, - EQUIPMENT_SLOT_CHEST, - EQUIPMENT_SLOT_WAIST, - EQUIPMENT_SLOT_LEGS, - EQUIPMENT_SLOT_FEET, - EQUIPMENT_SLOT_WRISTS, - EQUIPMENT_SLOT_HANDS, - EQUIPMENT_SLOT_BACK, - EQUIPMENT_SLOT_TABARD, - EQUIPMENT_SLOT_END - }; - - // Display items in visible slots - for (EquipmentSlots const* itr = &itemSlots[0]; *itr != EQUIPMENT_SLOT_END; ++itr) - { - if (*itr == EQUIPMENT_SLOT_HEAD && player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM)) - data << uint32(0); - else if (*itr == EQUIPMENT_SLOT_BACK && player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK)) - data << uint32(0); - else if (Item const* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, *itr)) - data << uint32(item->GetTemplate()->DisplayInfoID); - else - data << uint32(0); - } - } - else - { - // Skip player data for creatures - data << uint8(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - data << uint32(0); - } - - SendPacket(&data); -} - -void WorldSession::HandleUpdateProjectilePosition(WorldPacket& recvPacket) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_UPDATE_PROJECTILE_POSITION"); - - uint64 casterGuid; - uint32 spellId; - uint8 castCount; - float x, y, z; // Position of missile hit - - recvPacket.readPackGUID(casterGuid); - recvPacket >> spellId; - recvPacket >> castCount; - recvPacket >> x; - recvPacket >> y; - recvPacket >> z; - - WorldPacket data(SMSG_SET_PROJECTILE_POSITION, 21); - data << uint64(casterGuid); - data << uint8(castCount); - data << float(x); - data << float(y); - data << float(z); - SendPacket(&data); -} diff --git a/src/server/game/Server/Protocol/Handlers/TaxiHandler.cpp b/src/server/game/Server/Protocol/Handlers/TaxiHandler.cpp deleted file mode 100755 index 3533b153bd8..00000000000 --- a/src/server/game/Server/Protocol/Handlers/TaxiHandler.cpp +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "DatabaseEnv.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Opcodes.h" -#include "Log.h" -#include "ObjectMgr.h" -#include "Player.h" -#include "UpdateMask.h" -#include "Path.h" -#include "WaypointMovementGenerator.h" - -void WorldSession::HandleTaxiNodeStatusQueryOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_TAXINODE_STATUS_QUERY"); - - uint64 guid; - - recv_data >> guid; - SendTaxiStatus(guid); -} - -void WorldSession::SendTaxiStatus(uint64 guid) -{ - // cheating checks - Creature* unit = GetPlayer()->GetMap()->GetCreature(guid); - if (!unit) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WorldSession::SendTaxiStatus - Unit (GUID: %u) not found.", uint32(GUID_LOPART(guid))); - return; - } - - uint32 curloc = sObjectMgr->GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), GetPlayer()->GetTeam()); - - // not found nearest - if (curloc == 0) - return; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: current location %u ", curloc); - - WorldPacket data(SMSG_TAXINODE_STATUS, 9); - data << guid; - data << uint8(GetPlayer()->m_taxi.IsTaximaskNodeKnown(curloc) ? 1 : 0); - SendPacket(&data); - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_TAXINODE_STATUS"); -} - -void WorldSession::HandleTaxiQueryAvailableNodes(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_TAXIQUERYAVAILABLENODES"); - - uint64 guid; - recv_data >> guid; - - // cheating checks - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER); - if (!unit) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleTaxiQueryAvailableNodes - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); - return; - } - - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - // unknown taxi node case - if (SendLearnNewTaxiNode(unit)) - return; - - // known taxi node case - SendTaxiMenu(unit); -} - -void WorldSession::SendTaxiMenu(Creature* unit) -{ - // find current node - uint32 curloc = sObjectMgr->GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), GetPlayer()->GetTeam()); - - if (curloc == 0) - return; - - bool lastTaxiCheaterState = GetPlayer()->isTaxiCheater(); - if (unit->GetEntry() == 29480) GetPlayer()->SetTaxiCheater(true); // Grimwing in Ebon Hold, special case. NOTE: Not perfect, Zul'Aman should not be included according to WoWhead, and I think taxicheat includes it. - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_TAXINODE_STATUS_QUERY %u ", curloc); - - WorldPacket data(SMSG_SHOWTAXINODES, (4+8+4+8*4)); - data << uint32(1); - data << uint64(unit->GetGUID()); - data << uint32(curloc); - GetPlayer()->m_taxi.AppendTaximaskTo(data, GetPlayer()->isTaxiCheater()); - SendPacket(&data); - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_SHOWTAXINODES"); - - GetPlayer()->SetTaxiCheater(lastTaxiCheaterState); -} - -void WorldSession::SendDoFlight(uint32 mountDisplayId, uint32 path, uint32 pathNode) -{ - // remove fake death - if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - - while (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) - GetPlayer()->GetMotionMaster()->MovementExpired(false); - - if (mountDisplayId) - GetPlayer()->Mount(mountDisplayId); - - GetPlayer()->GetMotionMaster()->MoveTaxiFlight(path, pathNode); -} - -bool WorldSession::SendLearnNewTaxiNode(Creature* unit) -{ - // find current node - uint32 curloc = sObjectMgr->GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), GetPlayer()->GetTeam()); - - if (curloc == 0) - return true; // `true` send to avoid WorldSession::SendTaxiMenu call with one more curlock seartch with same false result. - - if (GetPlayer()->m_taxi.SetTaximaskNode(curloc)) - { - WorldPacket msg(SMSG_NEW_TAXI_PATH, 0); - SendPacket(&msg); - - WorldPacket update(SMSG_TAXINODE_STATUS, 9); - update << uint64(unit->GetGUID()); - update << uint8(1); - SendPacket(&update); - - return true; - } - else - return false; -} - -void WorldSession::SendDiscoverNewTaxiNode(uint32 nodeid) -{ - if (GetPlayer()->m_taxi.SetTaximaskNode(nodeid)) - { - WorldPacket msg(SMSG_NEW_TAXI_PATH, 0); - SendPacket(&msg); - } -} - -void WorldSession::HandleActivateTaxiExpressOpcode (WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_ACTIVATETAXIEXPRESS"); - - uint64 guid; - uint32 node_count; - - recv_data >> guid >> node_count; - - Creature* npc = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER); - if (!npc) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleActivateTaxiExpressOpcode - Unit (GUID: %u) not found or you can't interact with it.", uint32(GUID_LOPART(guid))); - return; - } - std::vector nodes; - - for (uint32 i = 0; i < node_count; ++i) - { - uint32 node; - recv_data >> node; - nodes.push_back(node); - } - - if (nodes.empty()) - return; - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_ACTIVATETAXIEXPRESS from %d to %d", nodes.front(), nodes.back()); - - GetPlayer()->ActivateTaxiPathTo(nodes, npc); -} - -void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_MOVE_SPLINE_DONE"); - - uint64 guid; // used only for proper packet read - recv_data.readPackGUID(guid); - - MovementInfo movementInfo; // used only for proper packet read - ReadMovementInfo(recv_data, &movementInfo); - - recv_data.read_skip(); // unk - - // in taxi flight packet received in 2 case: - // 1) end taxi path in far (multi-node) flight - // 2) switch from one map to other in case multim-map taxi path - // we need process only (1) - - uint32 curDest = GetPlayer()->m_taxi.GetTaxiDestination(); - if (!curDest) - return; - - TaxiNodesEntry const* curDestNode = sTaxiNodesStore.LookupEntry(curDest); - - // far teleport case - if (curDestNode && curDestNode->map_id != GetPlayer()->GetMapId()) - { - if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) - { - // short preparations to continue flight - FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top()); - - flight->SetCurrentNodeAfterTeleport(); - TaxiPathNodeEntry const& node = flight->GetPath()[flight->GetCurrentNode()]; - flight->SkipCurrentNode(); - - GetPlayer()->TeleportTo(curDestNode->map_id, node.x, node.y, node.z, GetPlayer()->GetOrientation()); - } - return; - } - - uint32 destinationnode = GetPlayer()->m_taxi.NextTaxiDestination(); - if (destinationnode > 0) // if more destinations to go - { - // current source node for next destination - uint32 sourcenode = GetPlayer()->m_taxi.GetTaxiSource(); - - // Add to taximask middle hubs in taxicheat mode (to prevent having player with disabled taxicheat and not having back flight path) - if (GetPlayer()->isTaxiCheater()) - { - if (GetPlayer()->m_taxi.SetTaximaskNode(sourcenode)) - { - WorldPacket data(SMSG_NEW_TAXI_PATH, 0); - _player->GetSession()->SendPacket(&data); - } - } - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Taxi has to go from %u to %u", sourcenode, destinationnode); - - uint32 mountDisplayId = sObjectMgr->GetTaxiMountDisplayId(sourcenode, GetPlayer()->GetTeam()); - - uint32 path, cost; - sObjectMgr->GetTaxiPath(sourcenode, destinationnode, path, cost); - - if (path && mountDisplayId) - SendDoFlight(mountDisplayId, path, 1); // skip start fly node - else - GetPlayer()->m_taxi.ClearTaxiDestinations(); // clear problematic path and next - return; - } - else - GetPlayer()->m_taxi.ClearTaxiDestinations(); // not destinations, clear source node - - GetPlayer()->CleanupAfterTaxiFlight(); - GetPlayer()->SetFallInformation(0, GetPlayer()->GetPositionZ()); - if (GetPlayer()->pvpInfo.inHostileArea) - GetPlayer()->CastSpell(GetPlayer(), 2479, true); -} - -void WorldSession::HandleActivateTaxiOpcode(WorldPacket & recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_ACTIVATETAXI"); - - uint64 guid; - std::vector nodes; - nodes.resize(2); - - recv_data >> guid >> nodes[0] >> nodes[1]; - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_ACTIVATETAXI from %d to %d", nodes[0], nodes[1]); - Creature* npc = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER); - if (!npc) - { - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleActivateTaxiOpcode - Unit (GUID: %u) not found or you can't interact with it.", uint32(GUID_LOPART(guid))); - return; - } - - GetPlayer()->ActivateTaxiPathTo(nodes, npc); -} diff --git a/src/server/game/Server/Protocol/Handlers/TicketHandler.cpp b/src/server/game/Server/Protocol/Handlers/TicketHandler.cpp deleted file mode 100755 index a270d42b000..00000000000 --- a/src/server/game/Server/Protocol/Handlers/TicketHandler.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Language.h" -#include "WorldPacket.h" -#include "Common.h" -#include "ObjectMgr.h" -#include "TicketMgr.h" -#include "Player.h" -#include "World.h" -#include "WorldSession.h" -#include "Util.h" - -void WorldSession::HandleGMTicketCreateOpcode(WorldPacket & recv_data) -{ - // Don't accept tickets if the ticket queue is disabled. (Ticket UI is greyed out but not fully dependable) - if (sTicketMgr->GetStatus() == GMTICKET_QUEUE_STATUS_DISABLED) - return; - - if (GetPlayer()->getLevel() < sWorld->getIntConfig(CONFIG_TICKET_LEVEL_REQ)) - { - SendNotification(GetTrinityString(LANG_TICKET_REQ), sWorld->getIntConfig(CONFIG_TICKET_LEVEL_REQ)); - return; - } - - GMTicketResponse response = GMTICKET_RESPONSE_FAILURE; - // Player must not have ticket - if (!sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID())) - { - GmTicket* ticket = new GmTicket(GetPlayer(), recv_data); - sTicketMgr->AddTicket(ticket); - sTicketMgr->UpdateLastChange(); - - sWorld->SendGMText(LANG_COMMAND_TICKETNEW, GetPlayer()->GetName(), ticket->GetId()); - - response = GMTICKET_RESPONSE_SUCCESS; - } - - WorldPacket data(SMSG_GMTICKET_CREATE, 4); - data << uint32(response); - SendPacket(&data); -} - -void WorldSession::HandleGMTicketUpdateOpcode(WorldPacket & recv_data) -{ - std::string message; - recv_data >> message; - - GMTicketResponse response = GMTICKET_RESPONSE_FAILURE; - if (GmTicket *ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID())) - { - SQLTransaction trans = SQLTransaction(NULL); - ticket->SetMessage(message); - ticket->SaveToDB(trans); - - sWorld->SendGMText(LANG_COMMAND_TICKETUPDATED, GetPlayer()->GetName(), ticket->GetId()); - - response = GMTICKET_RESPONSE_SUCCESS; - } - - WorldPacket data(SMSG_GMTICKET_UPDATETEXT, 4); - data << uint32(response); - SendPacket(&data); -} - -void WorldSession::HandleGMTicketDeleteOpcode(WorldPacket & /*recv_data*/) -{ - if (GmTicket* ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID())) - { - WorldPacket data(SMSG_GMTICKET_DELETETICKET, 4); - data << uint32(GMTICKET_RESPONSE_TICKET_DELETED); - SendPacket(&data); - - sWorld->SendGMText(LANG_COMMAND_TICKETPLAYERABANDON, GetPlayer()->GetName(), ticket->GetId()); - - sTicketMgr->CloseTicket(ticket->GetId(), GetPlayer()->GetGUID()); - sTicketMgr->SendTicket(this, NULL); - } -} - -void WorldSession::HandleGMTicketGetTicketOpcode(WorldPacket & /*recv_data*/) -{ - SendQueryTimeResponse(); - - if (GmTicket* ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID())) - { - if (ticket->IsCompleted()) - ticket->SendResponse(this); - else - sTicketMgr->SendTicket(this, ticket); - } - else - sTicketMgr->SendTicket(this, NULL); -} - -void WorldSession::HandleGMTicketSystemStatusOpcode(WorldPacket & /*recv_data*/) -{ - // Note: This only disables the ticket UI at client side and is not fully reliable - // are we sure this is a uint32? Should ask Zor - WorldPacket data(SMSG_GMTICKET_SYSTEMSTATUS, 4); - data << uint32(sTicketMgr->GetStatus() ? GMTICKET_QUEUE_STATUS_ENABLED : GMTICKET_QUEUE_STATUS_DISABLED); - SendPacket(&data); -} - -void WorldSession::HandleGMSurveySubmit(WorldPacket& recv_data) -{ - uint32 nextSurveyID = sTicketMgr->GetNextSurveyID(); - // just put the survey into the database - uint32 mainSurvey; // GMSurveyCurrentSurvey.dbc, column 1 (all 9) ref to GMSurveySurveys.dbc - recv_data >> mainSurvey; - - // sub_survey1, r1, comment1, sub_survey2, r2, comment2, sub_survey3, r3, comment3, sub_survey4, r4, comment4, sub_survey5, r5, comment5, sub_survey6, r6, comment6, sub_survey7, r7, comment7, sub_survey8, r8, comment8, sub_survey9, r9, comment9, sub_survey10, r10, comment10, - for (uint8 i = 0; i < 10; i++) - { - uint32 subSurveyId; // ref to i'th GMSurveySurveys.dbc field (all fields in that dbc point to fields in GMSurveyQuestions.dbc) - recv_data >> subSurveyId; - if (!subSurveyId) - break; - - uint8 rank; // probably some sort of ref to GMSurveyAnswers.dbc - recv_data >> rank; - std::string comment; // comment ("Usage: GMSurveyAnswerSubmit(question, rank, comment)") - recv_data >> comment; - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GM_SUBSURVEY); - stmt->setUInt32(0, nextSurveyID); - stmt->setUInt32(1, subSurveyId); - stmt->setUInt32(2, rank); - stmt->setString(3, comment); - CharacterDatabase.Execute(stmt); - } - - std::string comment; // just a guess - recv_data >> comment; - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GM_SURVEY); - stmt->setUInt32(0, GUID_LOPART(GetPlayer()->GetGUID())); - stmt->setUInt32(1, nextSurveyID); - stmt->setUInt32(2, mainSurvey); - stmt->setString(3, comment); - - CharacterDatabase.Execute(stmt); -} - -void WorldSession::HandleReportLag(WorldPacket& recv_data) -{ - // just put the lag report into the database... - // can't think of anything else to do with it - uint32 lagType, mapId; - recv_data >> lagType; - recv_data >> mapId; - float x, y, z; - recv_data >> x; - recv_data >> y; - recv_data >> z; - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_LAG_REPORT); - stmt->setUInt32(0, GUID_LOPART(GetPlayer()->GetGUID())); - stmt->setUInt8 (1, lagType); - stmt->setUInt16(2, mapId); - stmt->setFloat (3, x); - stmt->setFloat (4, y); - stmt->setFloat (5, z); - CharacterDatabase.Execute(stmt); -} - -void WorldSession::HandleGMResponseResolve(WorldPacket& /*recvPacket*/) -{ - // empty packet - if (GmTicket* ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID())) - { - uint8 getSurvey = 0; - if (float(rand_chance()) < sWorld->getFloatConfig(CONFIG_CHANCE_OF_GM_SURVEY)) - getSurvey = 1; - - WorldPacket data(SMSG_GMRESPONSE_STATUS_UPDATE, 4); - data << uint8(getSurvey); - SendPacket(&data); - - WorldPacket data2(SMSG_GMTICKET_DELETETICKET, 4); - data2 << uint32(GMTICKET_RESPONSE_TICKET_DELETED); - SendPacket(&data2); - - sTicketMgr->CloseTicket(ticket->GetId(), GetPlayer()->GetGUID()); - sTicketMgr->SendTicket(this, NULL); - } -} diff --git a/src/server/game/Server/Protocol/Handlers/TradeHandler.cpp b/src/server/game/Server/Protocol/Handlers/TradeHandler.cpp deleted file mode 100755 index ebe54eb17eb..00000000000 --- a/src/server/game/Server/Protocol/Handlers/TradeHandler.cpp +++ /dev/null @@ -1,731 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "World.h" -#include "ObjectAccessor.h" -#include "Log.h" -#include "Opcodes.h" -#include "Player.h" -#include "Item.h" -#include "Spell.h" -#include "SocialMgr.h" -#include "Language.h" -#include "AccountMgr.h" - -void WorldSession::SendTradeStatus(TradeStatus status) -{ - WorldPacket data; - - switch (status) - { - case TRADE_STATUS_BEGIN_TRADE: - data.Initialize(SMSG_TRADE_STATUS, 4+8); - data << uint32(status); - data << uint64(0); - break; - case TRADE_STATUS_OPEN_WINDOW: - data.Initialize(SMSG_TRADE_STATUS, 4+4); - data << uint32(status); - data << uint32(0); // added in 2.4.0 - break; - case TRADE_STATUS_CLOSE_WINDOW: - data.Initialize(SMSG_TRADE_STATUS, 4+4+1+4); - data << uint32(status); - data << uint32(0); - data << uint8(0); - data << uint32(0); - break; - case TRADE_STATUS_ONLY_CONJURED: - case TRADE_STATUS_NOT_ELIGIBLE: - data.Initialize(SMSG_TRADE_STATUS, 4+1); - data << uint32(status); - data << uint8(0); - break; - default: - data.Initialize(SMSG_TRADE_STATUS, 4); - data << uint32(status); - break; - } - - SendPacket(&data); -} - -void WorldSession::HandleIgnoreTradeOpcode(WorldPacket& /*recvPacket*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Ignore Trade %u", _player->GetGUIDLow()); - // recvPacket.print_storage(); -} - -void WorldSession::HandleBusyTradeOpcode(WorldPacket& /*recvPacket*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Busy Trade %u", _player->GetGUIDLow()); - // recvPacket.print_storage(); -} - -void WorldSession::SendUpdateTrade(bool trader_data /*= true*/) -{ - TradeData* view_trade = trader_data ? _player->GetTradeData()->GetTraderData() : _player->GetTradeData(); - - WorldPacket data(SMSG_TRADE_STATUS_EXTENDED, 1+4+4+4+4+4+7*(1+4+4+4+4+8+4+4+4+4+8+4+4+4+4+4+4)); - data << uint8(trader_data); // 1 means traders data, 0 means own - data << uint32(0); // added in 2.4.0, this value must be equal to value from TRADE_STATUS_OPEN_WINDOW status packet (different value for different players to block multiple trades?) - data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = next field in most cases - data << uint32(TRADE_SLOT_COUNT); // trade slots count/number?, = prev field in most cases - data << uint32(view_trade->GetMoney()); // trader gold - data << uint32(view_trade->GetSpell()); // spell casted on lowest slot item - - for (uint8 i = 0; i < TRADE_SLOT_COUNT; ++i) - { - data << uint8(i); // trade slot number, if not specified, then end of packet - - if (Item* item = view_trade->GetItem(TradeSlots(i))) - { - data << uint32(item->GetTemplate()->ItemId); // entry - data << uint32(item->GetTemplate()->DisplayInfoID);// display id - data << uint32(item->GetCount()); // stack count - // wrapped: hide stats but show giftcreator name - data << uint32(item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED) ? 1 : 0); - data << uint64(item->GetUInt64Value(ITEM_FIELD_GIFTCREATOR)); - // perm. enchantment and gems - data << uint32(item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT)); - for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot) - data << uint32(item->GetEnchantmentId(EnchantmentSlot(enchant_slot))); - // creator - data << uint64(item->GetUInt64Value(ITEM_FIELD_CREATOR)); - data << uint32(item->GetSpellCharges()); // charges - data << uint32(item->GetItemSuffixFactor()); // SuffixFactor - data << uint32(item->GetItemRandomPropertyId());// random properties id - data << uint32(item->GetTemplate()->LockID); // lock id - // max durability - data << uint32(item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY)); - // durability - data << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY)); - } - else - { - for (uint8 j = 0; j < 18; ++j) - data << uint32(0); - } - } - SendPacket(&data); -} - -//============================================================== -// transfer the items to the players - -void WorldSession::moveItems(Item* myItems[], Item* hisItems[]) -{ - Player* trader = _player->GetTrader(); - if (!trader) - return; - - for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) - { - ItemPosCountVec traderDst; - ItemPosCountVec playerDst; - bool traderCanTrade = (myItems[i] == NULL || trader->CanStoreItem(NULL_BAG, NULL_SLOT, traderDst, myItems[i], false) == EQUIP_ERR_OK); - bool playerCanTrade = (hisItems[i] == NULL || _player->CanStoreItem(NULL_BAG, NULL_SLOT, playerDst, hisItems[i], false) == EQUIP_ERR_OK); - if (traderCanTrade && playerCanTrade) - { - // Ok, if trade item exists and can be stored - // If we trade in both directions we had to check, if the trade will work before we actually do it - // A roll back is not possible after we stored it - if (myItems[i]) - { - // logging - sLog->outDebug(LOG_FILTER_NETWORKIO, "partner storing: %u", myItems[i]->GetGUIDLow()); - if (!AccountMgr::IsPlayerAccount(_player->GetSession()->GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) - { - sLog->outCommand(_player->GetSession()->GetAccountId(), "GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)", - _player->GetName(), _player->GetSession()->GetAccountId(), - myItems[i]->GetTemplate()->Name1.c_str(), myItems[i]->GetEntry(), myItems[i]->GetCount(), - trader->GetName(), trader->GetSession()->GetAccountId()); - } - - // adjust time (depends on /played) - if (myItems[i]->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE)) - myItems[i]->SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, trader->GetTotalPlayedTime()-(_player->GetTotalPlayedTime()-myItems[i]->GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME))); - // store - trader->MoveItemToInventory(traderDst, myItems[i], true, true); - } - if (hisItems[i]) - { - // logging - sLog->outDebug(LOG_FILTER_NETWORKIO, "player storing: %u", hisItems[i]->GetGUIDLow()); - if (!AccountMgr::IsPlayerAccount(trader->GetSession()->GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) - { - sLog->outCommand(trader->GetSession()->GetAccountId(), "GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)", - trader->GetName(), trader->GetSession()->GetAccountId(), - hisItems[i]->GetTemplate()->Name1.c_str(), hisItems[i]->GetEntry(), hisItems[i]->GetCount(), - _player->GetName(), _player->GetSession()->GetAccountId()); - } - - // adjust time (depends on /played) - if (hisItems[i]->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE)) - hisItems[i]->SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, _player->GetTotalPlayedTime()-(trader->GetTotalPlayedTime()-hisItems[i]->GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME))); - // store - _player->MoveItemToInventory(playerDst, hisItems[i], true, true); - } - } - else - { - // in case of fatal error log error message - // return the already removed items to the original owner - if (myItems[i]) - { - if (!traderCanTrade) - sLog->outError("trader can't store item: %u", myItems[i]->GetGUIDLow()); - if (_player->CanStoreItem(NULL_BAG, NULL_SLOT, playerDst, myItems[i], false) == EQUIP_ERR_OK) - _player->MoveItemToInventory(playerDst, myItems[i], true, true); - else - sLog->outError("player can't take item back: %u", myItems[i]->GetGUIDLow()); - } - // return the already removed items to the original owner - if (hisItems[i]) - { - if (!playerCanTrade) - sLog->outError("player can't store item: %u", hisItems[i]->GetGUIDLow()); - if (trader->CanStoreItem(NULL_BAG, NULL_SLOT, traderDst, hisItems[i], false) == EQUIP_ERR_OK) - trader->MoveItemToInventory(traderDst, hisItems[i], true, true); - else - sLog->outError("trader can't take item back: %u", hisItems[i]->GetGUIDLow()); - } - } - } -} - -//============================================================== - -static void setAcceptTradeMode(TradeData* myTrade, TradeData* hisTrade, Item* *myItems, Item* *hisItems) -{ - myTrade->SetInAcceptProcess(true); - hisTrade->SetInAcceptProcess(true); - - // store items in local list and set 'in-trade' flag - for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) - { - if (Item* item = myTrade->GetItem(TradeSlots(i))) - { - sLog->outStaticDebug("player trade item %u bag: %u slot: %u", item->GetGUIDLow(), item->GetBagSlot(), item->GetSlot()); - //Can return NULL - myItems[i] = item; - myItems[i]->SetInTrade(); - } - - if (Item* item = hisTrade->GetItem(TradeSlots(i))) - { - sLog->outStaticDebug("partner trade item %u bag: %u slot: %u", item->GetGUIDLow(), item->GetBagSlot(), item->GetSlot()); - hisItems[i] = item; - hisItems[i]->SetInTrade(); - } - } -} - -static void clearAcceptTradeMode(TradeData* myTrade, TradeData* hisTrade) -{ - myTrade->SetInAcceptProcess(false); - hisTrade->SetInAcceptProcess(false); -} - -static void clearAcceptTradeMode(Item* *myItems, Item* *hisItems) -{ - // clear 'in-trade' flag - for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) - { - if (myItems[i]) - myItems[i]->SetInTrade(false); - if (hisItems[i]) - hisItems[i]->SetInTrade(false); - } -} - -void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) -{ - TradeData* my_trade = _player->m_trade; - if (!my_trade) - return; - - Player* trader = my_trade->GetTrader(); - - TradeData* his_trade = trader->m_trade; - if (!his_trade) - return; - - Item* myItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL }; - Item* hisItems[TRADE_SLOT_TRADED_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL }; - bool myCanCompleteTrade = true, hisCanCompleteTrade = true; - - // set before checks for propertly undo at problems (it already set in to client) - my_trade->SetAccepted(true); - - // not accept case incorrect money amount - if (!_player->HasEnoughMoney(my_trade->GetMoney())) - { - SendNotification(LANG_NOT_ENOUGH_GOLD); - my_trade->SetAccepted(false, true); - return; - } - - // not accept case incorrect money amount - if (!trader->HasEnoughMoney(his_trade->GetMoney())) - { - trader->GetSession()->SendNotification(LANG_NOT_ENOUGH_GOLD); - his_trade->SetAccepted(false, true); - return; - } - - // not accept if some items now can't be trade (cheating) - for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) - { - if (Item* item = my_trade->GetItem(TradeSlots(i))) - { - if (!item->CanBeTraded(false, true)) - { - SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); - return; - } - if (item->IsBindedNotWith(trader)) - { - SendTradeStatus(TRADE_STATUS_NOT_ELIGIBLE); - SendTradeStatus(TRADE_STATUS_CLOSE_WINDOW/*TRADE_STATUS_TRADE_CANCELED*/); - return; - } - } - - if (Item* item = his_trade->GetItem(TradeSlots(i))) - { - if (!item->CanBeTraded(false, true)) - { - SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); - return; - } - //if (item->IsBindedNotWith(_player)) // dont mark as invalid when his item isnt good (not exploitable because if item is invalid trade will fail anyway later on the same check) - //{ - // SendTradeStatus(TRADE_STATUS_NOT_ELIGIBLE); - // his_trade->SetAccepted(false, true); - // return; - //} - } - } - - if (his_trade->IsAccepted()) - { - setAcceptTradeMode(my_trade, his_trade, myItems, hisItems); - - Spell* my_spell = NULL; - SpellCastTargets my_targets; - - Spell* his_spell = NULL; - SpellCastTargets his_targets; - - // not accept if spell can't be casted now (cheating) - if (uint32 my_spell_id = my_trade->GetSpell()) - { - SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(my_spell_id); - Item* castItem = my_trade->GetSpellCastItem(); - - if (!spellEntry || !his_trade->GetItem(TRADE_SLOT_NONTRADED) || - (my_trade->HasSpellCastItem() && !castItem)) - { - clearAcceptTradeMode(my_trade, his_trade); - clearAcceptTradeMode(myItems, hisItems); - - my_trade->SetSpell(0); - return; - } - - my_spell = new Spell(_player, spellEntry, TRIGGERED_FULL_MASK); - my_spell->m_CastItem = castItem; - my_targets.SetTradeItemTarget(_player); - my_spell->m_targets = my_targets; - - SpellCastResult res = my_spell->CheckCast(true); - if (res != SPELL_CAST_OK) - { - my_spell->SendCastResult(res); - - clearAcceptTradeMode(my_trade, his_trade); - clearAcceptTradeMode(myItems, hisItems); - - delete my_spell; - my_trade->SetSpell(0); - return; - } - } - - // not accept if spell can't be casted now (cheating) - if (uint32 his_spell_id = his_trade->GetSpell()) - { - SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(his_spell_id); - Item* castItem = his_trade->GetSpellCastItem(); - - if (!spellEntry || !my_trade->GetItem(TRADE_SLOT_NONTRADED) || (his_trade->HasSpellCastItem() && !castItem)) - { - delete my_spell; - his_trade->SetSpell(0); - - clearAcceptTradeMode(my_trade, his_trade); - clearAcceptTradeMode(myItems, hisItems); - return; - } - - his_spell = new Spell(trader, spellEntry, TRIGGERED_FULL_MASK); - his_spell->m_CastItem = castItem; - his_targets.SetTradeItemTarget(trader); - his_spell->m_targets = his_targets; - - SpellCastResult res = his_spell->CheckCast(true); - if (res != SPELL_CAST_OK) - { - his_spell->SendCastResult(res); - - clearAcceptTradeMode(my_trade, his_trade); - clearAcceptTradeMode(myItems, hisItems); - - delete my_spell; - delete his_spell; - - his_trade->SetSpell(0); - return; - } - } - - // inform partner client - trader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); - - // test if item will fit in each inventory - hisCanCompleteTrade = (trader->CanStoreItems(myItems, TRADE_SLOT_TRADED_COUNT) == EQUIP_ERR_OK); - myCanCompleteTrade = (_player->CanStoreItems(hisItems, TRADE_SLOT_TRADED_COUNT) == EQUIP_ERR_OK); - - clearAcceptTradeMode(myItems, hisItems); - - // in case of missing space report error - if (!myCanCompleteTrade) - { - clearAcceptTradeMode(my_trade, his_trade); - - SendNotification(LANG_NOT_FREE_TRADE_SLOTS); - trader->GetSession()->SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS); - my_trade->SetAccepted(false); - his_trade->SetAccepted(false); - return; - } - else if (!hisCanCompleteTrade) - { - clearAcceptTradeMode(my_trade, his_trade); - - SendNotification(LANG_NOT_PARTNER_FREE_TRADE_SLOTS); - trader->GetSession()->SendNotification(LANG_NOT_FREE_TRADE_SLOTS); - my_trade->SetAccepted(false); - his_trade->SetAccepted(false); - return; - } - - // execute trade: 1. remove - for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) - { - if (myItems[i]) - { - myItems[i]->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, _player->GetGUID()); - _player->MoveItemFromInventory(myItems[i]->GetBagSlot(), myItems[i]->GetSlot(), true); - } - if (hisItems[i]) - { - hisItems[i]->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, trader->GetGUID()); - trader->MoveItemFromInventory(hisItems[i]->GetBagSlot(), hisItems[i]->GetSlot(), true); - } - } - - // execute trade: 2. store - moveItems(myItems, hisItems); - - // logging money - if (sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) - { - if (!AccountMgr::IsPlayerAccount(_player->GetSession()->GetSecurity()) && my_trade->GetMoney() > 0) - { - sLog->outCommand(_player->GetSession()->GetAccountId(), "GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", - _player->GetName(), _player->GetSession()->GetAccountId(), - my_trade->GetMoney(), - trader->GetName(), trader->GetSession()->GetAccountId()); - } - if (!AccountMgr::IsPlayerAccount(trader->GetSession()->GetSecurity()) && his_trade->GetMoney() > 0) - { - sLog->outCommand(trader->GetSession()->GetAccountId(), "GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", - trader->GetName(), trader->GetSession()->GetAccountId(), - his_trade->GetMoney(), - _player->GetName(), _player->GetSession()->GetAccountId()); - } - } - - // update money - _player->ModifyMoney(-int32(my_trade->GetMoney())); - _player->ModifyMoney(his_trade->GetMoney()); - trader->ModifyMoney(-int32(his_trade->GetMoney())); - trader->ModifyMoney(my_trade->GetMoney()); - - if (my_spell) - my_spell->prepare(&my_targets); - - if (his_spell) - his_spell->prepare(&his_targets); - - // cleanup - clearAcceptTradeMode(my_trade, his_trade); - delete _player->m_trade; - _player->m_trade = NULL; - delete trader->m_trade; - trader->m_trade = NULL; - - // desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards) - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - _player->SaveInventoryAndGoldToDB(trans); - trader->SaveInventoryAndGoldToDB(trans); - CharacterDatabase.CommitTransaction(trans); - - trader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE); - SendTradeStatus(TRADE_STATUS_TRADE_COMPLETE); - } - else - { - trader->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_ACCEPT); - } -} - -void WorldSession::HandleUnacceptTradeOpcode(WorldPacket& /*recvPacket*/) -{ - TradeData* my_trade = _player->GetTradeData(); - if (!my_trade) - return; - - my_trade->SetAccepted(false, true); -} - -void WorldSession::HandleBeginTradeOpcode(WorldPacket& /*recvPacket*/) -{ - TradeData* my_trade = _player->m_trade; - if (!my_trade) - return; - - my_trade->GetTrader()->GetSession()->SendTradeStatus(TRADE_STATUS_OPEN_WINDOW); - SendTradeStatus(TRADE_STATUS_OPEN_WINDOW); -} - -void WorldSession::SendCancelTrade() -{ - if (m_playerRecentlyLogout) - return; - - SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); -} - -void WorldSession::HandleCancelTradeOpcode(WorldPacket& /*recvPacket*/) -{ - // sended also after LOGOUT COMPLETE - if (_player) // needed because STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT - _player->TradeCancel(true); -} - -void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket) -{ - if (GetPlayer()->m_trade) - { - recvPacket.rfinish(); - return; - } - - uint64 ID; - recvPacket >> ID; - - if (!GetPlayer()->isAlive()) - { - SendTradeStatus(TRADE_STATUS_YOU_DEAD); - return; - } - - if (GetPlayer()->HasUnitState(UNIT_STAT_STUNNED)) - { - SendTradeStatus(TRADE_STATUS_YOU_STUNNED); - return; - } - - if (isLogingOut()) - { - SendTradeStatus(TRADE_STATUS_YOU_LOGOUT); - return; - } - - if (GetPlayer()->isInFlight()) - { - SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); - return; - } - - if (GetPlayer()->getLevel() < sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)) - { - SendNotification(GetTrinityString(LANG_TRADE_REQ), sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)); - return; - } - - Player* pOther = ObjectAccessor::FindPlayer(ID); - - if (!pOther) - { - SendTradeStatus(TRADE_STATUS_NO_TARGET); - return; - } - - if (pOther == GetPlayer() || pOther->m_trade) - { - SendTradeStatus(TRADE_STATUS_BUSY); - return; - } - - if (!pOther->isAlive()) - { - SendTradeStatus(TRADE_STATUS_TARGET_DEAD); - return; - } - - if (pOther->isInFlight()) - { - SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); - return; - } - - if (pOther->HasUnitState(UNIT_STAT_STUNNED)) - { - SendTradeStatus(TRADE_STATUS_TARGET_STUNNED); - return; - } - - if (pOther->GetSession()->isLogingOut()) - { - SendTradeStatus(TRADE_STATUS_TARGET_LOGOUT); - return; - } - - if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) - { - SendTradeStatus(TRADE_STATUS_IGNORE_YOU); - return; - } - - if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) && pOther->GetTeam() !=_player->GetTeam()) - { - SendTradeStatus(TRADE_STATUS_WRONG_FACTION); - return; - } - - if (!pOther->IsWithinDistInMap(_player, 10.0f, false)) - { - SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); - return; - } - - if (pOther->getLevel() < sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)) - { - SendNotification(GetTrinityString(LANG_TRADE_OTHER_REQ), sWorld->getIntConfig(CONFIG_TRADE_LEVEL_REQ)); - return; - } - - // OK start trade - _player->m_trade = new TradeData(_player, pOther); - pOther->m_trade = new TradeData(pOther, _player); - - WorldPacket data(SMSG_TRADE_STATUS, 12); - data << uint32(TRADE_STATUS_BEGIN_TRADE); - data << uint64(_player->GetGUID()); - pOther->GetSession()->SendPacket(&data); -} - -void WorldSession::HandleSetTradeGoldOpcode(WorldPacket& recvPacket) -{ - uint32 gold; - recvPacket >> gold; - - TradeData* my_trade = _player->GetTradeData(); - if (!my_trade) - return; - - // gold can be incorrect, but this is checked at trade finished. - my_trade->SetMoney(gold); -} - -void WorldSession::HandleSetTradeItemOpcode(WorldPacket& recvPacket) -{ - // send update - uint8 tradeSlot; - uint8 bag; - uint8 slot; - - recvPacket >> tradeSlot; - recvPacket >> bag; - recvPacket >> slot; - - TradeData* my_trade = _player->GetTradeData(); - if (!my_trade) - return; - - // invalid slot number - if (tradeSlot >= TRADE_SLOT_COUNT) - { - SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); - return; - } - - // check cheating, can't fail with correct client operations - Item* item = _player->GetItemByPos(bag, slot); - if (!item || (tradeSlot != TRADE_SLOT_NONTRADED && !item->CanBeTraded(false, true))) - { - SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); - return; - } - - uint64 iGUID = item->GetGUID(); - - // prevent place single item into many trade slots using cheating and client bugs - if (my_trade->HasItem(iGUID)) - { - // cheating attempt - SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); - return; - } - - my_trade->SetItem(TradeSlots(tradeSlot), item); -} - -void WorldSession::HandleClearTradeItemOpcode(WorldPacket& recvPacket) -{ - uint8 tradeSlot; - recvPacket >> tradeSlot; - - TradeData* my_trade = _player->m_trade; - if (!my_trade) - return; - - // invalid slot number - if (tradeSlot >= TRADE_SLOT_COUNT) - return; - - my_trade->SetItem(TradeSlots(tradeSlot), NULL); -} - diff --git a/src/server/game/Server/Protocol/Handlers/VehicleHandler.cpp b/src/server/game/Server/Protocol/Handlers/VehicleHandler.cpp deleted file mode 100644 index ce4f6ccb8fe..00000000000 --- a/src/server/game/Server/Protocol/Handlers/VehicleHandler.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Opcodes.h" -#include "Vehicle.h" -#include "Player.h" -#include "Log.h" -#include "ObjectAccessor.h" - -void WorldSession::HandleDismissControlledVehicle(WorldPacket &recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_DISMISS_CONTROLLED_VEHICLE"); - - uint64 vehicleGUID = _player->GetCharmGUID(); - - if (!vehicleGUID) // something wrong here... - { - recv_data.rfinish(); // prevent warnings spam - return; - } - - uint64 guid; - - recv_data.readPackGUID(guid); - - MovementInfo mi; - mi.guid = guid; - ReadMovementInfo(recv_data, &mi); - - _player->m_movementInfo = mi; - - _player->ExitVehicle(); -} - -void WorldSession::HandleChangeSeatsOnControlledVehicle(WorldPacket &recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE"); - - Unit* vehicle_base = GetPlayer()->GetVehicleBase(); - if (!vehicle_base) - { - recv_data.rfinish(); // prevent warnings spam - return; - } - - VehicleSeatEntry const* seat = GetPlayer()->GetVehicle()->GetSeatForPassenger(GetPlayer()); - if (!seat->CanSwitchFromSeat()) - { - recv_data.rfinish(); // prevent warnings spam - sLog->outError("HandleChangeSeatsOnControlledVehicle, Opcode: %u, Player %u tried to switch seats but current seatflags %u don't permit that.", - recv_data.GetOpcode(), GetPlayer()->GetGUIDLow(), seat->m_flags); - return; - } - - switch (recv_data.GetOpcode()) - { - case CMSG_REQUEST_VEHICLE_PREV_SEAT: - GetPlayer()->ChangeSeat(-1, false); - break; - case CMSG_REQUEST_VEHICLE_NEXT_SEAT: - GetPlayer()->ChangeSeat(-1, true); - break; - case CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE: - { - uint64 guid; // current vehicle guid - recv_data.readPackGUID(guid); - - ReadMovementInfo(recv_data, &vehicle_base->m_movementInfo); - - uint64 accessory; // accessory guid - recv_data.readPackGUID(accessory); - - int8 seatId; - recv_data >> seatId; - - if (vehicle_base->GetGUID() != guid) - return; - - if (!accessory) - GetPlayer()->ChangeSeat(-1, seatId > 0); // prev/next - else if (Unit* vehUnit = Unit::GetUnit(*GetPlayer(), accessory)) - { - if (Vehicle* vehicle = vehUnit->GetVehicleKit()) - if (vehicle->HasEmptySeat(seatId)) - vehUnit->HandleSpellClick(GetPlayer(), seatId); - } - break; - } - case CMSG_REQUEST_VEHICLE_SWITCH_SEAT: - { - uint64 guid; // current vehicle guid - recv_data.readPackGUID(guid); - - int8 seatId; - recv_data >> seatId; - - if (vehicle_base->GetGUID() == guid) - GetPlayer()->ChangeSeat(seatId); - else if (Unit* vehUnit = Unit::GetUnit(*GetPlayer(), guid)) - if (Vehicle* vehicle = vehUnit->GetVehicleKit()) - if (vehicle->HasEmptySeat(seatId)) - vehUnit->HandleSpellClick(GetPlayer(), seatId); - break; - } - default: - break; - } -} - -void WorldSession::HandleEnterPlayerVehicle(WorldPacket &data) -{ - // Read guid - uint64 guid; - data >> guid; - - if (Player* player = ObjectAccessor::FindPlayer(guid)) - { - if (!player->GetVehicleKit()) - return; - if (!player->IsInRaidWith(_player)) - return; - if (!player->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) - return; - - _player->EnterVehicle(player); - } -} - -void WorldSession::HandleEjectPassenger(WorldPacket &data) -{ - Vehicle* vehicle = _player->GetVehicleKit(); - if (!vehicle) - { - data.rfinish(); // prevent warnings spam - sLog->outError("HandleEjectPassenger: Player %u is not in a vehicle!", GetPlayer()->GetGUIDLow()); - return; - } - - uint64 guid; - data >> guid; - - if (IS_PLAYER_GUID(guid)) - { - Player* player = ObjectAccessor::FindPlayer(guid); - if (!player) - { - sLog->outError("Player %u tried to eject player %u from vehicle, but the latter was not found in world!", GetPlayer()->GetGUIDLow(), GUID_LOPART(guid)); - return; - } - - if (!player->IsOnVehicle(vehicle->GetBase())) - { - sLog->outError("Player %u tried to eject player %u, but they are not in the same vehicle", GetPlayer()->GetGUIDLow(), GUID_LOPART(guid)); - return; - } - - VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(player); - ASSERT(seat); - if (seat->IsEjectable()) - player->ExitVehicle(); - else - sLog->outError("Player %u attempted to eject player %u from non-ejectable seat.", GetPlayer()->GetGUIDLow(), GUID_LOPART(guid)); - } - - else if (IS_CREATURE_GUID(guid)) - { - Unit* unit = ObjectAccessor::GetUnit(*_player, guid); - if (!unit) // creatures can be ejected too from player mounts - { - sLog->outError("Player %u tried to eject creature guid %u from vehicle, but the latter was not found in world!", GetPlayer()->GetGUIDLow(), GUID_LOPART(guid)); - return; - } - - if (!unit->IsOnVehicle(vehicle->GetBase())) - { - sLog->outError("Player %u tried to eject unit %u, but they are not in the same vehicle", GetPlayer()->GetGUIDLow(), GUID_LOPART(guid)); - return; - } - - VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(unit); - ASSERT(seat); - if (seat->IsEjectable()) - { - ASSERT(GetPlayer() == vehicle->GetBase()); - unit->ExitVehicle(); - } - else - sLog->outError("Player %u attempted to eject creature GUID %u from non-ejectable seat.", GetPlayer()->GetGUIDLow(), GUID_LOPART(guid)); - } - else - sLog->outError("HandleEjectPassenger: Player %u tried to eject invalid GUID "UI64FMTD, GetPlayer()->GetGUIDLow(), guid); -} - -void WorldSession::HandleRequestVehicleExit(WorldPacket& /*recv_data*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_REQUEST_VEHICLE_EXIT"); - - if (Vehicle* vehicle = GetPlayer()->GetVehicle()) - { - if (VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(GetPlayer())) - { - if (seat->CanEnterOrExit()) - GetPlayer()->ExitVehicle(); - else - sLog->outError("Player %u tried to exit vehicle, but seatflags %u (ID: %u) don't permit that.", - GetPlayer()->GetGUIDLow(), seat->m_ID, seat->m_flags); - } - } -} diff --git a/src/server/game/Server/Protocol/Handlers/VoiceChatHandler.cpp b/src/server/game/Server/Protocol/Handlers/VoiceChatHandler.cpp deleted file mode 100755 index 34ad5ac3eae..00000000000 --- a/src/server/game/Server/Protocol/Handlers/VoiceChatHandler.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2008-2012 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "Common.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Opcodes.h" -#include "Log.h" - -void WorldSession::HandleVoiceSessionEnableOpcode(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_VOICE_SESSION_ENABLE"); - // uint8 isVoiceEnabled, uint8 isMicrophoneEnabled - recv_data.read_skip(); - recv_data.read_skip(); -} - -void WorldSession::HandleChannelVoiceOnOpcode(WorldPacket& /*recv_data*/) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CHANNEL_VOICE_ON"); - // Enable Voice button in channel context menu -} - -void WorldSession::HandleSetActiveVoiceChannel(WorldPacket& recv_data) -{ - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_SET_ACTIVE_VOICE_CHANNEL"); - recv_data.read_skip(); - recv_data.read_skip(); -} - diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt index d34b1b8c3c3..d43cce45c00 100644 --- a/src/server/scripts/CMakeLists.txt +++ b/src/server/scripts/CMakeLists.txt @@ -112,6 +112,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/game/Grids/Notifiers ${CMAKE_SOURCE_DIR}/src/server/game/Groups ${CMAKE_SOURCE_DIR}/src/server/game/Guilds + ${CMAKE_SOURCE_DIR}/src/server/game/Handlers ${CMAKE_SOURCE_DIR}/src/server/game/Instances ${CMAKE_SOURCE_DIR}/src/server/game/LookingForGroup ${CMAKE_SOURCE_DIR}/src/server/game/Loot @@ -130,7 +131,6 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/game/Scripting ${CMAKE_SOURCE_DIR}/src/server/game/Server ${CMAKE_SOURCE_DIR}/src/server/game/Server/Protocol - ${CMAKE_SOURCE_DIR}/src/server/game/Server/Protocol/Handlers ${CMAKE_SOURCE_DIR}/src/server/game/Skills ${CMAKE_SOURCE_DIR}/src/server/game/Spells ${CMAKE_SOURCE_DIR}/src/server/game/Spells/Auras diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt index 60adce41326..e2b70c9c673 100644 --- a/src/server/worldserver/CMakeLists.txt +++ b/src/server/worldserver/CMakeLists.txt @@ -108,6 +108,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/game/Grids ${CMAKE_SOURCE_DIR}/src/server/game/Groups ${CMAKE_SOURCE_DIR}/src/server/game/Guilds + ${CMAKE_SOURCE_DIR}/src/server/game/Handlers ${CMAKE_SOURCE_DIR}/src/server/game/Instances ${CMAKE_SOURCE_DIR}/src/server/game/Loot ${CMAKE_SOURCE_DIR}/src/server/game/Mails @@ -123,7 +124,6 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/game/Reputation ${CMAKE_SOURCE_DIR}/src/server/game/Scripting ${CMAKE_SOURCE_DIR}/src/server/game/Server/Protocol - ${CMAKE_SOURCE_DIR}/src/server/game/Server/Protocol/Handlers ${CMAKE_SOURCE_DIR}/src/server/game/Server ${CMAKE_SOURCE_DIR}/src/server/game/Skills ${CMAKE_SOURCE_DIR}/src/server/game/Spells -- cgit v1.2.3 From 6c1815db7f795e697f2df18a554f5b1a33e6c73a Mon Sep 17 00:00:00 2001 From: kaelima Date: Thu, 26 Jan 2012 14:48:05 +0100 Subject: Core/Battleground: Remove useless and unused function --- src/server/game/Battlegrounds/Battleground.cpp | 13 ------------- src/server/game/Battlegrounds/Battleground.h | 1 - 2 files changed, 14 deletions(-) (limited to 'src') diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 6a758695116..e33676d1d65 100755 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -895,19 +895,6 @@ uint32 Battleground::GetBonusHonorFromKill(uint32 kills) const return Trinity::Honor::hk_honor_at_level(maxLevel, float(kills)); } -uint32 Battleground::GetBattlemasterEntry() const -{ - switch (GetTypeID(true)) - { - case BATTLEGROUND_AV: return 15972; - case BATTLEGROUND_WS: return 14623; - case BATTLEGROUND_AB: return 14879; - case BATTLEGROUND_EY: return 22516; - case BATTLEGROUND_NA: return 20200; - default: return 0; - } -} - void Battleground::BlockMovement(Player* player) { player->SetClientControl(player, 0); // movement disabled NOTE: the effect will be automatically removed by client when the player is teleported from the battleground, so no need to send with uint8(1) in RemovePlayerAtLeave() diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index fcfc0c48cb4..fbbd94cad22 100755 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -360,7 +360,6 @@ class Battleground uint8 GetArenaType() const { return m_ArenaType; } uint8 GetWinner() const { return m_Winner; } uint32 GetScriptId() const { return ScriptId; } - uint32 GetBattlemasterEntry() const; uint32 GetBonusHonorFromKill(uint32 kills) const; bool IsRandom() const { return m_IsRandom; } -- cgit v1.2.3 From 83c85a2f07cfdc10ee90f5cb2744057efc4a3262 Mon Sep 17 00:00:00 2001 From: Shocker Date: Fri, 27 Jan 2012 02:24:48 +0200 Subject: Scripts/Utgarde Keep: Fix possible crsah in Ingvar code --- .../Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp index 1ab95c53500..d2133a78bc9 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp @@ -391,7 +391,8 @@ public: ingvar->RemoveAurasDueToSpell(SPELL_SCOURG_RESURRECTION_DUMMY); if (boss_ingvar_the_plunderer::boss_ingvar_the_plundererAI* pAI = CAST_AI(boss_ingvar_the_plunderer::boss_ingvar_the_plundererAI, ingvar->AI())) - pAI->StartZombiePhase(); + if (ingvar->getVictim()) + pAI->StartZombiePhase(); me->GetMotionMaster()->MovePoint(2, x+1, y, z+30); ++uiResurectPhase; -- cgit v1.2.3 From e43b1cd7500a11dac3a6e3375306bf041344df6f Mon Sep 17 00:00:00 2001 From: Subv2112 Date: Fri, 27 Jan 2012 08:34:36 -0500 Subject: Core/SAI: Run mode should not be set to true each time a creature resets, it should use its previous value Signed-off-by: Subv2112 --- src/server/game/AI/SmartScripts/SmartAI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 79fe3df7ff7..d4b2a9746be 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -89,7 +89,7 @@ void SmartAI::UpdateDespawn(const uint32 diff) void SmartAI::Reset() { if (!HasEscortState(SMART_ESCORT_ESCORTING))//dont mess up escort movement after combat - SetRun(true); + SetRun(mRun); GetScript()->OnReset(); } -- cgit v1.2.3 From ac40323ea0036dbb2643d4a9f21e5b4c2e8bfbee Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Date: Fri, 27 Jan 2012 13:07:40 -0300 Subject: Scripts/UK: Fixed crash. A better way must be implemented if there is any. --- src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp index ea54fc16095..94a133c78a6 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp @@ -302,7 +302,7 @@ class spell_frost_tomb : public SpellScriptLoader if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEATH) if (Unit* caster = GetCaster()) if (caster->ToCreature() && caster->isAlive()) - caster->ToCreature()->DespawnOrUnsummon(); + caster->ToCreature()->DespawnOrUnsummon(1000); } void Register() -- cgit v1.2.3 From 2db5c13d8f173a0f577f1d657291994bb814d37c Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Date: Fri, 27 Jan 2012 13:44:44 -0300 Subject: Core/Spline: Removed redundant call. --- src/server/game/Movement/Spline/MoveSplineInit.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/server/game/Movement/Spline/MoveSplineInit.cpp b/src/server/game/Movement/Spline/MoveSplineInit.cpp index 885ade57653..b5ae923dc32 100644 --- a/src/server/game/Movement/Spline/MoveSplineInit.cpp +++ b/src/server/game/Movement/Spline/MoveSplineInit.cpp @@ -106,7 +106,6 @@ namespace Movement void MoveSplineInit::SetFacing(const Unit * target) { args.flags.EnableFacingTarget(); - target->GetUInt64Value(OBJECT_FIELD_GUID); //args.facing.target = target->GetObjectGuid().GetRawValue(); args.facing.target = target->GetUInt64Value(OBJECT_FIELD_GUID); } -- cgit v1.2.3 From ff81a2455b9dc9afb4e3875a02899fc52b0a510f Mon Sep 17 00:00:00 2001 From: Subv2112 Date: Sat, 28 Jan 2012 12:25:44 -0500 Subject: Core/Conditions: Make CONDITION_CLASS and CONDITION_RACE use a mask, this will reduce the amount of conditions needed Signed-off-by: Subv --- src/server/game/Conditions/ConditionMgr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 49b5d4cba65..9b045a8ed6a 100755 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -73,10 +73,10 @@ bool Condition::Meets(Player* player, Unit* invoker) condMeets = player->GetTeam() == mConditionValue1; break; case CONDITION_CLASS: - condMeets = player->getClass() == mConditionValue1; + condMeets = player->getClassMask() & mConditionValue1; break; case CONDITION_RACE: - condMeets = player->getRace() == mConditionValue1; + condMeets = player->getRaceMask() & mConditionValue1; break; case CONDITION_SKILL: condMeets = player->HasSkill(mConditionValue1) && player->GetBaseSkillValue(mConditionValue1) >= mConditionValue2; -- cgit v1.2.3 From 59f378ea8980efa25fe1ec620cd872e64f5cf303 Mon Sep 17 00:00:00 2001 From: Subv2112 Date: Sat, 28 Jan 2012 12:45:27 -0500 Subject: Core/Conditions: Fixed the error introduced in the previous commit --- src/server/game/Conditions/ConditionMgr.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 9b045a8ed6a..dd46898a0c6 100755 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -1180,9 +1180,9 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) } case CONDITION_CLASS: { - if (cond->mConditionValue1 >= MAX_CLASSES) + if (!(cond->mConditionValue1 & CLASSMASK_ALL_PLAYABLE)) { - sLog->outErrorDb("Class condition has non existing class (%u), skipped", cond->mConditionValue1); + sLog->outErrorDb("Class condition has non existing classmask (%u), skipped", cond->mConditionValue1 & ~CLASSMASK_ALL_PLAYABLE); return false; } @@ -1192,9 +1192,9 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) } case CONDITION_RACE: { - if (cond->mConditionValue1 >= MAX_RACES) + if (!(cond->mConditionValue1 & RACEMASK_ALL_PLAYABLE)) { - sLog->outErrorDb("Race condition has non existing race (%u), skipped", cond->mConditionValue1); + sLog->outErrorDb("Race condition has non existing racemask (%u), skipped", cond->mConditionValue1 & ~RACEMASK_ALL_PLAYABLE); return false; } -- cgit v1.2.3 From 03953930f91915cfa128f44dbb298c482e7589bd Mon Sep 17 00:00:00 2001 From: Subv2112 Date: Sat, 28 Jan 2012 16:03:36 -0500 Subject: Scripts/Commands: Adjust .pinfo and .gm list to respect the realmid in account_access table. closes #1306 Signed-off-by: Subv2112 --- src/server/game/Chat/Commands/Level2.cpp | 4 ++-- src/server/scripts/Commands/cs_gm.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/server/game/Chat/Commands/Level2.cpp b/src/server/game/Chat/Commands/Level2.cpp index 31942d9e2fa..68961b9de61 100755 --- a/src/server/game/Chat/Commands/Level2.cpp +++ b/src/server/game/Chat/Commands/Level2.cpp @@ -332,8 +332,8 @@ bool ChatHandler::HandlePInfoCommand(const char* args) QueryResult result = LoginDatabase.PQuery("SELECT a.username, aa.gmlevel, a.email, a.last_ip, a.last_login, a.mutetime " "FROM account a " "LEFT JOIN account_access aa " - "ON (a.id = aa.id) " - "WHERE a.id = '%u'", accId); + "ON (a.id = aa.id AND (aa.RealmID = -1 OR aa.RealmID = %u)) " + "WHERE a.id = '%u'", realmID, accId); if (result) { Field* fields = result->Fetch(); diff --git a/src/server/scripts/Commands/cs_gm.cpp b/src/server/scripts/Commands/cs_gm.cpp index b69f800327e..9b9d1cfd146 100644 --- a/src/server/scripts/Commands/cs_gm.cpp +++ b/src/server/scripts/Commands/cs_gm.cpp @@ -26,6 +26,7 @@ EndScriptData */ #include "ObjectMgr.h" #include "Chat.h" #include "AccountMgr.h" +#include "World.h" class gm_commandscript : public CommandScript { @@ -155,7 +156,7 @@ public: static bool HandleGMListFullCommand(ChatHandler* handler, char const* /*args*/) { ///- Get the accounts with GM Level >0 - QueryResult result = LoginDatabase.PQuery("SELECT a.username, aa.gmlevel FROM account a, account_access aa WHERE a.id=aa.id AND aa.gmlevel >= %u", SEC_MODERATOR); + QueryResult result = LoginDatabase.PQuery("SELECT a.username, aa.gmlevel FROM account a, account_access aa WHERE a.id=aa.id AND aa.gmlevel >= %u AND (aa.realmid = -1 OR aa.realmid = %u)", SEC_MODERATOR, realmID); if (result) { handler->SendSysMessage(LANG_GMLIST); -- cgit v1.2.3 From fa384665af344d79824bc454d6bdd75d25977ba0 Mon Sep 17 00:00:00 2001 From: LiMCrosS Date: Sat, 28 Jan 2012 19:27:52 -0200 Subject: ICC/Sindragosa: POINT_FROSTWYRM_LAND now is EFFECT_MOTION_TYPE --- src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp index 11100e6297e..3d3eaa1cc87 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -646,7 +646,7 @@ class npc_spinestalker : public CreatureScript void MovementInform(uint32 type, uint32 point) { - if (type != POINT_MOTION_TYPE || point != POINT_FROSTWYRM_LAND) + if (type != EFFECT_MOTION_TYPE || point != POINT_FROSTWYRM_LAND) return; me->setActive(false); @@ -761,7 +761,7 @@ class npc_rimefang : public CreatureScript void MovementInform(uint32 type, uint32 point) { - if (type != POINT_MOTION_TYPE || point != POINT_FROSTWYRM_LAND) + if (type != EFFECT_MOTION_TYPE || point != POINT_FROSTWYRM_LAND) return; me->setActive(false); -- cgit v1.2.3 From 5ceae46302b1b601927b50f3ea973941cd8938d0 Mon Sep 17 00:00:00 2001 From: Nay Date: Sun, 29 Jan 2012 01:48:36 +0000 Subject: Core/Scripts: Rename pAI to ai --- .../CullingOfStratholme/culling_of_stratholme.cpp | 40 +++++++++++----------- .../UtgardeKeep/boss_ingvar_the_plunderer.cpp | 6 ++-- 2 files changed, 23 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp index ad0a36da84e..6cdb794bf5e 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp @@ -234,53 +234,53 @@ public: bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) { player->PlayerTalkClass->ClearMenus(); - npc_arthasAI* pAI = CAST_AI(npc_arthas::npc_arthasAI, creature->AI()); + npc_arthasAI* ai = CAST_AI(npc_arthas::npc_arthasAI, creature->AI()); - if (!pAI) + if (!ai) return false; switch (action) { case GOSSIP_ACTION_INFO_DEF: - pAI->Start(true, true, player->GetGUID(), 0, false, false); - pAI->SetDespawnAtEnd(false); - pAI->bStepping = false; - pAI->uiStep = 1; + ai->Start(true, true, player->GetGUID(), 0, false, false); + ai->SetDespawnAtEnd(false); + ai->bStepping = false; + ai->uiStep = 1; break; case GOSSIP_ACTION_INFO_DEF+1: - pAI->bStepping = true; - pAI->uiStep = 24; + ai->bStepping = true; + ai->uiStep = 24; break; case GOSSIP_ACTION_INFO_DEF+2: - pAI->SetHoldState(false); - pAI->bStepping = false; - pAI->uiStep = 61; + ai->SetHoldState(false); + ai->bStepping = false; + ai->uiStep = 61; break; case GOSSIP_ACTION_INFO_DEF+3: - pAI->SetHoldState(false); + ai->SetHoldState(false); break; case GOSSIP_ACTION_INFO_DEF+4: - pAI->bStepping = true; - pAI->uiStep = 84; + ai->bStepping = true; + ai->uiStep = 84; break; case GOSSIP_ACTION_INFO_DEF+5: - pAI->bStepping = true; - pAI->uiStep = 85; + ai->bStepping = true; + ai->uiStep = 85; break; } player->CLOSE_GOSSIP_MENU(); - pAI->SetDespawnAtFar(true); + ai->SetDespawnAtFar(true); creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); return true; } bool OnGossipHello(Player* player, Creature* creature) { - npc_arthasAI* pAI = CAST_AI(npc_arthas::npc_arthasAI, creature->AI()); + npc_arthasAI* ai = CAST_AI(npc_arthas::npc_arthasAI, creature->AI()); - if (pAI && pAI->bStepping == false) + if (ai && ai->bStepping == false) { - switch (pAI->uiGossipStep) + switch (ai->uiGossipStep) { case 0: //This one is a workaround since the very beggining of the script is wrong. { diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp index d2133a78bc9..0c59097a9ec 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp @@ -390,9 +390,9 @@ public: { ingvar->RemoveAurasDueToSpell(SPELL_SCOURG_RESURRECTION_DUMMY); - if (boss_ingvar_the_plunderer::boss_ingvar_the_plundererAI* pAI = CAST_AI(boss_ingvar_the_plunderer::boss_ingvar_the_plundererAI, ingvar->AI())) - if (ingvar->getVictim()) - pAI->StartZombiePhase(); + if (ingvar->getVictim()) + if (boss_ingvar_the_plunderer::boss_ingvar_the_plundererAI* ai = CAST_AI(boss_ingvar_the_plunderer::boss_ingvar_the_plundererAI, ingvar->AI())) + ai->StartZombiePhase(); me->GetMotionMaster()->MovePoint(2, x+1, y, z+30); ++uiResurectPhase; -- cgit v1.2.3