From 803acccb0723143e95df107eaf04477c791702a4 Mon Sep 17 00:00:00 2001 From: danik Date: Fri, 6 Jan 2012 17:49:15 +0100 Subject: Command/Account: fixed crash when creating account from console --- src/server/scripts/Commands/cs_account.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/server/scripts') diff --git a/src/server/scripts/Commands/cs_account.cpp b/src/server/scripts/Commands/cs_account.cpp index bd415c0f79f..ac265acbf71 100644 --- a/src/server/scripts/Commands/cs_account.cpp +++ b/src/server/scripts/Commands/cs_account.cpp @@ -109,7 +109,8 @@ public: { case AOR_OK: handler->PSendSysMessage(LANG_ACCOUNT_CREATED, accountName); - sLog->outChar("Account: %d (IP: %s) Character:[%s] (GUID: %u) Change Password.", handler->GetSession()->GetAccountId(),handler->GetSession()->GetRemoteAddress().c_str(), handler->GetSession()->GetPlayer()->GetName(), handler->GetSession()->GetPlayer()->GetGUIDLow()); + if (handler->GetSession()) + sLog->outChar("Account: %d (IP: %s) Character:[%s] (GUID: %u) Change Password.", handler->GetSession()->GetAccountId(),handler->GetSession()->GetRemoteAddress().c_str(), handler->GetSession()->GetPlayer()->GetName(), handler->GetSession()->GetPlayer()->GetGUIDLow()); break; case AOR_NAME_TOO_LONG: handler->SendSysMessage(LANG_ACCOUNT_TOO_LONG); -- cgit v1.2.3 From fbe3eaf2266039fe5469fd79c1cae92d278ead97 Mon Sep 17 00:00:00 2001 From: Emo Norfik Date: Sat, 7 Jan 2012 20:42:18 +0100 Subject: Scripts/Trial of the Crusader: Fix height position of Permafrost casted by Frost Sphere. It needs option "vmap.enableHeight = 1" to work properly. --- .../TrialOfTheCrusader/boss_anubarak_trial.cpp | 26 +++++++--------------- 1 file changed, 8 insertions(+), 18 deletions(-) (limited to 'src/server/scripts') diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp index e6678be3a2b..bc6145252d2 100755 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp @@ -568,12 +568,11 @@ public: } bool m_bFall; - uint32 m_uiPermafrostTimer; + float x, y, z; void Reset() { m_bFall = false; - m_uiPermafrostTimer = 0; me->SetReactState(REACT_PASSIVE); me->SetFlying(true); me->SetDisplayId(25144); @@ -590,11 +589,13 @@ public: if (!m_bFall) { m_bFall = true; - me->SetFlying(false); me->GetMotionMaster()->MoveIdle(); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); //At hit the ground - me->GetMotionMaster()->MoveFall(142.2f, 0); + me->GetPosition(x, y, z); + z = me->GetMap()->GetHeight(x, y, z, true, 50); + me->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH); + me->GetMotionMaster()->MoveFall(z, 0); //me->FallGround(); //need correct vmap use (i believe it isn't working properly right now) } } @@ -607,24 +608,13 @@ public: switch (uiId) { case 0: - m_uiPermafrostTimer = IN_MILLISECONDS; - break; - } - } - - void UpdateAI(const uint32 uiDiff) - { - if (m_uiPermafrostTimer) - { - if (m_uiPermafrostTimer <= uiDiff) - { - m_uiPermafrostTimer = 0; me->RemoveAurasDueToSpell(SPELL_FROST_SPHERE); me->SetDisplayId(11686); - me->SetFloatValue(OBJECT_FIELD_SCALE_X, 2.0f); + me->Relocate(x, y, z, me->GetOrientation()); DoCast(SPELL_PERMAFROST_VISUAL); DoCast(SPELL_PERMAFROST); - } else m_uiPermafrostTimer -= uiDiff; + me->SetFloatValue(OBJECT_FIELD_SCALE_X, 2.0f); + break; } } }; -- cgit v1.2.3 From b52f381c3e5c8d24ae420afd47238c6a4d5e3d5a Mon Sep 17 00:00:00 2001 From: malcrom Date: Sun, 8 Jan 2012 09:55:34 +0100 Subject: DB/SAI: convert Blood Knight Dawnstar script to DB closes #4701 --- sql/updates/world/2012_01_08_01_world_sai.sql | 24 ++++++++++++++ src/server/scripts/EasternKingdoms/ghostlands.cpp | 39 ----------------------- 2 files changed, 24 insertions(+), 39 deletions(-) create mode 100644 sql/updates/world/2012_01_08_01_world_sai.sql (limited to 'src/server/scripts') diff --git a/sql/updates/world/2012_01_08_01_world_sai.sql b/sql/updates/world/2012_01_08_01_world_sai.sql new file mode 100644 index 00000000000..fcdc21662c0 --- /dev/null +++ b/sql/updates/world/2012_01_08_01_world_sai.sql @@ -0,0 +1,24 @@ +-- UPDATE Blood Knight Dawnstar Gossip +SET @ENTRY := 17832; +SET @GOSSIPID := 7486; +SET @TEXTID := 9070; +-- Creature Gossip_menu_id Update from sniff +UPDATE `creature_template` SET `gossip_menu_id`=@GOSSIPID WHERE `entry`=@ENTRY; +-- Gossip Menu insert from sniff +DELETE FROM `gossip_menu` WHERE `entry`=@GOSSIPID AND `text_id`=@TEXTID; +INSERT INTO `gossip_menu` (`entry`,`text_id`) VALUES (@GOSSIPID,@TEXTID); +-- Creature Gossip_menu_option Update from sniff +DELETE FROM `gossip_menu_option` WHERE `menu_id` IN (@GOSSIPID) AND `id` IN (0); +INSERT INTO `gossip_menu_option` (`menu_id`,`id`,`option_icon`,`option_text`,`option_id`,`npc_option_npcflag`,`action_menu_id`,`action_poi_id`,`box_coded`,`box_money`,`box_text`) VALUES +(@GOSSIPID,0,0, 'Take Blood Knight Insignia',1,1,0,0,0,0, ''); +-- Gossip option Conditions +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup`=@GOSSIPID; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES +(15,@GOSSIPID,0,0,9,9692,0,0,0,'','Show gossip option if player has quest 9692 but not complete'), +(15,@GOSSIPID,0,0,26,24226,1,0,0,'','Show gossip option if player does not have item 24226'); +-- SAI for Blood Knight Dawnstar +UPDATE `creature_template` SET `AIName`='SmartAI',`ScriptName`='' WHERE `entry`=@ENTRY; +DELETE FROM `smart_scripts` WHERE (`entryorguid`=@ENTRY 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 +(@ENTRY,0,0,1,62,0,100,0,@GOSSIPID,0,0,0,56,24226,1,0,0,0,0,7,0,0,0,0,0,0,0,'Blood Knight Dawnstar - On Gossip option select - Create Blood Knight Insignia'), +(@ENTRY,0,1,0,61,0,100,0,0,0,0,0,72,0,0,0,0,0,0,7,0,0,0,0,0,0,0,'Blood Knight Dawnstar - On Gossip option select - Close Gossip'); diff --git a/src/server/scripts/EasternKingdoms/ghostlands.cpp b/src/server/scripts/EasternKingdoms/ghostlands.cpp index a5a8bd45cfd..6c33ee4a02c 100644 --- a/src/server/scripts/EasternKingdoms/ghostlands.cpp +++ b/src/server/scripts/EasternKingdoms/ghostlands.cpp @@ -33,45 +33,6 @@ EndContentData */ #include "ScriptPCH.h" #include "ScriptedEscortAI.h" -/*###### -## npc_blood_knight_dawnstar -######*/ - -#define GOSSIP_H_BKD "Take Blood Knight Insignia" - -class npc_blood_knight_dawnstar : public CreatureScript -{ -public: - npc_blood_knight_dawnstar() : CreatureScript("npc_blood_knight_dawnstar") { } - - bool OnGossipSelect(Player* player, Creature* /*creature*/, uint32 /*uiSender*/, uint32 uiAction) - { - player->PlayerTalkClass->ClearMenus(); - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - ItemPosCountVec dest; - uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, 24226, 1, NULL); - if (msg == EQUIP_ERR_OK) - { - player->StoreNewItem(dest, 24226, 1, true); - player->PlayerTalkClass->ClearMenus(); - } - } - return true; - } - - bool OnGossipHello(Player* player, Creature* creature) - { - if (player->GetQuestStatus(9692) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(24226, 1, true)) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_H_BKD, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); - - return true; - } - -}; - /*###### ## npc_budd_nedreck ######*/ -- cgit v1.2.3 From c65dec07f8ac9c69b82c739d304d84589163fd8b Mon Sep 17 00:00:00 2001 From: ZxBiohazardZx Date: Sun, 8 Jan 2012 11:13:03 +0100 Subject: Core/Scripts: remove call to unexisting class related to b52f381c3e5c8d24ae420afd47238c6a4d5e3d5a --- src/server/scripts/EasternKingdoms/ghostlands.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/server/scripts') diff --git a/src/server/scripts/EasternKingdoms/ghostlands.cpp b/src/server/scripts/EasternKingdoms/ghostlands.cpp index 6c33ee4a02c..412613572f1 100644 --- a/src/server/scripts/EasternKingdoms/ghostlands.cpp +++ b/src/server/scripts/EasternKingdoms/ghostlands.cpp @@ -216,7 +216,6 @@ public: void AddSC_ghostlands() { - new npc_blood_knight_dawnstar(); new npc_budd_nedreck(); new npc_rathis_tomber(); new npc_ranger_lilatha(); -- cgit v1.2.3 From b6f9caff6bb0c5ad0262a5e9a1db2b988bff65ce Mon Sep 17 00:00:00 2001 From: malcrom Date: Sun, 8 Jan 2012 11:43:35 +0100 Subject: Core/Script: update creature_text for Balinda from sniffs closes #4692 --- sql/updates/world/2012_01_08_06_world_creature_text.sql | 11 +++++++++++ .../scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp | 9 +++++---- 2 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 sql/updates/world/2012_01_08_06_world_creature_text.sql (limited to 'src/server/scripts') diff --git a/sql/updates/world/2012_01_08_06_world_creature_text.sql b/sql/updates/world/2012_01_08_06_world_creature_text.sql new file mode 100644 index 00000000000..3372f05e5ac --- /dev/null +++ b/sql/updates/world/2012_01_08_06_world_creature_text.sql @@ -0,0 +1,11 @@ +-- Remove old script text for boss_balinda.cpp "Not sure if the text actually exist" +DELETE FROM `script_texts` WHERE `entry` IN (-1810023,-1810024); +-- Add new creature_text for Captain Balinda Stonehearth +DELETE FROM `creature_text` WHERE `entry` IN (11949); +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +-- Aggro +(11949,0,0, 'Begone, uncouth scum! The Alliance shall prevail in Alterac Valley!',14,0,100,0,0,0, 'Captain Balinda Stonehearth'), +-- Reset +(11949,1,0, 'Filthy Frostwolf cowards! If you want a fight, you''ll have to come to me!',14,0,100,0,0,0, 'Captain Balinda Stonehearth'), +-- (Alliance players receives Stormpike's Salvation buff (+20% health points for 2 minutes)) +(11949,2,0, 'Take heart, Alliance! Throw these villains from Alterac Valley!',14,0,100,0,0,0, 'Captain Balinda Stonehearth'); diff --git a/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp index d3083146967..1292cdaee17 100644 --- a/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp +++ b/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp @@ -27,8 +27,9 @@ enum Spells enum Yells { - YELL_AGGRO = -1810023, - YELL_EVADE = -1810024 + YELL_AGGRO = 0, + YELL_EVADE = 1, + YELL_SALVATION = 2, }; enum Creatures @@ -122,7 +123,7 @@ public: void EnterCombat(Unit* /*who*/) { - DoScriptText(YELL_AGGRO, me); + Talk(YELL_AGGRO); } void JustRespawned() @@ -185,7 +186,7 @@ public: if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50) { EnterEvadeMode(); - DoScriptText(YELL_EVADE, me); + Talk(YELL_EVADE); } resetTimer = 5 * IN_MILLISECONDS; } else resetTimer -= diff; -- cgit v1.2.3 From 2ba7cfacca22a00db7c3647f29249f6b742ded0c Mon Sep 17 00:00:00 2001 From: malcrom Date: Sun, 8 Jan 2012 11:47:41 +0100 Subject: Core/Script: update creature_text for Galvangar from sniffs closes #4694 --- sql/updates/world/2012_01_08_07_world_creature_text.sql | 11 +++++++++++ .../scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 sql/updates/world/2012_01_08_07_world_creature_text.sql (limited to 'src/server/scripts') diff --git a/sql/updates/world/2012_01_08_07_world_creature_text.sql b/sql/updates/world/2012_01_08_07_world_creature_text.sql new file mode 100644 index 00000000000..c929866f4f1 --- /dev/null +++ b/sql/updates/world/2012_01_08_07_world_creature_text.sql @@ -0,0 +1,11 @@ +-- Remove old script text for boss_galvangar.cpp "Not sure if the text actually exist" +DELETE FROM `script_texts` WHERE `entry` IN (-1810021,-1810022); +-- Add new creature_text for Captain Galvangar +DELETE FROM `creature_text` WHERE `entry` IN (11947); +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +-- Aggro +(11947,0,0, 'Die! Your kind has no place in Alterac Valley!',14,0,100,0,0,0, 'Captain Galvangar'), +-- Reset +(11947,1,0, 'I''ll never fall for that, fool! If you want a battle it will be on my terms and in my lair!',14,0,100,0,0,0, 'Captain Galvangar'), +-- Casting Fury of the Frostwolf +(11947,2,0, 'Now is the time to attack! For the Horde!',14,0,100,0,0,0, 'Captain Galvangar'); diff --git a/src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp index 95c16612aef..da53cffc99d 100644 --- a/src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp +++ b/src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp @@ -28,8 +28,8 @@ enum Spells enum Yells { - YELL_AGGRO = -1810021, - YELL_EVADE = -1810022 + YELL_AGGRO = 0, + YELL_EVADE = 1 }; class boss_galvangar : public CreatureScript @@ -60,7 +60,7 @@ public: void EnterCombat(Unit* /*who*/) { - DoScriptText(YELL_AGGRO, me); + Talk(YELL_AGGRO); } void JustRespawned() @@ -109,7 +109,7 @@ public: if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50) { EnterEvadeMode(); - DoScriptText(YELL_EVADE, me); + Talk(YELL_EVADE); } ResetTimer = 5 * IN_MILLISECONDS; } else ResetTimer -= diff; -- cgit v1.2.3 From 4112b2a7d4bdf4237ff5caeb6fdf35ec8365d28a Mon Sep 17 00:00:00 2001 From: malcrom Date: Sun, 8 Jan 2012 11:58:19 +0100 Subject: Core/Script: update creature_text for Drekthar from sniffs closes #4693 --- .../world/2012_01_08_08_world_creature_text.sql | 17 +++++++++++++++++ .../EasternKingdoms/AlteracValley/boss_drekthar.cpp | 20 ++++++++------------ 2 files changed, 25 insertions(+), 12 deletions(-) create mode 100644 sql/updates/world/2012_01_08_08_world_creature_text.sql (limited to 'src/server/scripts') diff --git a/sql/updates/world/2012_01_08_08_world_creature_text.sql b/sql/updates/world/2012_01_08_08_world_creature_text.sql new file mode 100644 index 00000000000..42249e67b84 --- /dev/null +++ b/sql/updates/world/2012_01_08_08_world_creature_text.sql @@ -0,0 +1,17 @@ +-- Remove old script text for boss_drekthar.cpp "Not sure if the text actually exist" +DELETE FROM `script_texts` WHERE `entry` IN (-1810000,-1810001,-1810002,-1810003,-1810004,-1810005,-1810006,-1810007); +-- Add new creature_text for Drek'Thar +DELETE FROM `creature_text` WHERE `entry` IN (11946); +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +-- Aggro +(11946,0,0, 'Stormpike filth! In my keep?! Slay them all!',14,0,100,0,0,0, 'Drek''Thar'), +-- Reset +(11946,1,0, 'You seek to draw the General of the Frostwolf legion out from his fortress? PREPOSTEROUS!',14,0,100,0,0,0, 'Drek''Thar'), +-- Raid wipe +(11946,2,0, 'Stormpike weaklings, face me in my fortress - if you dare!',14,0,100,0,0,0, 'Drek''Thar'), +-- Combat +(11946,3,0, 'Your attacks are slowed by the cold, I think!',14,0,100,0,0,0, 'Drek''Thar'), +(11946,3,1, 'Today, you will meet your ancestors!',14,0,100,0,0,0, 'Drek''Thar'), +(11946,3,2, 'If you will not leave Alterac Valley on your own, then the Frostwolves will force you out!',14,0,100,0,0,0, 'Drek''Thar'), +(11946,3,3, 'You cannot defeat the Frostwolf clan!',14,0,100,0,0,0, 'Drek''Thar'), +(11946,3,4, 'You are no match for the strength of the Horde!',14,0,100,0,0,0, 'Drek''Thar'); diff --git a/src/server/scripts/EasternKingdoms/AlteracValley/boss_drekthar.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/boss_drekthar.cpp index 959ed88be1c..8b2a95be977 100644 --- a/src/server/scripts/EasternKingdoms/AlteracValley/boss_drekthar.cpp +++ b/src/server/scripts/EasternKingdoms/AlteracValley/boss_drekthar.cpp @@ -31,14 +31,10 @@ enum Spells enum Yells { - YELL_AGGRO = -1810000, - YELL_EVADE = -1810001, - YELL_RESPAWN = -1810002, - YELL_RANDOM1 = -1810003, - YELL_RANDOM2 = -1810004, - YELL_RANDOM3 = -1810005, - YELL_RANDOM4 = -1810006, - YELL_RANDOM5 = -1810007 + YELL_AGGRO = 0, + YELL_EVADE = 1, + YELL_RESPAWN = 2, + YELL_RANDOM = 3 }; class boss_drekthar : public CreatureScript @@ -69,13 +65,13 @@ public: void EnterCombat(Unit* /*who*/) { - DoScriptText(YELL_AGGRO, me); + Talk(YELL_AGGRO); } void JustRespawned() { Reset(); - DoScriptText(YELL_RESPAWN, me); + Talk(YELL_RESPAWN); } void UpdateAI(const uint32 diff) @@ -109,7 +105,7 @@ public: if (YellTimer <= diff) { - DoScriptText(RAND(YELL_RANDOM1, YELL_RANDOM2, YELL_RANDOM3, YELL_RANDOM4, YELL_RANDOM5), me); + Talk(YELL_RANDOM); YellTimer = urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS); //20 to 30 seconds } else YellTimer -= diff; @@ -119,7 +115,7 @@ public: if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50) { EnterEvadeMode(); - DoScriptText(YELL_EVADE, me); + Talk(YELL_EVADE); } ResetTimer = 5 * IN_MILLISECONDS; } else ResetTimer -= diff; -- cgit v1.2.3 From ae4d221b3cb701514165a70d5e1c8ecf8bab6806 Mon Sep 17 00:00:00 2001 From: malcrom Date: Sun, 8 Jan 2012 12:07:12 +0100 Subject: Core/Script: update creature_text for Vanndar from sniffs closes #4696 --- .../world/2012_01_08_09_world_creature_text.sql | 20 ++++++++++++++++++++ .../EasternKingdoms/AlteracValley/boss_vanndar.cpp | 22 ++++++++-------------- 2 files changed, 28 insertions(+), 14 deletions(-) create mode 100644 sql/updates/world/2012_01_08_09_world_creature_text.sql (limited to 'src/server/scripts') diff --git a/sql/updates/world/2012_01_08_09_world_creature_text.sql b/sql/updates/world/2012_01_08_09_world_creature_text.sql new file mode 100644 index 00000000000..c838e6dc4f2 --- /dev/null +++ b/sql/updates/world/2012_01_08_09_world_creature_text.sql @@ -0,0 +1,20 @@ +-- Remove old script text for boss_vanndar.cpp "Not sure if the text actually exist" +DELETE FROM `script_texts` WHERE `entry` BETWEEN -181008 AND -1810018; +-- Add new creature_text for Vanndar Stormpike +DELETE FROM `creature_text` WHERE `entry` IN (11948); +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +-- Aggro +(11948,0,0, 'Soldiers of Stormpike, your General is under attack! I require aid! Come! Come! Slay these mangy Frostwolf dogs.',14,0,100,0,0,0, 'Vanndar Stormpike'), +-- Reset +(11948,1,0, 'You''ll never get me out of me bunker, heathens!',14,0,100,0,0,0, 'Vanndar Stormpike'), +(11948,1,1, 'Why don''t ya try again without yer cheap tactics, pansies! Or are you too chicken?',14,0,100,0,0,0, 'Vanndar Stormpike'), +-- Combat +(11948,2,0, 'I will tell you this much...Alterac Valley will be ours.',14,0,100,0,0,0, 'Vanndar Stormpike'), +(11948,2,1, 'Your attacks are weak! Go practice on some rabbits and come back when you''re stronger.',14,0,100,0,0,0, 'Vanndar Stormpike'), +(11948,2,2, 'We will not be swayed from our mission!',14,0,100,0,0,0, 'Vanndar Stormpike'), +(11948,2,3, 'It''ll take more than you rabble to bring me down!',14,0,100,0,0,0, 'Vanndar Stormpike'), +(11948,2,4, 'We, the Alliance, will prevail!',14,0,100,0,0,0, 'Vanndar Stormpike'), +(11948,2,5, 'The Stormpike clan bows to no one, especially the horde!',14,0,100,0,0,0, 'Vanndar Stormpike'), +(11948,2,6, 'Is that the best you can do?',14,0,100,0,0,0, 'Vanndar Stormpike'), +-- Said with a spell cast (Alliance players receive 10/20/30% damage/size increases, gained by turning in [Polished Armor Scraps] +(11948,3,0, 'Take no prisoners! Drive these heathens from our lands!',14,0,100,0,0,0, 'Vanndar Stormpike'); diff --git a/src/server/scripts/EasternKingdoms/AlteracValley/boss_vanndar.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/boss_vanndar.cpp index 94b5bc9a56c..f5d2db1c347 100644 --- a/src/server/scripts/EasternKingdoms/AlteracValley/boss_vanndar.cpp +++ b/src/server/scripts/EasternKingdoms/AlteracValley/boss_vanndar.cpp @@ -19,17 +19,11 @@ enum Yells { - YELL_AGGRO = -1810008, - YELL_EVADE = -1810009, - YELL_RESPAWN1 = -1810010, - YELL_RESPAWN2 = -1810011, - YELL_RANDOM1 = -1810012, - YELL_RANDOM2 = -1810013, - YELL_RANDOM3 = -1810014, - YELL_RANDOM4 = -1810015, - YELL_RANDOM5 = -1810016, - YELL_RANDOM6 = -1810017, - YELL_RANDOM7 = -1810018 + YELL_AGGRO = 0, + YELL_EVADE = 1, + YELL_RESPAWN1 = -1810010, // no creature_text + YELL_RESPAWN2 = -1810011, // no creature_text + YELL_RANDOM1 = 3 }; enum Spells @@ -65,7 +59,7 @@ public: void EnterCombat(Unit* /*who*/) { - DoScriptText(YELL_AGGRO, me); + Talk(YELL_AGGRO); } void JustRespawned() @@ -99,7 +93,7 @@ public: if (YellTimer <= diff) { - DoScriptText(RAND(YELL_RANDOM1, YELL_RANDOM2, YELL_RANDOM3, YELL_RANDOM4, YELL_RANDOM5, YELL_RANDOM6, YELL_RANDOM7), me); + Talk(YELL_RANDOM); YellTimer = urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS); //20 to 30 seconds } else YellTimer -= diff; @@ -109,7 +103,7 @@ public: if (me->GetDistance2d(me->GetHomePosition().GetPositionX(), me->GetHomePosition().GetPositionY()) > 50) { EnterEvadeMode(); - DoScriptText(YELL_EVADE, me); + Talk(YELL_EVADE); } ResetTimer = 5 * IN_MILLISECONDS; } else ResetTimer -= diff; -- cgit v1.2.3 From b556ac564b10184060e22941044d81f03b120229 Mon Sep 17 00:00:00 2001 From: ZxBiohazardZx Date: Sun, 8 Jan 2012 12:50:15 +0100 Subject: Core/Build: fix build --- src/server/scripts/EasternKingdoms/AlteracValley/boss_vanndar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/server/scripts') diff --git a/src/server/scripts/EasternKingdoms/AlteracValley/boss_vanndar.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/boss_vanndar.cpp index f5d2db1c347..f885538c909 100644 --- a/src/server/scripts/EasternKingdoms/AlteracValley/boss_vanndar.cpp +++ b/src/server/scripts/EasternKingdoms/AlteracValley/boss_vanndar.cpp @@ -23,7 +23,7 @@ enum Yells YELL_EVADE = 1, YELL_RESPAWN1 = -1810010, // no creature_text YELL_RESPAWN2 = -1810011, // no creature_text - YELL_RANDOM1 = 3 + YELL_RANDOM = 3 }; enum Spells -- cgit v1.2.3 From 7b86761045286efd8fcceb7fffef10bd9c219d4a Mon Sep 17 00:00:00 2001 From: malcrom Date: Sun, 8 Jan 2012 13:23:54 +0100 Subject: Core/Script: update creature_text for Phizzlethorpe from sniffs closes #4698 --- .../world/2012_01_08_10_world_creature_text.sql | 25 ++++++++++++++ .../scripts/EasternKingdoms/arathi_highlands.cpp | 40 +++++++++++----------- 2 files changed, 45 insertions(+), 20 deletions(-) create mode 100644 sql/updates/world/2012_01_08_10_world_creature_text.sql (limited to 'src/server/scripts') diff --git a/sql/updates/world/2012_01_08_10_world_creature_text.sql b/sql/updates/world/2012_01_08_10_world_creature_text.sql new file mode 100644 index 00000000000..b93a0a50d39 --- /dev/null +++ b/sql/updates/world/2012_01_08_10_world_creature_text.sql @@ -0,0 +1,25 @@ +-- Remove old script text for arathi_highlands.cpp +DELETE FROM `script_texts` WHERE `entry` BETWEEN -1000264 AND -1000273; +-- Add new creature_text for Professor Phizzlethorpe +DELETE FROM `creature_text` WHERE `entry` IN (2768); +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +-- SAY_PROGRESS_1 +(2768,0,0, 'Ok, $N. Follow me to the cave where I''ll attempt to harness the power of the rune stone into these goggles.',12,0,100,0,0,0, 'Professor Phizzlethorpe'), +-- SAY_PROGRESS_2 +(2768,1,0, 'I discovered this cave on our first day here. I believe the energy in the stone can be used to our advantage.',12,0,100,0,0,0, 'Professor Phizzlethorpe'), +-- SAY_PROGRESS_3 +(2768,2,0, 'I''ll begin drawing energy from the stone. Your job, $N, is to defend me. This place is cursed... trust me.',12,0,100,0,0,0, 'Professor Phizzlethorpe'), +-- EMOTE_PROGRESS_4 +(2768,3,0, '%s begins tinkering with the goggles before the stone.',16,0,100,0,0,0, 'Professor Phizzlethorpe'), +-- SAY_AGGRO +(2768,4,0, 'Help!!! Get these things off me so I can get my work done!',12,0,100,0,0,0, 'Professor Phizzlethorpe'), +-- SAY_PROGRESS_5 +(2768,5,0, 'Almost done! Just a little longer!',12,0,100,0,0,0, 'Professor Phizzlethorpe'), +-- SAY_PROGRESS_6 +(2768,6,0, 'I''ve done it! I have harnessed the power of the stone into the goggles! Let''s get out of here!',12,0,100,0,0,0, 'Professor Phizzlethorpe'), +-- SAY_PROGRESS_7 +(2768,7,0, 'Phew! Glad to be back from that creepy cave.',12,0,100,0,0,0, 'Professor Phizzlethorpe'), +-- EMOTE_PROGRESS_8 +(2768,8,0, '%s hands one glowing goggles over to Doctor Draxlegauge.',16,0,100,0,0,0, 'Professor Phizzlethorpe'), +-- SAY_PROGRESS_9 +(2768,9,0, 'Doctor Draxlegauge will give you further instructions, $N. Many thanks for your help!',12,0,100,0,0,0, 'Professor Phizzlethorpe'); diff --git a/src/server/scripts/EasternKingdoms/arathi_highlands.cpp b/src/server/scripts/EasternKingdoms/arathi_highlands.cpp index 8b6cbf26de2..e2a9717882b 100644 --- a/src/server/scripts/EasternKingdoms/arathi_highlands.cpp +++ b/src/server/scripts/EasternKingdoms/arathi_highlands.cpp @@ -36,16 +36,16 @@ EndContentData */ enum eEnums { - SAY_PROGRESS_1 = -1000264, - SAY_PROGRESS_2 = -1000265, - SAY_PROGRESS_3 = -1000266, - EMOTE_PROGRESS_4 = -1000267, - SAY_AGGRO = -1000268, - SAY_PROGRESS_5 = -1000269, - SAY_PROGRESS_6 = -1000270, - SAY_PROGRESS_7 = -1000271, - EMOTE_PROGRESS_8 = -1000272, - SAY_PROGRESS_9 = -1000273, + SAY_PROGRESS_1 = 0, + SAY_PROGRESS_2 = 1, + SAY_PROGRESS_3 = 2, + EMOTE_PROGRESS_4 = 3, + SAY_AGGRO = 4, + SAY_PROGRESS_5 = 5, + SAY_PROGRESS_6 = 6, + SAY_PROGRESS_7 = 7, + EMOTE_PROGRESS_8 = 8, + SAY_PROGRESS_9 = 9, QUEST_SUNKEN_TREASURE = 665, MOB_VENGEFUL_SURGE = 2776 @@ -73,24 +73,24 @@ class npc_professor_phizzlethorpe : public CreatureScript switch (uiPointId) { - case 4:DoScriptText(SAY_PROGRESS_2, me, player);break; - case 5:DoScriptText(SAY_PROGRESS_3, me, player);break; - case 8:DoScriptText(EMOTE_PROGRESS_4, me);break; + case 4:Talk(SAY_PROGRESS_2, player->GetGUID());break; + case 5:Talk(SAY_PROGRESS_3, player->GetGUID());break; + case 8:Talk(EMOTE_PROGRESS_4);break; case 9: { me->SummonCreature(MOB_VENGEFUL_SURGE, -2052.96f, -2142.49f, 20.15f, 1.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); me->SummonCreature(MOB_VENGEFUL_SURGE, -2052.96f, -2142.49f, 20.15f, 1.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); break; } - case 10:DoScriptText(SAY_PROGRESS_5, me, player);break; + case 10:Talk(SAY_PROGRESS_5, player->GetGUID());break; case 11: - DoScriptText(SAY_PROGRESS_6, me, player); + Talk(SAY_PROGRESS_6, player->GetGUID()); SetRun(); break; - case 19:DoScriptText(SAY_PROGRESS_7, me, player); break; + case 19:Talk(SAY_PROGRESS_7, player->GetGUID()); break; case 20: - DoScriptText(EMOTE_PROGRESS_8, me); - DoScriptText(SAY_PROGRESS_9, me, player); + Talk(EMOTE_PROGRESS_8); + Talk(SAY_PROGRESS_9, player->GetGUID()); if (player) CAST_PLR(player)->GroupEventHappens(QUEST_SUNKEN_TREASURE, me); break; @@ -104,7 +104,7 @@ class npc_professor_phizzlethorpe : public CreatureScript void EnterCombat(Unit* /*who*/) { - DoScriptText(SAY_AGGRO, me); + Talk(SAY_AGGRO); } void UpdateAI(const uint32 diff) @@ -122,7 +122,7 @@ class npc_professor_phizzlethorpe : public CreatureScript { if (quest->GetQuestId() == QUEST_SUNKEN_TREASURE) { - DoScriptText(SAY_PROGRESS_1, creature, player); + creature->AI()->Talk(SAY_PROGRESS_1, player->GetGUID()); if (npc_escortAI* pEscortAI = CAST_AI(npc_professor_phizzlethorpeAI, (creature->AI()))) pEscortAI->Start(false, false, player->GetGUID(), quest); -- cgit v1.2.3 From 57e1972b86a0f1dae1ab8c7832814df000407c71 Mon Sep 17 00:00:00 2001 From: malcrom Date: Sun, 8 Jan 2012 13:34:49 +0100 Subject: Core/Script: update creature_text for the Paladin Trial Quests in Eversong from sniffs closes #4699 --- sql/updates/world/2012_01_08_11_world_creature_text.sql | 9 +++++++++ src/server/scripts/EasternKingdoms/eversong_woods.cpp | 16 ++++++++-------- 2 files changed, 17 insertions(+), 8 deletions(-) create mode 100644 sql/updates/world/2012_01_08_11_world_creature_text.sql (limited to 'src/server/scripts') diff --git a/sql/updates/world/2012_01_08_11_world_creature_text.sql b/sql/updates/world/2012_01_08_11_world_creature_text.sql new file mode 100644 index 00000000000..bf34c1f541c --- /dev/null +++ b/sql/updates/world/2012_01_08_11_world_creature_text.sql @@ -0,0 +1,9 @@ +-- Remove old script text for eversong_woods.cpp +DELETE FROM `script_texts` WHERE `entry` BETWEEN -1000637 AND -1000640; +-- Master Kelerun Bloodmourn say text +DELETE FROM `creature_text` WHERE `entry`=17807; +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +(17807,0,0, 'Let the trial begin, Bloodwrath, attack!',14,0,100,0,0,0, 'Master Kelerun Bloodmourn'), +(17807,1,0, 'Champion Lightrend, make me proud!',14,0,100,0,0,0, 'Master Kelerun Bloodmourn'), +(17807,2,0, 'Show this upstart how a real Blood Knight fights, Swiftblade!',14,0,100,0,0,0, 'Master Kelerun Bloodmourn'), +(17807,3,0, 'Show $N the meaning of pain, Sunstriker!',14,0,100,0,0,0, 'Master Kelerun Bloodmourn'); diff --git a/src/server/scripts/EasternKingdoms/eversong_woods.cpp b/src/server/scripts/EasternKingdoms/eversong_woods.cpp index 7c09a740d26..4797774ef49 100644 --- a/src/server/scripts/EasternKingdoms/eversong_woods.cpp +++ b/src/server/scripts/EasternKingdoms/eversong_woods.cpp @@ -69,10 +69,10 @@ enum eFaction enum eSays { - TEXT_SECOND_TRIAL_1 = -1000637, - TEXT_SECOND_TRIAL_2 = -1000638, - TEXT_SECOND_TRIAL_3 = -1000639, - TEXT_SECOND_TRIAL_4 = -1000640, + TEXT_SECOND_TRIAL_1 = 0, + TEXT_SECOND_TRIAL_2 = 1, + TEXT_SECOND_TRIAL_3 = 2, + TEXT_SECOND_TRIAL_4 = 3, }; struct Locations @@ -335,16 +335,16 @@ public: switch (paladinPhase) { case 0: - DoScriptText(TEXT_SECOND_TRIAL_1, me); + Talk(TEXT_SECOND_TRIAL_1); break; case 1: - DoScriptText(TEXT_SECOND_TRIAL_2, me); + Talk(TEXT_SECOND_TRIAL_2); break; case 2: - DoScriptText(TEXT_SECOND_TRIAL_3, me); + Talk(TEXT_SECOND_TRIAL_3); break; case 3: - DoScriptText(TEXT_SECOND_TRIAL_4, me); + Talk(TEXT_SECOND_TRIAL_4); break; } } -- cgit v1.2.3 From 138e5309e6fff172e56a08a8af844c2c1975eca4 Mon Sep 17 00:00:00 2001 From: Emo Norfik Date: Sat, 7 Jan 2012 21:18:27 +0100 Subject: Scripts/Halls of Lightning: Implement "Lightning Struck" achievement. --- .../HallsOfLightning/01_boss_general_bjarngrim.sql | 30 ++++++++++++ .../Ulduar/HallsOfLightning/boss_bjarngrim.cpp | 54 +++++++++++++++++++++- 2 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 sql/custom/Ulduar/HallsOfLightning/01_boss_general_bjarngrim.sql (limited to 'src/server/scripts') diff --git a/sql/custom/Ulduar/HallsOfLightning/01_boss_general_bjarngrim.sql b/sql/custom/Ulduar/HallsOfLightning/01_boss_general_bjarngrim.sql new file mode 100644 index 00000000000..b4a77999612 --- /dev/null +++ b/sql/custom/Ulduar/HallsOfLightning/01_boss_general_bjarngrim.sql @@ -0,0 +1,30 @@ +-- HoL General Bjarngrim event Temporary Electrical Charge +-- Clear wrong aura +UPDATE `creature_addon` SET `auras`='' WHERE `guid` = 126981; + +-- add spell link for Temporary Electrical Charge +DELETE FROM `spell_linked_spell` WHERE `spell_trigger`='-52098' AND `spell_effect`='52092'; +INSERT INTO `spell_linked_spell` (`spell_trigger`, `spell_effect`, `type`, `comment`) VALUES +('-52098', '52092', '0', 'Charge Up - Temporary Electrical Charge'); + +-- Set 10 sec delay on platforms where boss gets Temporary Electrical Charge +UPDATE `waypoint_data` SET `delay`=10000 WHERE `id`=1269810 AND `point` IN (2, 5, 11, 14); + +-- Cast self Charge Up to get Temporary Electrical Charge +DELETE FROM `waypoint_scripts` WHERE `id`=12698101; +INSERT INTO `waypoint_scripts` (`id`, `delay`, `command`, `datalong`, `datalong2`, `dataint`, `x`, `y`, `z`, `o`, `guid`) VALUES +(12698101, 0, 14, 52092, 1, 0, 0, 0, 0, 0, 855), +(12698101, 2, 15, 52098, 1, 0, 0, 0, 0, 0, 856); +UPDATE `waypoint_data` SET `action`=12698101 WHERE `id`=1269810 AND `point` IN (5, 14); + +-- Remove aura Temporary Electrical Charge +DELETE FROM `waypoint_scripts` WHERE `id`=12698102; +INSERT INTO `waypoint_scripts` (`id`, `delay`, `command`, `datalong`, `datalong2`, `dataint`, `x`, `y`, `z`, `o`, `guid`) VALUES +(12698102, 0, 14, 52092, 1, 0, 0, 0, 0, 0, 857); +UPDATE `waypoint_data` SET `action`=12698102 WHERE `id`=1269810 AND `point` IN (2, 3, 4, 11, 12, 13); + +-- Lightning Struck achievement +DELETE FROM `disables` WHERE `sourceType`=4 AND `entry`=6835; +DELETE FROM `achievement_criteria_data` WHERE `type`=11 AND `criteria_id`=6835; +INSERT INTO `achievement_criteria_data` (`criteria_id`, `type`, `value1`, `value2`, `ScriptName`) VALUES +(6835, 11, 0, 0, 'achievement_lightning_struck'); diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp index e96801f3ecb..0cf69eeb537 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp @@ -61,7 +61,7 @@ enum eEnums //OTHER SPELLS //SPELL_CHARGE_UP = 52098, // only used when starting walk from one platform to the other - //SPELL_TEMPORARY_ELECTRICAL_CHARGE = 52092, // triggered part of above + SPELL_TEMPORARY_ELECTRICAL_CHARGE = 52092, // triggered part of above NPC_STORMFORGED_LIEUTENANT = 29240, SPELL_ARC_WELD = 59085, @@ -77,6 +77,8 @@ enum eEnums STANCE_BATTLE = 2 }; +#define DATA_LIGHTNING_STRUCK 1834 + /*###### ## boss_bjarngrim ######*/ @@ -98,11 +100,14 @@ public: m_instance = creature->GetInstanceScript(); m_uiStance = STANCE_DEFENSIVE; memset(&m_auiStormforgedLieutenantGUID, 0, sizeof(m_auiStormforgedLieutenantGUID)); + canBuff = true; } InstanceScript* m_instance; bool m_bIsChangingStance; + bool achiLightningStruck; + bool canBuff; uint8 m_uiChargingStatus; uint8 m_uiStance; @@ -126,6 +131,11 @@ public: void Reset() { + if (canBuff) + if (!me->HasAura(SPELL_TEMPORARY_ELECTRICAL_CHARGE)) + me->AddAura(SPELL_TEMPORARY_ELECTRICAL_CHARGE, me); + + achiLightningStruck = false; m_bIsChangingStance = false; m_uiChargingStatus = 0; @@ -167,8 +177,21 @@ public: m_instance->SetData(TYPE_BJARNGRIM, NOT_STARTED); } + void EnterEvadeMode() + { + if (me->HasAura(SPELL_TEMPORARY_ELECTRICAL_CHARGE)) + canBuff = true; + else + canBuff = false; + + ScriptedAI::EnterEvadeMode(); + } + void EnterCombat(Unit* /*who*/) { + if (me->HasAura(SPELL_TEMPORARY_ELECTRICAL_CHARGE)) + achiLightningStruck = true; + DoScriptText(SAY_AGGRO, me); //must get both lieutenants here and make sure they are with him @@ -178,6 +201,14 @@ public: m_instance->SetData(TYPE_BJARNGRIM, IN_PROGRESS); } + uint32 GetData(uint32 type) + { + if (type == DATA_LIGHTNING_STRUCK) + return achiLightningStruck ? 1 : 0; + + return 0; + } + void KilledUnit(Unit* /*victim*/) { DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2, SAY_SLAY_3), me); @@ -211,7 +242,7 @@ public: void UpdateAI(const uint32 uiDiff) { //Return since we have no target - if (!UpdateVictim()) + if (!UpdateVictim()) return; // Change stance @@ -432,8 +463,27 @@ public: }; +class achievement_lightning_struck : public AchievementCriteriaScript +{ + public: + achievement_lightning_struck() : AchievementCriteriaScript("achievement_lightning_struck") { } + + bool OnCheck(Player* /*player*/, Unit* target) + { + if (!target) + return false; + + if (Creature* bjarngrim = target->ToCreature()) + if (bjarngrim->AI()->GetData(DATA_LIGHTNING_STRUCK)) + return true; + + return false; + } +}; + void AddSC_boss_bjarngrim() { new boss_bjarngrim(); new mob_stormforged_lieutenant(); + new achievement_lightning_struck(); } -- cgit v1.2.3 From 03a7f1291624d036d32ca030b2bfc0d982cd5424 Mon Sep 17 00:00:00 2001 From: malcrom Date: Sun, 8 Jan 2012 14:20:11 +0100 Subject: Core/Script: update creature_text for Twilight Corruptor from sniffs closes #4697 --- sql/updates/world/2011_01_08_12_world_creature_text.sql | 6 ++++++ .../EasternKingdoms/AlteracValley/boss_vanndar.cpp | 3 ++- src/server/scripts/EasternKingdoms/duskwood.cpp | 16 ++++++++++++---- 3 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 sql/updates/world/2011_01_08_12_world_creature_text.sql (limited to 'src/server/scripts') diff --git a/sql/updates/world/2011_01_08_12_world_creature_text.sql b/sql/updates/world/2011_01_08_12_world_creature_text.sql new file mode 100644 index 00000000000..a2795b906ef --- /dev/null +++ b/sql/updates/world/2011_01_08_12_world_creature_text.sql @@ -0,0 +1,6 @@ +-- Twilight Corrupter say text +DELETE FROM `creature_text` WHERE `entry` IN (15625); +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +(15625,0,0, 'Come, $N. See what the Nightmare brings...',14,0,100,0,0,0, 'Twilight Corrupter'), +(15625,1,0, 'The Nightmare cannot be stopped!',14,0,100,0,0,0, 'Twilight Corrupter'), +(15625,2,0, 'Twilight Corrupter squeezes the last bit of life out of $N and swallows their soul.',16,0,100,0,0,0, 'Twilight Corrupter'); diff --git a/src/server/scripts/EasternKingdoms/AlteracValley/boss_vanndar.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/boss_vanndar.cpp index f885538c909..54fcb9d99c2 100644 --- a/src/server/scripts/EasternKingdoms/AlteracValley/boss_vanndar.cpp +++ b/src/server/scripts/EasternKingdoms/AlteracValley/boss_vanndar.cpp @@ -23,7 +23,8 @@ enum Yells YELL_EVADE = 1, YELL_RESPAWN1 = -1810010, // no creature_text YELL_RESPAWN2 = -1810011, // no creature_text - YELL_RANDOM = 3 + YELL_RANDOM = 2, + YELL_SPELL = 3, }; enum Spells diff --git a/src/server/scripts/EasternKingdoms/duskwood.cpp b/src/server/scripts/EasternKingdoms/duskwood.cpp index 872137ee937..5d04489bbca 100644 --- a/src/server/scripts/EasternKingdoms/duskwood.cpp +++ b/src/server/scripts/EasternKingdoms/duskwood.cpp @@ -25,6 +25,14 @@ EndScriptData */ #include "ScriptPCH.h" +enum Yells +{ + YELL_TWILIGHTCORRUPTOR_RESPAWN = 0, + YELL_TWILIGHTCORRUPTOR_AGGRO = 1, + YELL_TWILIGHTCORRUPTOR_KILL = 2, +}; + + /*###### # at_twilight_grove ######*/ @@ -43,11 +51,11 @@ public: TCorrupter->setFaction(14); TCorrupter->SetMaxHealth(832750); } - if (Unit* CorrupterSpeaker = player->SummonCreature(1, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()-1, 0, TEMPSUMMON_TIMED_DESPAWN, 15000)) + if (Creature* CorrupterSpeaker = player->SummonCreature(1, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()-1, 0, TEMPSUMMON_TIMED_DESPAWN, 15000)) { CorrupterSpeaker->SetName("Twilight Corrupter"); CorrupterSpeaker->SetVisible(true); - CorrupterSpeaker->MonsterYell("Come, $N. See what the Nightmare brings...", 0, player->GetGUID()); + CorrupterSpeaker->AI()->Talk(YELL_TWILIGHTCORRUPTOR_RESPAWN, player->GetGUID()); } } return false; @@ -89,7 +97,7 @@ public: } void EnterCombat(Unit* /*who*/) { - me->MonsterYell("The Nightmare cannot be stopped!", 0, me->GetGUID()); + Talk(YELL_TWILIGHTCORRUPTOR_AGGRO); } void KilledUnit(Unit* victim) @@ -97,7 +105,7 @@ public: if (victim->GetTypeId() == TYPEID_PLAYER) { ++KillCount; - me->MonsterTextEmote("Twilight Corrupter squeezes the last bit of life out of $N and swallows their soul.", victim->GetGUID(), true); + Talk(YELL_TWILIGHTCORRUPTOR_KILL, victim->GetGUID()); if (KillCount == 3) { -- cgit v1.2.3 From c0bc5f6dcc44ba95bf0f75a7486e36b527462d1b Mon Sep 17 00:00:00 2001 From: Emo Norfik Date: Sun, 8 Jan 2012 17:22:31 +0100 Subject: Scripts/Halls of Lightning: Move criteria check for "Lightning Struck" achievement from criteria script to DB. Thx to Vincent-Michael for pointing this out. --- .../HallsOfLightning/02_boss_general_bjarngrim.sql | 5 ++++ .../Ulduar/HallsOfLightning/boss_bjarngrim.cpp | 34 ---------------------- 2 files changed, 5 insertions(+), 34 deletions(-) create mode 100644 sql/custom/Ulduar/HallsOfLightning/02_boss_general_bjarngrim.sql (limited to 'src/server/scripts') diff --git a/sql/custom/Ulduar/HallsOfLightning/02_boss_general_bjarngrim.sql b/sql/custom/Ulduar/HallsOfLightning/02_boss_general_bjarngrim.sql new file mode 100644 index 00000000000..6cd1a367e81 --- /dev/null +++ b/sql/custom/Ulduar/HallsOfLightning/02_boss_general_bjarngrim.sql @@ -0,0 +1,5 @@ +-- Lightning Struck achievement move from criteria script to DB thx Vincent-Michael +DELETE FROM `achievement_criteria_data` WHERE `ScriptName`='achievement_lightning_struck'; +DELETE FROM `achievement_criteria_data` WHERE `type`=7 AND `criteria_id`=6835; +INSERT INTO `achievement_criteria_data` (`criteria_id`, `type`, `value1`, `value2`, `ScriptName`) VALUES +(6835, 7, 52092, 0, ''); diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp index 0cf69eeb537..c6f72890d1f 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp @@ -77,8 +77,6 @@ enum eEnums STANCE_BATTLE = 2 }; -#define DATA_LIGHTNING_STRUCK 1834 - /*###### ## boss_bjarngrim ######*/ @@ -106,7 +104,6 @@ public: InstanceScript* m_instance; bool m_bIsChangingStance; - bool achiLightningStruck; bool canBuff; uint8 m_uiChargingStatus; @@ -135,7 +132,6 @@ public: if (!me->HasAura(SPELL_TEMPORARY_ELECTRICAL_CHARGE)) me->AddAura(SPELL_TEMPORARY_ELECTRICAL_CHARGE, me); - achiLightningStruck = false; m_bIsChangingStance = false; m_uiChargingStatus = 0; @@ -189,9 +185,6 @@ public: void EnterCombat(Unit* /*who*/) { - if (me->HasAura(SPELL_TEMPORARY_ELECTRICAL_CHARGE)) - achiLightningStruck = true; - DoScriptText(SAY_AGGRO, me); //must get both lieutenants here and make sure they are with him @@ -201,14 +194,6 @@ public: m_instance->SetData(TYPE_BJARNGRIM, IN_PROGRESS); } - uint32 GetData(uint32 type) - { - if (type == DATA_LIGHTNING_STRUCK) - return achiLightningStruck ? 1 : 0; - - return 0; - } - void KilledUnit(Unit* /*victim*/) { DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2, SAY_SLAY_3), me); @@ -463,27 +448,8 @@ public: }; -class achievement_lightning_struck : public AchievementCriteriaScript -{ - public: - achievement_lightning_struck() : AchievementCriteriaScript("achievement_lightning_struck") { } - - bool OnCheck(Player* /*player*/, Unit* target) - { - if (!target) - return false; - - if (Creature* bjarngrim = target->ToCreature()) - if (bjarngrim->AI()->GetData(DATA_LIGHTNING_STRUCK)) - return true; - - return false; - } -}; - void AddSC_boss_bjarngrim() { new boss_bjarngrim(); new mob_stormforged_lieutenant(); - new achievement_lightning_struck(); } -- cgit v1.2.3 From 6cb495048916a916804ebf8bde19e9619b12f897 Mon Sep 17 00:00:00 2001 From: Emo Norfik Date: Sun, 8 Jan 2012 23:07:31 +0000 Subject: Scripts/Utgarde Pinnacle: - Re-write Svala Sorrowgrave - Scripted achievement The Incredible Hulk. This script was writen basing on work and data: - Original TC script. - Albis fix for Arthas sounds and texts https://github.com/TrinityCore/TrinityCore/issues/4002 . - Ric event start fix. - Recorded encounters uploaded on YouTube. - Data found on ScriptDev2 forums. - Iov's custom SD2 repo and Svalas's script https://github.com/Iov/scriptdev2 . Also thx to: - ZxBiohazardZx for pointing how to fix looting problem when boss is killed when flying. - Aokromes for confirmig how many times event "Ritual of the Sword" is performed. - Mini event with Arthas. - Call Flames: timers of cast and time between "Ball of Flame" (48246) can be wrong (based on videos). - Ritual of the Sword works and is performed once at 50% hp but: a) Still need retail data for teleport position of Svala floating above player. b) Need fully fixed spell Ritual of the Sword (48276), the triggering of spell Ritual Strike - Trigger Missile (48331) part was hardcoded. - Spell Paralyze (48278) used by Ritual Channeler: fixed stacking and selection to ritual player only. - Achievement "The Incredible Hulk": works but often Scourge Hulk don't get initial dmg from spell Ritual Strike (spell 48277 Effect #1 Value: 6650 to 7350). - Looting problems when Svala was killed in air (require vmaps and option "vmap.enableHeight = 1" enabled in "worldserver.conf"). - Moved script_texts to creature_text. It require option "vmap.enableHeight = 1" to work properly. --- sql/updates/world/2011_01_08_16_world_misc.sql | 117 ++++ src/server/game/Spells/SpellMgr.cpp | 2 + .../UtgardeKeep/UtgardePinnacle/boss_svala.cpp | 775 ++++++++++++++------- .../UtgardePinnacle/instance_pinnacle.cpp | 9 +- .../UtgardeKeep/UtgardePinnacle/utgarde_pinnacle.h | 2 +- 5 files changed, 667 insertions(+), 238 deletions(-) create mode 100644 sql/updates/world/2011_01_08_16_world_misc.sql (limited to 'src/server/scripts') diff --git a/sql/updates/world/2011_01_08_16_world_misc.sql b/sql/updates/world/2011_01_08_16_world_misc.sql new file mode 100644 index 00000000000..63cd81ff869 --- /dev/null +++ b/sql/updates/world/2011_01_08_16_world_misc.sql @@ -0,0 +1,117 @@ +/* Texts */ + +-- Move text used in Svala Sorrowgrave from script_texts to creature_text +-- Remove old script text for boss_svala.cpp +DELETE FROM `script_texts` WHERE `entry` BETWEEN -1575027 AND -1575015; + +DELETE FROM `creature_text` WHERE `entry` IN (26668,29281); +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +(26668,0,0, 'The sensation is... beyond my imagining. I am yours to command, my king.',14,0,0,0,0,13857, 'Svala Sorrowgrave SAY_DIALOG_WITH_ARTHAS_2'), +(26668,1,0, 'I will be happy to slaughter them in your name! Come, enemies of the Scourge! I will show you the might of the Lich King!',14,0,0,0,0,13858, 'Svala Sorrowgrave SAY_DIALOG_WITH_ARTHAS_3'), +(26668,2,0, 'I will vanquish your soul!',14,0,0,0,0,13842, 'Svala Sorrowgrave SAY_AGGRO'), +(26668,3,0, 'You were a fool to challenge the power of the Lich King!',14,0,0,0,0,13845, 'Svala Sorrowgrave SAY_SLAY_1'), +(26668,3,1, 'Your will is done, my king.',14,0,0,0,0,13847, 'Svala Sorrowgrave SAY_SLAY_2'), +(26668,3,2, 'Another soul for my master.',14,0,0,0,0,13848, 'Svala Sorrowgrave SAY_SLAY_3'), +(26668,4,0, 'Nooo! I did not come this far... to...',14,0,0,0,0,13855, 'Svala Sorrowgrave SAY_DEATH'), +(26668,5,0, 'Your death approaches.',14,0,0,0,0,13850, 'Svala Sorrowgrave SAY_SACRIFICE_1'), +(26668,5,1, 'Go now to my master.',14,0,0,0,0,13851, 'Svala Sorrowgrave SAY_SACRIFICE_2'), +(26668,5,2, 'Your end is inevitable.',14,0,0,0,0,13852, 'Svala Sorrowgrave SAY_SACRIFICE_3'), +(26668,5,3, 'Yor-guul mak!',14,0,0,0,0,13853, 'Svala Sorrowgrave SAY_SACRIFICE_4'), +(26668,5,4, 'Any last words?',14,0,0,0,0,13854, 'Svala Sorrowgrave SAY_SACRIFICE_5'), +(29281,0,0, 'My liege! I have done as you asked, and now beseech you for your blessing!',14,0,0,0,0,13856, 'Svala SAY_DIALOG_WITH_ARTHAS_1'); + +/* Templates */ + +UPDATE `creature_template` SET `unit_flags`=2 WHERE `entry` IN (29281, 30809); -- And this, fixes her flag so script can be started (credit to ric) +UPDATE `creature` SET `spawntimesecs`=86400 WHERE `id`=29281; -- Set Svala's spawn time +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|1 WHERE `entry`=30809; -- Set flags_extra = 1 for Svala hero difficulty +UPDATE `creature_template` SET `InhabitType`=7, `flags_extra`=`flags_extra`|130 WHERE `entry`=30805; -- Set same data on heroic ver to triggers +UPDATE `creature_template` SET `InhabitType`=7, `flags_extra`=`flags_extra`|128 WHERE `entry`=30771; -- Set same data on heroic ver to triggers + +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask` +|1 -- CHARM +|2 -- DISORIENTED +|4 -- DISARM +|8 -- DISTRACT +|16 -- FEAR +|32 -- GRIP +|64 -- ROOT +|128 -- PACIFY +|256 -- SILENCE +|512 -- SLEEP +|1024 -- SNARE +|2048 -- STUN +|4096 -- FREEZE +|8192 -- KNOCKOUT +|65536 -- POLYMORPH +|131072 -- BANISH +|524288 -- SHACKLE +|4194304 -- TURN +|8388608 -- HORROR +|67108864 -- DAZE +|536870912 -- SAPPED +WHERE `entry` IN (29281, 30809, 26668, 30810); + +-- Apply Image of Arthas Visual Effect +DELETE FROM `creature_template_addon` WHERE `entry`=29280; +INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES +(29280, 0, 0, 0, 1, 0, '54134'); + +-- Flame Brazier triggers deletion (will spawn them after activating event 17841 called by spell Call Flames 48258) +DELETE FROM `creature` WHERE `id`=27273 AND `map`=575; +DELETE FROM `creature_addon` WHERE `guid` IN (126121, 126122); + +/* Spells */ + +DELETE FROM `spell_target_position` WHERE `id` IN (48267,48276, 48271, 48274, 48275); +INSERT INTO `spell_target_position` (`id`, `target_map`, `target_position_x`, `target_position_y`, `target_position_z`, `target_orientation`) VALUES +(48267, 575, 296.632, -346.075, 90.5474, 4.60767), -- Svala Ritual - Player teleport position +(48276, 575, 296.651, -346.293, 108.5474, 1.58), -- Svala Ritual - Svala teleport position +(48271, 575, 296.42, -355.01, 90.94, 1.58), -- Summon Ritual Channeler positions +(48274, 575, 302.36, -352.01, 90.54, 2.20), -- Summon Ritual Channeler positions +(48275, 575, 291.39, -352.01, 90.54, 0.91); -- Summon Ritual Channeler positions + +DELETE FROM `conditions` WHERE `SourceEntry` IN (48331,48246,48277) AND `SourceTypeOrReferenceId`=13; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13, 0, 48331, 0, 18, 1, 27327, 0, 0, '', NULL), -- Spell script target for flying sword +(13, 0, 48246, 0, 18, 1, 0, 0, 0, '', NULL), -- Spell script target for Flame Brazier's (on players only) +(13, 0, 48277, 0, 18, 1, 26555, 0, 0, '', NULL), -- Spell script target for Ritual Strike DMG -- Players +(13, 0, 48277, 0, 18, 1, 27327, 0, 0, '', NULL); -- Spell script target for Ritual Strike DMG -- Ritual Target + +/* Achivements */ + +-- The Incredible Hulk achievement 2043 +DELETE FROM `disables` WHERE `sourceType`=4 AND `entry`=7322; +DELETE FROM `achievement_criteria_data` WHERE `criteria_id`=7322 AND `type`=11; +INSERT INTO `achievement_criteria_data` (`criteria_id`, `type`, `value1`, `value2`, `ScriptName`) VALUES +(7322, 11, 0, 0, 'achievement_incredible_hulk'); + +/* AI */ + +DELETE FROM `creature_ai_scripts` WHERE `creature_id`=26555; -- Scourge Hulk +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`=27273; -- Flame Brazier + +-- Add Send Script Event (17841) summon 3 triggers +DELETE FROM `event_scripts` WHERE `id`=17841; +INSERT INTO `event_scripts` (`id`, `delay`, `command`, `datalong`, `datalong2`, `dataint`, `x`, `y`, `z`, `o`) VALUES +(17841, 0, 10, 27273, 10000, 0, 285.6, -357.5, 91.0833, 5.75959), +(17841, 3, 10, 27273, 10000, 0, 307, -357.5, 91.0833, 6.02139), +(17841, 6, 10, 27273, 10000, 0, 285.6, -357.5, 91.0833, 5.75959); + +-- SmartAI script Flame Brazier's cast Ball of Flame (48246) on random player +DELETE FROM `smart_scripts` WHERE `entryorguid`=27273 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 +(27273, 0, 0, 0, 1, 0, 100, 1, 100, 100, 100, 100, 11, 48246, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Flame Brazier - Ball of Flame'); + +/* Script names */ + +UPDATE `creature_template` SET `AIName`='', `ScriptName`='npc_scourge_hulk' WHERE `entry`=26555; +UPDATE `creature_template` SET `ScriptName`='' WHERE `entry`=26668; -- "boss_svala_sorrowgrave" script is now merged with "boss_svala" script +UPDATE `creature_template` SET `ScriptName`='npc_spectator' WHERE `entry`=26667; -- Spectators escape script +UPDATE `creature_template` SET `ScriptName`='npc_ritual_channeler' WHERE `entry`=27281; -- Change 'mob_ritual_channeler' to 'npc_ritual_channeler' + +-- Paralyze -- Filter targets -- cast only on sacrafacing target +DELETE FROM `spell_script_names` WHERE `spell_id`=48278; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(48278, 'spell_paralyze_pinnacle'); + diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index e57cbf4a390..f3d5697c672 100755 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3041,6 +3041,7 @@ void SpellMgr::LoadDbcDataCorrections() case 42611: // Shoot case 61588: // Blazing Harpoon case 52479: // Gift of the Harvester + case 48246: // Ball of Flame spellInfo->MaxAffectedTargets = 1; break; case 41376: // Spite @@ -3383,6 +3384,7 @@ void SpellMgr::LoadDbcDataCorrections() spellInfo->AreaGroupId = 0; // originally, these require area 4522, which is... outside of Icecrown Citadel break; case 70602: // Corruption + case 48278: // Paralyze spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; break; case 70715: // Column of Frost (visual marker) diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp index 01cd36266d0..7280c3d5b82 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp @@ -20,66 +20,93 @@ enum Spells { - SPELL_CALL_FLAMES = 48258, - SPELL_RITUAL_OF_THE_SWORD = 48276, //Effect #1 Teleport, Effect #2 Dummy + SPELL_SVALA_TRANSFORMING1 = 54140, + SPELL_SVALA_TRANSFORMING2 = 54205, + SPELL_TRANSFORMING_CHANNEL = 54142, + + SPELL_CALL_FLAMES = 48258, // caster effect only, triggers event 17841 SPELL_SINSTER_STRIKE = 15667, H_SPELL_SINSTER_STRIKE = 59409, - SPELL_SVALA_TRANSFORMING1 = 54140, - SPELL_SVALA_TRANSFORMING2 = 54205 + + SPELL_RITUAL_PREPARATION = 48267, + SPELL_RITUAL_OF_THE_SWORD = 48276, + SPELL_RITUAL_STRIKE_TRIGGER = 48331, // triggers 48277 & 59930, needs NPC_RITUAL_TARGET as spell_script_target + SPELL_RITUAL_DISARM = 54159, + SPELL_RITUAL_STRIKE_EFF_1 = 48277, + SPELL_RITUAL_STRIKE_EFF_2 = 59930, + + SPELL_SUMMONED_VIS = 64446, + SPELL_RITUAL_CHANNELER_1 = 48271, + SPELL_RITUAL_CHANNELER_2 = 48274, + SPELL_RITUAL_CHANNELER_3 = 48275, + + // Ritual Channeler spells + SPELL_PARALYZE = 48278, + SPELL_SHADOWS_IN_THE_DARK = 59407, + + // Scourge Hulk spells + SPELL_MIGHTY_BLOW = 48697, + SPELL_VOLATILE_INFECTION = 56785, + H_SPELL_VOLATILE_INFECTION = 59228 }; -//not in db + enum Yells { - SAY_DIALOG_WITH_ARTHAS_1 = -1575015, - SAY_DIALOG_WITH_ARTHAS_2 = -1575016, - SAY_DIALOG_WITH_ARTHAS_3 = -1575017, - SAY_AGGRO = -1575018, - SAY_SLAY_1 = -1575019, - SAY_SLAY_2 = -1575020, - SAY_SLAY_3 = -1575021, - SAY_DEATH = -1575022, - SAY_SACRIFICE_PLAYER_1 = -1575023, - SAY_SACRIFICE_PLAYER_2 = -1575024, - SAY_SACRIFICE_PLAYER_3 = -1575025, - SAY_SACRIFICE_PLAYER_4 = -1575026, - SAY_SACRIFICE_PLAYER_5 = -1575027, - SAY_DIALOG_OF_ARTHAS_1 = -1575028, - SAY_DIALOG_OF_ARTHAS_2 = -1575029 + // Svala + SAY_SVALA_INTRO_0 = 0, + + // Svala Sorrowgrave + SAY_SVALA_INTRO_1 = 0, + SAY_SVALA_INTRO_2 = 1, + SAY_AGGRO = 2, + SAY_SLAY = 3, + SAY_DEATH = 4, + SAY_SACRIFICE_PLAYER = 5, + + // Image of Arthas + SAY_DIALOG_OF_ARTHAS_1 = 0, + SAY_DIALOG_OF_ARTHAS_2 = 1 }; + enum Creatures { CREATURE_ARTHAS = 29280, // Image of Arthas CREATURE_SVALA_SORROWGRAVE = 26668, // Svala after transformation CREATURE_SVALA = 29281, // Svala before transformation - CREATURE_RITUAL_CHANNELER = 27281 + CREATURE_RITUAL_CHANNELER = 27281, + CREATURE_SPECTATOR = 26667, + CREATURE_RITUAL_TARGET = 27327, + CREATURE_FLAME_BRAZIER = 27273, + CREATURE_SCOURGE_HULK = 26555 }; -enum ChannelerSpells -{ - //ritual channeler's spells - SPELL_PARALYZE = 48278, - SPELL_SHADOWS_IN_THE_DARK = 59407 -}; -enum Misc + +enum Objects { - DATA_SVALA_DISPLAY_ID = 25944 + OBJECT_UTGARDE_MIRROR = 191745 }; -enum IntroPhase + +enum SvalaPhase { IDLE, INTRO, - FINISHED + NORMAL, + SACRIFICING, + SVALADEAD }; -enum CombatPhase + +#define DATA_INCREDIBLE_HULK 2043 + +static const float spectatorWP[2][3] = { - NORMAL, - SACRIFICING + {296.95f,-312.76f,86.36f}, + {297.69f,-275.81f,86.36f} }; static Position RitualChannelerPos[]= { - {296.42f, -355.01f, 90.94f, 0.0f}, - {302.36f, -352.01f, 90.54f, 0.0f}, - {291.39f, -350.89f, 90.54f, 0.0f} + {296.42f, -355.01f, 90.94f, 1.58f}, + {302.36f, -352.01f, 90.54f, 2.20f}, + {291.39f, -352.01f, 90.54f, 0.91f} }; static Position ArthasPos = { 295.81f, -366.16f, 92.57f, 1.58f }; static Position SvalaPos = { 296.632f, -346.075f, 90.6307f, 1.58f }; @@ -96,31 +123,96 @@ public: struct boss_svalaAI : public ScriptedAI { - boss_svalaAI(Creature* c) : ScriptedAI(c) + boss_svalaAI(Creature* creature) : ScriptedAI(creature), summons(creature) { - instance = c->GetInstanceScript(); + instance = creature->GetInstanceScript(); + Phase = IDLE; + + me->ApplySpellImmune(0, IMMUNITY_ID, SPELL_RITUAL_STRIKE_EFF_1, true); + me->ApplySpellImmune(0, IMMUNITY_ID, SPELL_RITUAL_STRIKE_EFF_2, true); } - uint32 uiIntroTimer; + InstanceScript* instance; + SummonList summons; + SvalaPhase Phase; + + Position pos; + float x, y, z; - uint8 uiIntroPhase; + uint32 introTimer; + uint8 introPhase; + uint8 sacrePhase; - IntroPhase Phase; + TempSummon* arthas; + uint64 arthasGUID; - TempSummon* pArthas; - uint64 uiArthasGUID; + uint32 sinsterStrikeTimer; + uint32 callFlamesTimer; + uint32 sacrificeTimer; - InstanceScript* instance; + bool sacrificed; void Reset() { - Phase = IDLE; - uiIntroTimer = 1 * IN_MILLISECONDS; - uiIntroPhase = 0; - uiArthasGUID = 0; + sacrificed = false; + SetCombatMovement(true); + + summons.DespawnAll(); + me->RemoveAllAuras(); + + if (Phase > INTRO) + { + me->SetFlying(true); + me->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + } + + if (Phase > NORMAL) + Phase = NORMAL; + + introTimer = 1 * IN_MILLISECONDS; + introPhase = 0; + arthasGUID = 0; if (instance) + { instance->SetData(DATA_SVALA_SORROWGRAVE_EVENT, NOT_STARTED); + instance->SetData64(DATA_SACRIFICED_PLAYER, 0); + } + } + + void JustReachedHome() + { + if (Phase > INTRO) + { + me->SetFlying(false); + me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + me->SetOrientation(1.58f); + me->SendMovementFlagUpdate(); + } + } + + void EnterCombat(Unit* /*who*/) + { + Talk(SAY_AGGRO); + + sinsterStrikeTimer = 7 * IN_MILLISECONDS; + callFlamesTimer = urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS); + + if (instance) + instance->SetData(DATA_SVALA_SORROWGRAVE_EVENT, IN_PROGRESS); + } + + void JustSummoned(Creature* summon) + { + if (summon->GetEntry() == CREATURE_RITUAL_CHANNELER) + summon->CastSpell(summon, SPELL_SUMMONED_VIS, true); + + summons.Summon(summon); + } + + void SummonedCreatureDespawn(Creature* summon) + { + summons.Despawn(summon); } void MoveInLineOfSight(Unit* who) @@ -132,287 +224,500 @@ public: { Phase = INTRO; me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + if (GameObject* mirror = GetClosestGameObjectWithEntry(me, OBJECT_UTGARDE_MIRROR, 100.0f)) + mirror->SetGoState(GO_STATE_READY); - if (Creature* pArthas = me->SummonCreature(CREATURE_ARTHAS, ArthasPos, TEMPSUMMON_MANUAL_DESPAWN)) + if (Creature* arthas = me->SummonCreature(CREATURE_ARTHAS, ArthasPos, TEMPSUMMON_MANUAL_DESPAWN)) { - pArthas->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - uiArthasGUID = pArthas->GetGUID(); + arthas->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + arthasGUID = arthas->GetGUID(); } } } + + void KilledUnit(Unit* victim) + { + if (victim != me) + Talk(SAY_SLAY); + } + + void DamageTaken(Unit* attacker, uint32 &damage) + { + if (Phase == SVALADEAD) + { + if (attacker != me) + damage = 0; + return; + } - void AttackStart(Unit* /*who*/) {} + if (damage >= me->GetHealth()) + { + if (Phase == SACRIFICING) + SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + + me->GetPosition(x, y, z); + z = me->GetMap()->GetHeight(x, y, z, true, 50); + + if (me->GetPositionZ() > z) + { + damage = 0; + Phase = SVALADEAD; + me->InterruptNonMeleeSpells(true); + me->RemoveAllAuras(); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->SetHealth(1); + + SetCombatMovement(false); + me->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH); + me->GetMotionMaster()->MoveFall(z, 1); + } + } + } + + void MovementInform(uint32 motionType, uint32 pointId) + { + if (motionType != POINT_MOTION_TYPE) + return; + + if (pointId == 1) + { + me->Relocate(x, y, z, me->GetOrientation()); + me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + } + + void JustDied(Unit* killer) + { + summons.DespawnAll(); + + if (instance) + instance->SetData(DATA_SVALA_SORROWGRAVE_EVENT, DONE); + + Talk(SAY_DEATH); + } + + void SpellHitTarget(Unit* target, const SpellInfo* spell) + { + if (spell->Id == SPELL_RITUAL_STRIKE_EFF_1 && Phase != NORMAL && Phase != SVALADEAD) + { + Phase = NORMAL; + SetCombatMovement(true); + + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 300, true)) + me->GetMotionMaster()->MoveChase(target); + } + } void UpdateAI(const uint32 diff) { - if (Phase != INTRO) + if (Phase == IDLE) + return; + + if (Phase == INTRO) + { + if (introTimer <= diff) + { + Creature* arthas = Unit::GetCreature(*me, arthasGUID); + if (!arthas) + return; + + switch (introPhase) + { + case 0: + Talk(SAY_SVALA_INTRO_0); + ++introPhase; + introTimer = 8100; + break; + case 1: + arthas->AI()->Talk(SAY_DIALOG_OF_ARTHAS_1); + ++introPhase; + introTimer = 10000; + break; + case 2: + arthas->CastSpell(me, SPELL_TRANSFORMING_CHANNEL, false); + me->SetFlying(true); + me->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + pos.Relocate(me); + pos.m_positionZ += 8.0f; + me->GetMotionMaster()->MoveTakeoff(0, pos, 3.30078125f); + // spectators flee event + if (instance) + { + std::list lspectatorList; + GetCreatureListWithEntryInGrid(lspectatorList, me, CREATURE_SPECTATOR, 100.0f); + for(std::list::iterator itr = lspectatorList.begin(); itr != lspectatorList.end(); ++itr) + { + if ((*itr)->isAlive()) + { + (*itr)->SetStandState(UNIT_STAND_STATE_STAND); + (*itr)->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); + (*itr)->GetMotionMaster()->MovePoint(1, spectatorWP[0][0], spectatorWP[0][1], spectatorWP[0][2]); + } + } + } + ++introPhase; + introTimer = 4200; + break; + case 3: + me->CastSpell(me, SPELL_SVALA_TRANSFORMING1, false); + ++introPhase; + introTimer = 6200; + break; + case 4: + me->CastSpell(me, SPELL_SVALA_TRANSFORMING2, false); + arthas->InterruptNonMeleeSpells(true); + me->RemoveAllAuras(); + me->UpdateEntry(CREATURE_SVALA_SORROWGRAVE); + me->SetFacingToObject(arthas); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + ++introPhase; + introTimer = 3200; + break; + case 5: + Talk(SAY_SVALA_INTRO_1); + ++introPhase; + introTimer = 10000; + break; + case 6: + arthas->AI()->Talk(SAY_DIALOG_OF_ARTHAS_2); + ++introPhase; + introTimer = 7200; + break; + case 7: + Talk(SAY_SVALA_INTRO_2); + me->SetOrientation(1.58f); + me->SendMovementFlagUpdate(); + arthas->SetVisible(false); + ++introPhase; + introTimer = 13800; + break; + case 8: + me->SetFlying(false); + me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + me->SendMovementFlagUpdate(); + pos.Relocate(me); + pos.m_positionX = me->GetHomePosition().GetPositionX(); + pos.m_positionY = me->GetHomePosition().GetPositionY(); + pos.m_positionZ = 90.6065f; + me->GetMotionMaster()->MoveLand(0, pos, 6.247422f); + ++introPhase; + introTimer = 3000; + break; + case 9: + if (GameObject* mirror = GetClosestGameObjectWithEntry(me, OBJECT_UTGARDE_MIRROR, 100.0f)) + mirror->SetGoState(GO_STATE_ACTIVE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + arthas->DespawnOrUnsummon(); + arthasGUID = 0; + Phase = NORMAL; + break; + } + } else introTimer -= diff; + return; + } - if (uiIntroTimer <= diff) + if (Phase == NORMAL) { - Creature* pArthas = Unit::GetCreature(*me, uiArthasGUID); - if (!pArthas) + //Return since we have no target + if (!UpdateVictim()) return; - switch (uiIntroPhase) + if (me->IsWithinMeleeRange(me->getVictim()) && me->HasUnitMovementFlag(MOVEMENTFLAG_LEVITATING)) { - case 0: - DoScriptText(SAY_DIALOG_WITH_ARTHAS_1, me); - ++uiIntroPhase; - uiIntroTimer = 3500; - break; - case 1: - DoScriptText(SAY_DIALOG_OF_ARTHAS_1, pArthas); - ++uiIntroPhase; - uiIntroTimer = 3500; - break; - case 2: - DoScriptText(SAY_DIALOG_WITH_ARTHAS_2, me); - ++uiIntroPhase; - uiIntroTimer = 3500; - break; - case 3: - DoScriptText(SAY_DIALOG_OF_ARTHAS_2, pArthas); - ++uiIntroPhase; - uiIntroTimer = 3500; - break; - case 4: - DoScriptText(SAY_DIALOG_WITH_ARTHAS_3, me); - DoCast(me, SPELL_SVALA_TRANSFORMING1); - ++uiIntroPhase; - uiIntroTimer = 2800; - break; - case 5: - DoCast(me, SPELL_SVALA_TRANSFORMING2); - ++uiIntroPhase; - uiIntroTimer = 200; - break; - case 6: - if (me->SummonCreature(CREATURE_SVALA_SORROWGRAVE, SvalaPos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60*IN_MILLISECONDS)) + me->SetFlying(false); + me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + me->SendMovementFlagUpdate(); + } + + if (sinsterStrikeTimer <= diff) + { + DoCast(me->getVictim(), SPELL_SINSTER_STRIKE); + sinsterStrikeTimer = urand(5 * IN_MILLISECONDS, 9 * IN_MILLISECONDS); + } else sinsterStrikeTimer -= diff; + + if (callFlamesTimer <= diff) + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + { + DoCast(target, SPELL_CALL_FLAMES); + callFlamesTimer = urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS); + } + } else callFlamesTimer -= diff; + + if (!sacrificed) + { + if (HealthBelowPct(50)) + { + if (Unit* sacrificeTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 80, true)) { - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - me->SetDisplayId(DATA_SVALA_DISPLAY_ID); - pArthas->DespawnOrUnsummon(); - uiArthasGUID = 0; - Phase = FINISHED; + if (instance) + instance->SetData64(DATA_SACRIFICED_PLAYER, sacrificeTarget->GetGUID()); + + Talk(SAY_SACRIFICE_PLAYER); + + DoCast(sacrificeTarget, SPELL_RITUAL_PREPARATION); + + SetCombatMovement(false); + me->SetFlying(true); + me->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + + Phase = SACRIFICING; + sacrePhase = 0; + sacrificeTimer = 1 * IN_MILLISECONDS; + + DoCast(me, SPELL_RITUAL_OF_THE_SWORD); + sacrificed = true; } - else - Reset(); - break; + } } - } else uiIntroTimer -= diff; + + DoMeleeAttackIfReady(); + } + else //SACRIFICING + { + if (sacrificeTimer <= diff) + { + switch (sacrePhase) + { + case 0: + // spawn ritual channelers + if (instance) + { + DoCast(me, SPELL_RITUAL_CHANNELER_1, true); + DoCast(me, SPELL_RITUAL_CHANNELER_2, true); + DoCast(me, SPELL_RITUAL_CHANNELER_3, true); + } + ++sacrePhase; + sacrificeTimer = 2 * IN_MILLISECONDS; + break; + case 1: + me->StopMoving(); + me->GetMotionMaster()->MoveIdle(); + me->InterruptNonMeleeSpells(true); + DoCast(me, SPELL_RITUAL_STRIKE_TRIGGER, true); + ++sacrePhase; + sacrificeTimer = 200; + break; + case 2: + DoCast(me, SPELL_RITUAL_DISARM); + ++sacrePhase; + break; + case 3: + break; + } + } + else sacrificeTimer -= diff; + } } }; }; -class mob_ritual_channeler : public CreatureScript +class npc_ritual_channeler : public CreatureScript { public: - mob_ritual_channeler() : CreatureScript("mob_ritual_channeler") { } + npc_ritual_channeler() : CreatureScript("npc_ritual_channeler") { } CreatureAI* GetAI(Creature* creature) const { - return new mob_ritual_channelerAI(creature); + return new npc_ritual_channelerAI(creature); } - struct mob_ritual_channelerAI : public Scripted_NoMovementAI + struct npc_ritual_channelerAI : public Scripted_NoMovementAI { - mob_ritual_channelerAI(Creature* c) :Scripted_NoMovementAI(c) + npc_ritual_channelerAI(Creature* c) :Scripted_NoMovementAI(c) { instance = c->GetInstanceScript(); } InstanceScript* instance; + uint32 paralyzeTimer; void Reset() { - DoCast(me, SPELL_SHADOWS_IN_THE_DARK); - } - - // called by svala sorrowgrave to set guid of victim - void DoAction(const int32 /*action*/) - { + paralyzeTimer = 1600; if (instance) - if (Unit* victim = me->GetUnit(*me, instance->GetData64(DATA_SACRIFICED_PLAYER))) - DoCast(victim, SPELL_PARALYZE); + if (IsHeroic()) + DoCast(me, SPELL_SHADOWS_IN_THE_DARK); } - - void EnterCombat(Unit* /*who*/) + + void UpdateAI(const uint32 diff) { + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + if (paralyzeTimer <= diff) + { + if (instance) + if (Unit* victim = me->GetUnit(*me, instance->GetData64(DATA_SACRIFICED_PLAYER))) + DoCast(victim, SPELL_PARALYZE, false); + + paralyzeTimer = 200; + } + else + paralyzeTimer -= diff; } }; - }; -class boss_svala_sorrowgrave : public CreatureScript +class npc_spectator : public CreatureScript { public: - boss_svala_sorrowgrave() : CreatureScript("boss_svala_sorrowgrave") { } + npc_spectator() : CreatureScript("npc_spectator") { } CreatureAI* GetAI(Creature* creature) const { - return new boss_svala_sorrowgraveAI(creature); + return new npc_spectatorAI(creature); } - struct boss_svala_sorrowgraveAI : public ScriptedAI + struct npc_spectatorAI : public ScriptedAI { - boss_svala_sorrowgraveAI(Creature* c) : ScriptedAI(c), summons(c) + npc_spectatorAI(Creature* c) : ScriptedAI(c) { } + + void Reset() { } + + void MovementInform(uint32 motionType, uint32 pointId) { - instance = c->GetInstanceScript(); + if (motionType == POINT_MOTION_TYPE) + { + if (pointId == 1) + me->GetMotionMaster()->MovePoint(2,spectatorWP[1][0],spectatorWP[1][1],spectatorWP[1][2]); + else if (pointId == 2) + me->DespawnOrUnsummon(1000); + } } + }; +}; - uint32 uiSinsterStrikeTimer; - uint32 uiCallFlamesTimer; - uint32 uiRitualOfSwordTimer; - uint32 uiSacrificeTimer; +class checkRitualTarget +{ + public: + explicit checkRitualTarget(Unit* _caster) : caster(_caster) { } - CombatPhase Phase; + bool operator() (Unit* unit) + { + if (InstanceScript* instance = caster->GetInstanceScript()) + if (instance->GetData64(DATA_SACRIFICED_PLAYER) == unit->GetGUID()) + return false; - SummonList summons; + return true; + } - bool bSacrificed; + private: + Unit* caster; +}; - InstanceScript* instance; +class spell_paralyze_pinnacle : public SpellScriptLoader +{ + public: + spell_paralyze_pinnacle() : SpellScriptLoader("spell_paralyze_pinnacle") { } - void Reset() + class spell_paralyze_pinnacle_SpellScript : public SpellScript { - uiSinsterStrikeTimer = 7 * IN_MILLISECONDS; - uiCallFlamesTimer = 10 * IN_MILLISECONDS; - uiRitualOfSwordTimer = 20 * IN_MILLISECONDS; - uiSacrificeTimer = 8 * IN_MILLISECONDS; - - bSacrificed = false; - - Phase = NORMAL; - - DoTeleportTo(296.632f, -346.075f, 90.6307f); - me->SetUnitMovementFlags(MOVEMENTFLAG_WALKING); + PrepareSpellScript(spell_paralyze_pinnacle_SpellScript); - summons.DespawnAll(); + void FilterTargets(std::list& unitList) + { + unitList.remove_if(checkRitualTarget(GetCaster())); + } - if (instance) + void Register() { - instance->SetData(DATA_SVALA_SORROWGRAVE_EVENT, NOT_STARTED); - instance->SetData64(DATA_SACRIFICED_PLAYER, 0); + OnUnitTargetSelect += SpellUnitTargetFn(spell_paralyze_pinnacle_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); } - } + }; - void EnterCombat(Unit* /*who*/) + SpellScript* GetSpellScript() const { - DoScriptText(SAY_AGGRO, me); - - if (instance) - instance->SetData(DATA_SVALA_SORROWGRAVE_EVENT, IN_PROGRESS); + return new spell_paralyze_pinnacle_SpellScript(); } +}; - void JustSummoned(Creature* summon) - { - summons.Summon(summon); - } +class npc_scourge_hulk : public CreatureScript +{ + public: + npc_scourge_hulk() : CreatureScript("npc_scourge_hulk") { } - void SummonedCreatureDespawn(Creature* summon) + struct npc_scourge_hulkAI : public ScriptedAI { - summons.Despawn(summon); - } + npc_scourge_hulkAI(Creature* creature) : ScriptedAI(creature) { } - void UpdateAI(const uint32 diff) - { - if (Phase == NORMAL) + uint32 mightyBlow; + uint32 volatileInfection; + + void Reset() + { + mightyBlow = urand(4000, 9000); + volatileInfection = urand(10000, 14000); + killedByRitualStrike = false; + } + + uint32 GetData(uint32 type) + { + return type == DATA_INCREDIBLE_HULK ? killedByRitualStrike : 0; + } + + void DamageTaken(Unit* attacker, uint32 &damage) + { + if (damage >= me->GetHealth() && attacker->GetEntry() == CREATURE_SVALA_SORROWGRAVE) + killedByRitualStrike = true; + } + + void UpdateAI(uint32 const diff) { - //Return since we have no target if (!UpdateVictim()) return; - if (uiSinsterStrikeTimer <= diff) - { - DoCast(me->getVictim(), SPELL_SINSTER_STRIKE); - uiSinsterStrikeTimer = urand(5 * IN_MILLISECONDS, 9 * IN_MILLISECONDS); - } else uiSinsterStrikeTimer -= diff; - - if (uiCallFlamesTimer <= diff) + if (mightyBlow <= diff) { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) - { - DoCast(target, SPELL_CALL_FLAMES); - uiCallFlamesTimer = urand(8 * IN_MILLISECONDS, 12 * IN_MILLISECONDS); - } - } else uiCallFlamesTimer -= diff; + if (Unit* victim = me->getVictim()) + if (!victim->HasUnitState(UNIT_STAT_STUNNED)) // Prevent knocking back a ritual player + DoCast(victim, SPELL_MIGHTY_BLOW); + mightyBlow = urand(12000, 17000); + } + else + mightyBlow -= diff; - if (!bSacrificed) + if (volatileInfection <= diff) { - if (uiRitualOfSwordTimer <= diff) - { - if (Unit* pSacrificeTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) - { - DoScriptText(RAND(SAY_SACRIFICE_PLAYER_1, SAY_SACRIFICE_PLAYER_2, SAY_SACRIFICE_PLAYER_3, SAY_SACRIFICE_PLAYER_4, SAY_SACRIFICE_PLAYER_5), me); - DoCast(pSacrificeTarget, SPELL_RITUAL_OF_THE_SWORD); - //Spell doesn't teleport - DoTeleportPlayer(pSacrificeTarget, 296.632f, -346.075f, 90.63f, 4.6f); - me->SetUnitMovementFlags(MOVEMENTFLAG_CAN_FLY); - DoTeleportTo(296.632f, -346.075f, 120.85f); - Phase = SACRIFICING; - if (instance) - { - instance->SetData64(DATA_SACRIFICED_PLAYER, pSacrificeTarget->GetGUID()); - - for (uint8 i = 0; i < 3; ++i) - if (Creature* summon = me->SummonCreature(CREATURE_RITUAL_CHANNELER, RitualChannelerPos[i], TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 360000)) - summon->AI()->DoAction(0); - } - - bSacrificed = true; - } - } else uiRitualOfSwordTimer -= diff; + DoCastVictim(SPELL_VOLATILE_INFECTION); + volatileInfection = urand(13000, 17000); } + else + volatileInfection -= diff; DoMeleeAttackIfReady(); } - else //SACRIFICING - { - if (uiSacrificeTimer <= diff) - { - Unit* pSacrificeTarget = instance ? Unit::GetUnit(*me, instance->GetData64(DATA_SACRIFICED_PLAYER)) : NULL; - if (instance && !summons.empty() && pSacrificeTarget && pSacrificeTarget->isAlive()) - me->Kill(pSacrificeTarget, false); // durability damage? - - //go down - Phase = NORMAL; - pSacrificeTarget = NULL; - me->SetUnitMovementFlags(MOVEMENTFLAG_WALKING); - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) - me->GetMotionMaster()->MoveChase(target); - uiSacrificeTimer = 8 * IN_MILLISECONDS; - } - else uiSacrificeTimer -= diff; - } - } + private: + bool killedByRitualStrike; + }; - void KilledUnit(Unit* /*victim*/) + CreatureAI* GetAI(Creature* creature) const { - DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2, SAY_SLAY_3), me); + return new npc_scourge_hulkAI(creature); } +}; - void JustDied(Unit* killer) - { - if (instance) - { - Creature* pSvala = Unit::GetCreature((*me), instance->GetData64(DATA_SVALA)); - if (pSvala && pSvala->isAlive()) - killer->Kill(pSvala); +class achievement_incredible_hulk : public AchievementCriteriaScript +{ + public: + achievement_incredible_hulk() : AchievementCriteriaScript("achievement_incredible_hulk") { } - instance->SetData(DATA_SVALA_SORROWGRAVE_EVENT, DONE); - } - DoScriptText(SAY_DEATH, me); + bool OnCheck(Player* /*player*/, Unit* target) + { + return target && target->IsAIEnabled && target->GetAI()->GetData(DATA_INCREDIBLE_HULK); } - }; - }; void AddSC_boss_svala() { new boss_svala(); - new mob_ritual_channeler(); - new boss_svala_sorrowgrave(); + new npc_ritual_channeler(); + new npc_spectator(); + new spell_paralyze_pinnacle(); + new npc_scourge_hulk(); + new achievement_incredible_hulk(); } diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_pinnacle.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_pinnacle.cpp index c5bc235da1f..cb596f284c5 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_pinnacle.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_pinnacle.cpp @@ -170,8 +170,12 @@ public: void SetData64(uint32 type, uint64 data) { - if (type == DATA_SACRIFICED_PLAYER) - uiSacrificedPlayer = data; + switch (type) + { + case DATA_SACRIFICED_PLAYER: + uiSacrificedPlayer = data; + break; + } } uint32 GetData(uint32 type) @@ -201,6 +205,7 @@ public: case DATA_MOB_ORB: return uiPalehoofOrb; case DATA_SVALA: return uiSvala; case DATA_GORTOK_PALEHOOF_SPHERE: return uiGortokPalehoofSphere; + case DATA_SACRIFICED_PLAYER: return uiSacrificedPlayer; } return 0; diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/utgarde_pinnacle.h b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/utgarde_pinnacle.h index 7d10483ca1d..872314ee25e 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/utgarde_pinnacle.h +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/utgarde_pinnacle.h @@ -53,7 +53,7 @@ enum eCreatures MOB_MASSIVE_JORMUNGAR = 26685, MOB_FEROCIOUS_RHINO = 26686, MOB_SVALA = 29281, - MOB_PALEHOOF_ORB = 26688, + MOB_PALEHOOF_ORB = 26688 }; #endif -- cgit v1.2.3 From f850baeb30e2532d2fb52fbd49368f313b73fe04 Mon Sep 17 00:00:00 2001 From: kaelima Date: Mon, 9 Jan 2012 10:07:46 +0100 Subject: Script/Naxxramas: Fixed "A Spore Loser", texts and timers for Loatheb encounter. Creds to Warpten, thanks. --- ...12_01_09_00_world_achievement_criteria_data.sql | 5 + .../world/2012_01_09_00_world_creature_text.sql | 5 + .../2012_01_09_00_world_spell_script_names.sql | 3 + .../scripts/Northrend/Naxxramas/boss_loatheb.cpp | 204 ++++++++++++++++----- 4 files changed, 168 insertions(+), 49 deletions(-) create mode 100644 sql/updates/world/2012_01_09_00_world_achievement_criteria_data.sql create mode 100644 sql/updates/world/2012_01_09_00_world_creature_text.sql create mode 100644 sql/updates/world/2012_01_09_00_world_spell_script_names.sql (limited to 'src/server/scripts') diff --git a/sql/updates/world/2012_01_09_00_world_achievement_criteria_data.sql b/sql/updates/world/2012_01_09_00_world_achievement_criteria_data.sql new file mode 100644 index 00000000000..6c2bcc86d03 --- /dev/null +++ b/sql/updates/world/2012_01_09_00_world_achievement_criteria_data.sql @@ -0,0 +1,5 @@ +DELETE FROM `disables` WHERE `sourceType`=4 AND `entry` IN (7612,7613); +DELETE FROM `achievement_criteria_data` WHERE `criteria_id` IN (7612,7613); +INSERT INTO `achievement_criteria_data` (`criteria_id`,`type`,`value1`,`value2`,`ScriptName`) VALUES +(7612,11,0,0, 'achievement_spore_loser'), +(7613,11,0,0, 'achievement_spore_loser'); diff --git a/sql/updates/world/2012_01_09_00_world_creature_text.sql b/sql/updates/world/2012_01_09_00_world_creature_text.sql new file mode 100644 index 00000000000..2a70be00b12 --- /dev/null +++ b/sql/updates/world/2012_01_09_00_world_creature_text.sql @@ -0,0 +1,5 @@ +DELETE FROM `creature_text` WHERE `entry`=16011; +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +(16011,0,0, 'An aura of necrotic energy blocks all healing!',41,0,100,0,0,0, 'Loatheb'), +(16011,1,0, 'The aura fades away, allowing for healing once more!',41,0,100,0,0,0, 'Loatheb'), +(16011,2,0, 'The aura''s power begins to wane!',41,0,100,0,0,0, 'Loatheb'); diff --git a/sql/updates/world/2012_01_09_00_world_spell_script_names.sql b/sql/updates/world/2012_01_09_00_world_spell_script_names.sql new file mode 100644 index 00000000000..7279fc54413 --- /dev/null +++ b/sql/updates/world/2012_01_09_00_world_spell_script_names.sql @@ -0,0 +1,3 @@ +DELETE FROM `spell_script_names` WHERE `spell_id`=59481; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(59481, 'spell_loatheb_necrotic_aura_warning'); diff --git a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp index 4c2348d30c9..502c841540a 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp @@ -20,79 +20,185 @@ enum Spells { - SPELL_NECROTIC_AURA = 55593, - SPELL_SUMMON_SPORE = 29234, - SPELL_DEATHBLOOM = 29865, - H_SPELL_DEATHBLOOM = 55053, - SPELL_INEVITABLE_DOOM = 29204, - H_SPELL_INEVITABLE_DOOM = 55052 + SPELL_NECROTIC_AURA = 55593, + SPELL_WARN_NECROTIC_AURA = 59481, + SPELL_SUMMON_SPORE = 29234, + SPELL_DEATHBLOOM = 29865, + H_SPELL_DEATHBLOOM = 55053, + SPELL_INEVITABLE_DOOM = 29204, + H_SPELL_INEVITABLE_DOOM = 55052 +}; + +enum Texts +{ + SAY_NECROTIC_AURA_APPLIED = 0, + SAY_NECROTIC_AURA_REMOVED = 1, + SAY_NECROTIC_AURA_FADING = 2, }; enum Events { - EVENT_NONE, - EVENT_AURA, - EVENT_BLOOM, - EVENT_DOOM, + EVENT_NECROTIC_AURA = 1, + EVENT_DEATHBLOOM = 2, + EVENT_INEVITABLE_DOOM = 3, + EVENT_SPORE = 4, + EVENT_NECROTIC_AURA_FADING = 5, +}; + +enum Achievement +{ + DATA_ACHIEVEMENT_SPORE_LOSER = 21822183, }; class boss_loatheb : public CreatureScript { -public: - boss_loatheb() : CreatureScript("boss_loatheb") { } + public: + boss_loatheb() : CreatureScript("boss_loatheb") { } - CreatureAI* GetAI(Creature* creature) const - { - return new boss_loathebAI (creature); - } + struct boss_loathebAI : public BossAI + { + boss_loathebAI(Creature* creature) : BossAI(creature, BOSS_LOATHEB) + { + } - struct boss_loathebAI : public BossAI - { - boss_loathebAI(Creature* c) : BossAI(c, BOSS_LOATHEB) {} + void Reset() + { + _Reset(); + _doomCounter = 0; + _sporeLoserData = true; + } - void EnterCombat(Unit* /*who*/) - { - _EnterCombat(); - events.ScheduleEvent(EVENT_AURA, 10000); - events.ScheduleEvent(EVENT_BLOOM, 5000); - events.ScheduleEvent(EVENT_DOOM, 120000); - } + void EnterCombat(Unit* /*who*/) + { + _EnterCombat(); + events.ScheduleEvent(EVENT_NECROTIC_AURA, 17000); + events.ScheduleEvent(EVENT_DEATHBLOOM, 5000); + events.ScheduleEvent(EVENT_SPORE, IsHeroic() ? 18000 : 36000); + events.ScheduleEvent(EVENT_INEVITABLE_DOOM, 120000); + } - void UpdateAI(const uint32 diff) - { - if (!UpdateVictim()) - return; + void SummonedCreatureDies(Creature* /*summon*/, Unit* /*killer*/) + { + _sporeLoserData = false; + } - events.Update(diff); + uint32 GetData(int32 id) + { + if (id != DATA_ACHIEVEMENT_SPORE_LOSER) + return 0; - while (uint32 eventId = events.ExecuteEvent()) + return uint32(_sporeLoserData); + } + + void UpdateAI(uint32 const diff) { - switch (eventId) + if (!UpdateVictim()) + return; + + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) { - case EVENT_AURA: - DoCastAOE(SPELL_NECROTIC_AURA); - events.ScheduleEvent(EVENT_AURA, 20000); - break; - case EVENT_BLOOM: - // TODO : Add missing text - DoCastAOE(SPELL_SUMMON_SPORE, true); - DoCastAOE(RAID_MODE(SPELL_DEATHBLOOM, H_SPELL_DEATHBLOOM)); - events.ScheduleEvent(EVENT_BLOOM, 30000); - break; - case EVENT_DOOM: - DoCastAOE(RAID_MODE(SPELL_INEVITABLE_DOOM, H_SPELL_INEVITABLE_DOOM)); - events.ScheduleEvent(EVENT_DOOM, events.GetTimer() < 5*60000 ? 30000 : 15000); - break; + switch (eventId) + { + case EVENT_NECROTIC_AURA: + DoCastAOE(SPELL_NECROTIC_AURA); + DoCast(me, SPELL_WARN_NECROTIC_AURA); + events.ScheduleEvent(EVENT_NECROTIC_AURA, 20000); + events.ScheduleEvent(EVENT_NECROTIC_AURA_FADING, 14000); + break; + case EVENT_DEATHBLOOM: + DoCastAOE(RAID_MODE(SPELL_DEATHBLOOM, H_SPELL_DEATHBLOOM)); + events.ScheduleEvent(EVENT_DEATHBLOOM, 30000); + break; + case EVENT_INEVITABLE_DOOM: + _doomCounter++; + DoCastAOE(RAID_MODE(SPELL_INEVITABLE_DOOM, H_SPELL_INEVITABLE_DOOM)); + events.ScheduleEvent(EVENT_INEVITABLE_DOOM, std::max(120000 - _doomCounter * 15000, 15000)); // needs to be confirmed + break; + case EVENT_SPORE: + DoCast(me, SPELL_SUMMON_SPORE, false); + events.ScheduleEvent(EVENT_SPORE, IsHeroic() ? 18000 : 36000); + break; + case EVENT_NECROTIC_AURA_FADING: + Talk(SAY_NECROTIC_AURA_FADING); + break; + default: + break; + } } + + DoMeleeAttackIfReady(); } - DoMeleeAttackIfReady(); + private: + bool _sporeLoserData; + uint8 _doomCounter; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new boss_loathebAI(creature); + } +}; + +class achievement_spore_loser : public AchievementCriteriaScript +{ + public: + achievement_spore_loser() : AchievementCriteriaScript("achievement_spore_loser") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + return target && target->GetAI()->GetData(DATA_ACHIEVEMENT_SPORE_LOSER); } - }; +}; + +typedef boss_loatheb::boss_loathebAI LoathebAI; + +class spell_loatheb_necrotic_aura_warning : public SpellScriptLoader +{ + public: + spell_loatheb_necrotic_aura_warning() : SpellScriptLoader("spell_loatheb_necrotic_aura_warning") { } + + class spell_loatheb_necrotic_aura_warning_AuraScript : public AuraScript + { + PrepareAuraScript(spell_loatheb_necrotic_aura_warning_AuraScript); + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellStore.LookupEntry(SPELL_WARN_NECROTIC_AURA)) + return false; + return true; + } + void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTarget()->IsAIEnabled) + CAST_AI(LoathebAI, GetTarget()->GetAI())->Talk(SAY_NECROTIC_AURA_APPLIED); + } + + void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTarget()->IsAIEnabled) + CAST_AI(LoathebAI, GetTarget()->GetAI())->Talk(SAY_NECROTIC_AURA_REMOVED); + } + + void Register() + { + AfterEffectApply += AuraEffectApplyFn(spell_loatheb_necrotic_aura_warning_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_loatheb_necrotic_aura_warning_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_loatheb_necrotic_aura_warning_AuraScript(); + } }; void AddSC_boss_loatheb() { new boss_loatheb(); + new achievement_spore_loser(); + new spell_loatheb_necrotic_aura_warning(); } -- cgit v1.2.3 From 2dc6cb15ed2b895311c2deb78daec9feabbf9d73 Mon Sep 17 00:00:00 2001 From: Emo Norfik Date: Mon, 9 Jan 2012 14:01:58 +0100 Subject: Scripts/Utgarde Pinnacle: - Fix spamming of spell Ball of Flame (48246). - Added missing text of Image of Arthas. - Code cleanup and code style. - Typo fix in sql naming in commit 6cb495048916a916804ebf8bde19e9619b12f897 --- sql/updates/world/2011_01_08_16_world_misc.sql | 117 --------------------- sql/updates/world/2012_01_08_16_world_misc.sql | 117 +++++++++++++++++++++ .../world/2012_01_09_01_world_creature_text.sql | 5 + .../world/2012_01_09_01_world_smart_scripts.sql | 2 + .../UtgardeKeep/UtgardePinnacle/boss_svala.cpp | 13 +-- 5 files changed, 127 insertions(+), 127 deletions(-) delete mode 100644 sql/updates/world/2011_01_08_16_world_misc.sql create mode 100644 sql/updates/world/2012_01_08_16_world_misc.sql create mode 100644 sql/updates/world/2012_01_09_01_world_creature_text.sql create mode 100644 sql/updates/world/2012_01_09_01_world_smart_scripts.sql (limited to 'src/server/scripts') diff --git a/sql/updates/world/2011_01_08_16_world_misc.sql b/sql/updates/world/2011_01_08_16_world_misc.sql deleted file mode 100644 index 63cd81ff869..00000000000 --- a/sql/updates/world/2011_01_08_16_world_misc.sql +++ /dev/null @@ -1,117 +0,0 @@ -/* Texts */ - --- Move text used in Svala Sorrowgrave from script_texts to creature_text --- Remove old script text for boss_svala.cpp -DELETE FROM `script_texts` WHERE `entry` BETWEEN -1575027 AND -1575015; - -DELETE FROM `creature_text` WHERE `entry` IN (26668,29281); -INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES -(26668,0,0, 'The sensation is... beyond my imagining. I am yours to command, my king.',14,0,0,0,0,13857, 'Svala Sorrowgrave SAY_DIALOG_WITH_ARTHAS_2'), -(26668,1,0, 'I will be happy to slaughter them in your name! Come, enemies of the Scourge! I will show you the might of the Lich King!',14,0,0,0,0,13858, 'Svala Sorrowgrave SAY_DIALOG_WITH_ARTHAS_3'), -(26668,2,0, 'I will vanquish your soul!',14,0,0,0,0,13842, 'Svala Sorrowgrave SAY_AGGRO'), -(26668,3,0, 'You were a fool to challenge the power of the Lich King!',14,0,0,0,0,13845, 'Svala Sorrowgrave SAY_SLAY_1'), -(26668,3,1, 'Your will is done, my king.',14,0,0,0,0,13847, 'Svala Sorrowgrave SAY_SLAY_2'), -(26668,3,2, 'Another soul for my master.',14,0,0,0,0,13848, 'Svala Sorrowgrave SAY_SLAY_3'), -(26668,4,0, 'Nooo! I did not come this far... to...',14,0,0,0,0,13855, 'Svala Sorrowgrave SAY_DEATH'), -(26668,5,0, 'Your death approaches.',14,0,0,0,0,13850, 'Svala Sorrowgrave SAY_SACRIFICE_1'), -(26668,5,1, 'Go now to my master.',14,0,0,0,0,13851, 'Svala Sorrowgrave SAY_SACRIFICE_2'), -(26668,5,2, 'Your end is inevitable.',14,0,0,0,0,13852, 'Svala Sorrowgrave SAY_SACRIFICE_3'), -(26668,5,3, 'Yor-guul mak!',14,0,0,0,0,13853, 'Svala Sorrowgrave SAY_SACRIFICE_4'), -(26668,5,4, 'Any last words?',14,0,0,0,0,13854, 'Svala Sorrowgrave SAY_SACRIFICE_5'), -(29281,0,0, 'My liege! I have done as you asked, and now beseech you for your blessing!',14,0,0,0,0,13856, 'Svala SAY_DIALOG_WITH_ARTHAS_1'); - -/* Templates */ - -UPDATE `creature_template` SET `unit_flags`=2 WHERE `entry` IN (29281, 30809); -- And this, fixes her flag so script can be started (credit to ric) -UPDATE `creature` SET `spawntimesecs`=86400 WHERE `id`=29281; -- Set Svala's spawn time -UPDATE `creature_template` SET `flags_extra`=`flags_extra`|1 WHERE `entry`=30809; -- Set flags_extra = 1 for Svala hero difficulty -UPDATE `creature_template` SET `InhabitType`=7, `flags_extra`=`flags_extra`|130 WHERE `entry`=30805; -- Set same data on heroic ver to triggers -UPDATE `creature_template` SET `InhabitType`=7, `flags_extra`=`flags_extra`|128 WHERE `entry`=30771; -- Set same data on heroic ver to triggers - -UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask` -|1 -- CHARM -|2 -- DISORIENTED -|4 -- DISARM -|8 -- DISTRACT -|16 -- FEAR -|32 -- GRIP -|64 -- ROOT -|128 -- PACIFY -|256 -- SILENCE -|512 -- SLEEP -|1024 -- SNARE -|2048 -- STUN -|4096 -- FREEZE -|8192 -- KNOCKOUT -|65536 -- POLYMORPH -|131072 -- BANISH -|524288 -- SHACKLE -|4194304 -- TURN -|8388608 -- HORROR -|67108864 -- DAZE -|536870912 -- SAPPED -WHERE `entry` IN (29281, 30809, 26668, 30810); - --- Apply Image of Arthas Visual Effect -DELETE FROM `creature_template_addon` WHERE `entry`=29280; -INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES -(29280, 0, 0, 0, 1, 0, '54134'); - --- Flame Brazier triggers deletion (will spawn them after activating event 17841 called by spell Call Flames 48258) -DELETE FROM `creature` WHERE `id`=27273 AND `map`=575; -DELETE FROM `creature_addon` WHERE `guid` IN (126121, 126122); - -/* Spells */ - -DELETE FROM `spell_target_position` WHERE `id` IN (48267,48276, 48271, 48274, 48275); -INSERT INTO `spell_target_position` (`id`, `target_map`, `target_position_x`, `target_position_y`, `target_position_z`, `target_orientation`) VALUES -(48267, 575, 296.632, -346.075, 90.5474, 4.60767), -- Svala Ritual - Player teleport position -(48276, 575, 296.651, -346.293, 108.5474, 1.58), -- Svala Ritual - Svala teleport position -(48271, 575, 296.42, -355.01, 90.94, 1.58), -- Summon Ritual Channeler positions -(48274, 575, 302.36, -352.01, 90.54, 2.20), -- Summon Ritual Channeler positions -(48275, 575, 291.39, -352.01, 90.54, 0.91); -- Summon Ritual Channeler positions - -DELETE FROM `conditions` WHERE `SourceEntry` IN (48331,48246,48277) AND `SourceTypeOrReferenceId`=13; -INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES -(13, 0, 48331, 0, 18, 1, 27327, 0, 0, '', NULL), -- Spell script target for flying sword -(13, 0, 48246, 0, 18, 1, 0, 0, 0, '', NULL), -- Spell script target for Flame Brazier's (on players only) -(13, 0, 48277, 0, 18, 1, 26555, 0, 0, '', NULL), -- Spell script target for Ritual Strike DMG -- Players -(13, 0, 48277, 0, 18, 1, 27327, 0, 0, '', NULL); -- Spell script target for Ritual Strike DMG -- Ritual Target - -/* Achivements */ - --- The Incredible Hulk achievement 2043 -DELETE FROM `disables` WHERE `sourceType`=4 AND `entry`=7322; -DELETE FROM `achievement_criteria_data` WHERE `criteria_id`=7322 AND `type`=11; -INSERT INTO `achievement_criteria_data` (`criteria_id`, `type`, `value1`, `value2`, `ScriptName`) VALUES -(7322, 11, 0, 0, 'achievement_incredible_hulk'); - -/* AI */ - -DELETE FROM `creature_ai_scripts` WHERE `creature_id`=26555; -- Scourge Hulk -UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`=27273; -- Flame Brazier - --- Add Send Script Event (17841) summon 3 triggers -DELETE FROM `event_scripts` WHERE `id`=17841; -INSERT INTO `event_scripts` (`id`, `delay`, `command`, `datalong`, `datalong2`, `dataint`, `x`, `y`, `z`, `o`) VALUES -(17841, 0, 10, 27273, 10000, 0, 285.6, -357.5, 91.0833, 5.75959), -(17841, 3, 10, 27273, 10000, 0, 307, -357.5, 91.0833, 6.02139), -(17841, 6, 10, 27273, 10000, 0, 285.6, -357.5, 91.0833, 5.75959); - --- SmartAI script Flame Brazier's cast Ball of Flame (48246) on random player -DELETE FROM `smart_scripts` WHERE `entryorguid`=27273 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 -(27273, 0, 0, 0, 1, 0, 100, 1, 100, 100, 100, 100, 11, 48246, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Flame Brazier - Ball of Flame'); - -/* Script names */ - -UPDATE `creature_template` SET `AIName`='', `ScriptName`='npc_scourge_hulk' WHERE `entry`=26555; -UPDATE `creature_template` SET `ScriptName`='' WHERE `entry`=26668; -- "boss_svala_sorrowgrave" script is now merged with "boss_svala" script -UPDATE `creature_template` SET `ScriptName`='npc_spectator' WHERE `entry`=26667; -- Spectators escape script -UPDATE `creature_template` SET `ScriptName`='npc_ritual_channeler' WHERE `entry`=27281; -- Change 'mob_ritual_channeler' to 'npc_ritual_channeler' - --- Paralyze -- Filter targets -- cast only on sacrafacing target -DELETE FROM `spell_script_names` WHERE `spell_id`=48278; -INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES -(48278, 'spell_paralyze_pinnacle'); - diff --git a/sql/updates/world/2012_01_08_16_world_misc.sql b/sql/updates/world/2012_01_08_16_world_misc.sql new file mode 100644 index 00000000000..63cd81ff869 --- /dev/null +++ b/sql/updates/world/2012_01_08_16_world_misc.sql @@ -0,0 +1,117 @@ +/* Texts */ + +-- Move text used in Svala Sorrowgrave from script_texts to creature_text +-- Remove old script text for boss_svala.cpp +DELETE FROM `script_texts` WHERE `entry` BETWEEN -1575027 AND -1575015; + +DELETE FROM `creature_text` WHERE `entry` IN (26668,29281); +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +(26668,0,0, 'The sensation is... beyond my imagining. I am yours to command, my king.',14,0,0,0,0,13857, 'Svala Sorrowgrave SAY_DIALOG_WITH_ARTHAS_2'), +(26668,1,0, 'I will be happy to slaughter them in your name! Come, enemies of the Scourge! I will show you the might of the Lich King!',14,0,0,0,0,13858, 'Svala Sorrowgrave SAY_DIALOG_WITH_ARTHAS_3'), +(26668,2,0, 'I will vanquish your soul!',14,0,0,0,0,13842, 'Svala Sorrowgrave SAY_AGGRO'), +(26668,3,0, 'You were a fool to challenge the power of the Lich King!',14,0,0,0,0,13845, 'Svala Sorrowgrave SAY_SLAY_1'), +(26668,3,1, 'Your will is done, my king.',14,0,0,0,0,13847, 'Svala Sorrowgrave SAY_SLAY_2'), +(26668,3,2, 'Another soul for my master.',14,0,0,0,0,13848, 'Svala Sorrowgrave SAY_SLAY_3'), +(26668,4,0, 'Nooo! I did not come this far... to...',14,0,0,0,0,13855, 'Svala Sorrowgrave SAY_DEATH'), +(26668,5,0, 'Your death approaches.',14,0,0,0,0,13850, 'Svala Sorrowgrave SAY_SACRIFICE_1'), +(26668,5,1, 'Go now to my master.',14,0,0,0,0,13851, 'Svala Sorrowgrave SAY_SACRIFICE_2'), +(26668,5,2, 'Your end is inevitable.',14,0,0,0,0,13852, 'Svala Sorrowgrave SAY_SACRIFICE_3'), +(26668,5,3, 'Yor-guul mak!',14,0,0,0,0,13853, 'Svala Sorrowgrave SAY_SACRIFICE_4'), +(26668,5,4, 'Any last words?',14,0,0,0,0,13854, 'Svala Sorrowgrave SAY_SACRIFICE_5'), +(29281,0,0, 'My liege! I have done as you asked, and now beseech you for your blessing!',14,0,0,0,0,13856, 'Svala SAY_DIALOG_WITH_ARTHAS_1'); + +/* Templates */ + +UPDATE `creature_template` SET `unit_flags`=2 WHERE `entry` IN (29281, 30809); -- And this, fixes her flag so script can be started (credit to ric) +UPDATE `creature` SET `spawntimesecs`=86400 WHERE `id`=29281; -- Set Svala's spawn time +UPDATE `creature_template` SET `flags_extra`=`flags_extra`|1 WHERE `entry`=30809; -- Set flags_extra = 1 for Svala hero difficulty +UPDATE `creature_template` SET `InhabitType`=7, `flags_extra`=`flags_extra`|130 WHERE `entry`=30805; -- Set same data on heroic ver to triggers +UPDATE `creature_template` SET `InhabitType`=7, `flags_extra`=`flags_extra`|128 WHERE `entry`=30771; -- Set same data on heroic ver to triggers + +UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask` +|1 -- CHARM +|2 -- DISORIENTED +|4 -- DISARM +|8 -- DISTRACT +|16 -- FEAR +|32 -- GRIP +|64 -- ROOT +|128 -- PACIFY +|256 -- SILENCE +|512 -- SLEEP +|1024 -- SNARE +|2048 -- STUN +|4096 -- FREEZE +|8192 -- KNOCKOUT +|65536 -- POLYMORPH +|131072 -- BANISH +|524288 -- SHACKLE +|4194304 -- TURN +|8388608 -- HORROR +|67108864 -- DAZE +|536870912 -- SAPPED +WHERE `entry` IN (29281, 30809, 26668, 30810); + +-- Apply Image of Arthas Visual Effect +DELETE FROM `creature_template_addon` WHERE `entry`=29280; +INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES +(29280, 0, 0, 0, 1, 0, '54134'); + +-- Flame Brazier triggers deletion (will spawn them after activating event 17841 called by spell Call Flames 48258) +DELETE FROM `creature` WHERE `id`=27273 AND `map`=575; +DELETE FROM `creature_addon` WHERE `guid` IN (126121, 126122); + +/* Spells */ + +DELETE FROM `spell_target_position` WHERE `id` IN (48267,48276, 48271, 48274, 48275); +INSERT INTO `spell_target_position` (`id`, `target_map`, `target_position_x`, `target_position_y`, `target_position_z`, `target_orientation`) VALUES +(48267, 575, 296.632, -346.075, 90.5474, 4.60767), -- Svala Ritual - Player teleport position +(48276, 575, 296.651, -346.293, 108.5474, 1.58), -- Svala Ritual - Svala teleport position +(48271, 575, 296.42, -355.01, 90.94, 1.58), -- Summon Ritual Channeler positions +(48274, 575, 302.36, -352.01, 90.54, 2.20), -- Summon Ritual Channeler positions +(48275, 575, 291.39, -352.01, 90.54, 0.91); -- Summon Ritual Channeler positions + +DELETE FROM `conditions` WHERE `SourceEntry` IN (48331,48246,48277) AND `SourceTypeOrReferenceId`=13; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13, 0, 48331, 0, 18, 1, 27327, 0, 0, '', NULL), -- Spell script target for flying sword +(13, 0, 48246, 0, 18, 1, 0, 0, 0, '', NULL), -- Spell script target for Flame Brazier's (on players only) +(13, 0, 48277, 0, 18, 1, 26555, 0, 0, '', NULL), -- Spell script target for Ritual Strike DMG -- Players +(13, 0, 48277, 0, 18, 1, 27327, 0, 0, '', NULL); -- Spell script target for Ritual Strike DMG -- Ritual Target + +/* Achivements */ + +-- The Incredible Hulk achievement 2043 +DELETE FROM `disables` WHERE `sourceType`=4 AND `entry`=7322; +DELETE FROM `achievement_criteria_data` WHERE `criteria_id`=7322 AND `type`=11; +INSERT INTO `achievement_criteria_data` (`criteria_id`, `type`, `value1`, `value2`, `ScriptName`) VALUES +(7322, 11, 0, 0, 'achievement_incredible_hulk'); + +/* AI */ + +DELETE FROM `creature_ai_scripts` WHERE `creature_id`=26555; -- Scourge Hulk +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`=27273; -- Flame Brazier + +-- Add Send Script Event (17841) summon 3 triggers +DELETE FROM `event_scripts` WHERE `id`=17841; +INSERT INTO `event_scripts` (`id`, `delay`, `command`, `datalong`, `datalong2`, `dataint`, `x`, `y`, `z`, `o`) VALUES +(17841, 0, 10, 27273, 10000, 0, 285.6, -357.5, 91.0833, 5.75959), +(17841, 3, 10, 27273, 10000, 0, 307, -357.5, 91.0833, 6.02139), +(17841, 6, 10, 27273, 10000, 0, 285.6, -357.5, 91.0833, 5.75959); + +-- SmartAI script Flame Brazier's cast Ball of Flame (48246) on random player +DELETE FROM `smart_scripts` WHERE `entryorguid`=27273 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 +(27273, 0, 0, 0, 1, 0, 100, 1, 100, 100, 100, 100, 11, 48246, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Flame Brazier - Ball of Flame'); + +/* Script names */ + +UPDATE `creature_template` SET `AIName`='', `ScriptName`='npc_scourge_hulk' WHERE `entry`=26555; +UPDATE `creature_template` SET `ScriptName`='' WHERE `entry`=26668; -- "boss_svala_sorrowgrave" script is now merged with "boss_svala" script +UPDATE `creature_template` SET `ScriptName`='npc_spectator' WHERE `entry`=26667; -- Spectators escape script +UPDATE `creature_template` SET `ScriptName`='npc_ritual_channeler' WHERE `entry`=27281; -- Change 'mob_ritual_channeler' to 'npc_ritual_channeler' + +-- Paralyze -- Filter targets -- cast only on sacrafacing target +DELETE FROM `spell_script_names` WHERE `spell_id`=48278; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(48278, 'spell_paralyze_pinnacle'); + diff --git a/sql/updates/world/2012_01_09_01_world_creature_text.sql b/sql/updates/world/2012_01_09_01_world_creature_text.sql new file mode 100644 index 00000000000..d1ec26bd7f4 --- /dev/null +++ b/sql/updates/world/2012_01_09_01_world_creature_text.sql @@ -0,0 +1,5 @@ +-- Missing Image of Arthas say text +DELETE FROM `creature_text` WHERE `entry`=29280; +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +(29280,0,0, 'Your sacrifice is a testament to your obedience. Indeed you are worthy of this charge. Arise, and forever be known as Svala Sorrowgrave!',14,0,0,0,0,14732, 'Image of Arthas SAY_DIALOG_OF_ARTHAS_1'), +(29280,1,0, 'Your first test awaits you. Destroy our uninvited guests.',14,0,0,0,0,14733, 'Image of Arthas SAY_DIALOG_OF_ARTHAS_2'); diff --git a/sql/updates/world/2012_01_09_01_world_smart_scripts.sql b/sql/updates/world/2012_01_09_01_world_smart_scripts.sql new file mode 100644 index 00000000000..a7304fa6e6a --- /dev/null +++ b/sql/updates/world/2012_01_09_01_world_smart_scripts.sql @@ -0,0 +1,2 @@ +-- Fix spamming of spell Ball of Flame (48246) +UPDATE `smart_scripts` SET `event_type`=54, `event_param1`=0, `event_param2`=0, `event_param3`=0, `event_param4`=0 WHERE `entryorguid`=27273; diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp index 7280c3d5b82..9cab1de197c 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp @@ -102,14 +102,7 @@ static const float spectatorWP[2][3] = {297.69f,-275.81f,86.36f} }; -static Position RitualChannelerPos[]= -{ - {296.42f, -355.01f, 90.94f, 1.58f}, - {302.36f, -352.01f, 90.54f, 2.20f}, - {291.39f, -352.01f, 90.54f, 0.91f} -}; static Position ArthasPos = { 295.81f, -366.16f, 92.57f, 1.58f }; -static Position SvalaPos = { 296.632f, -346.075f, 90.6307f, 1.58f }; class boss_svala : public CreatureScript { @@ -527,9 +520,9 @@ public: struct npc_ritual_channelerAI : public Scripted_NoMovementAI { - npc_ritual_channelerAI(Creature* c) :Scripted_NoMovementAI(c) + npc_ritual_channelerAI(Creature* creature) :Scripted_NoMovementAI(creature) { - instance = c->GetInstanceScript(); + instance = creature->GetInstanceScript(); } InstanceScript* instance; @@ -574,7 +567,7 @@ public: struct npc_spectatorAI : public ScriptedAI { - npc_spectatorAI(Creature* c) : ScriptedAI(c) { } + npc_spectatorAI(Creature* creature) : ScriptedAI(creature) { } void Reset() { } -- cgit v1.2.3 From 7101e9626cf9a94ca37110b1ee1fd1c0b6258b91 Mon Sep 17 00:00:00 2001 From: Subv2112 Date: Mon, 9 Jan 2012 09:28:27 -0500 Subject: Scripts/Commands: Fixed an error with account set gmlevel, the gmRealmID can be signed Signed-off-by: Subv2112 --- src/server/scripts/Commands/cs_account.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/server/scripts') diff --git a/src/server/scripts/Commands/cs_account.cpp b/src/server/scripts/Commands/cs_account.cpp index ac265acbf71..7372c92c4dd 100644 --- a/src/server/scripts/Commands/cs_account.cpp +++ b/src/server/scripts/Commands/cs_account.cpp @@ -510,7 +510,7 @@ public: stmt->setUInt32(0, targetAccountId); stmt->setUInt8(1, uint8(gm)); - stmt->setUInt32(2, gmRealmID); + stmt->setInt32(2, gmRealmID); LoginDatabase.Execute(stmt); } -- cgit v1.2.3 From f7276a95de6bda0fbf4a446b9bb94373328506e2 Mon Sep 17 00:00:00 2001 From: Subv2112 Date: Mon, 9 Jan 2012 20:36:56 -0500 Subject: Scripts/Achievements: Fixed achievement Shocking! on 10-man and 25-man closes #4751 Signed-off-by: Subv2112 --- src/server/game/Spells/SpellEffects.cpp | 32 ------------ .../scripts/Northrend/Naxxramas/boss_thaddius.cpp | 59 ++++++++++++++++++++++ .../Northrend/Naxxramas/instance_naxxramas.cpp | 24 +++++++-- src/server/scripts/Northrend/Naxxramas/naxxramas.h | 2 + 4 files changed, 81 insertions(+), 36 deletions(-) (limited to 'src/server/scripts') diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 40b3101cfd5..2c33488f76c 100755 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -333,38 +333,6 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) switch (m_spellInfo->Id) // better way to check unknown { - // Positive/Negative Charge - case 28062: - case 28085: - case 39090: - case 39093: - if (!m_triggeredByAuraSpell) - break; - if (unitTarget == m_caster) - { - uint8 count = 0; - for (std::list::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) - if (ihit->targetGUID != m_caster->GetGUID()) - if (Player* target = ObjectAccessor::GetPlayer(*m_caster, ihit->targetGUID)) - if (target->HasAura(m_triggeredByAuraSpell->Id)) - ++count; - if (count) - { - uint32 spellId = 0; - switch (m_spellInfo->Id) - { - case 28062: spellId = 29659; break; - case 28085: spellId = 29660; break; - case 39090: spellId = 39089; break; - case 39093: spellId = 39092; break; - } - m_caster->SetAuraStack(spellId, m_caster, count); - } - } - - if (unitTarget->HasAura(m_triggeredByAuraSpell->Id)) - damage = 0; - break; // Consumption case 28865: damage = (((InstanceMap*)m_caster->GetMap())->GetDifficulty() == REGULAR_DIFFICULTY ? 2750 : 4250); diff --git a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp index b0138fb1a5e..24ef5fdcd3e 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp @@ -400,9 +400,68 @@ public: }; +class spell_thaddius_pos_neg_charge : public SpellScriptLoader +{ + public: + spell_thaddius_pos_neg_charge() : SpellScriptLoader("spell_thaddius_pos_neg_charge") { } + + class spell_thaddius_pos_neg_charge_SpellScript : public SpellScript + { + PrepareSpellScript(spell_thaddius_pos_neg_charge_SpellScript); + + void HandleTargets(std::list& targetList) + { + uint8 count = 0; + for (std::list::iterator ihit = targetList.begin(); ihit != targetList.end(); ++ihit) + if ((*ihit)->GetGUID() != GetCaster()->GetGUID()) + if (Player* target = (*ihit)->ToPlayer()) + if (target->HasAura(GetTriggeringSpell()->Id)) + ++count; + if (count) + { + uint32 spellId = 0; + switch (GetSpellInfo()->Id) + { + case 28062: spellId = 29659; break; + case 28085: spellId = 29660; break; + case 39090: spellId = 39089; break; + case 39093: spellId = 39092; break; + } + GetCaster()->SetAuraStack(spellId, GetCaster(), count); + } + } + + void HandleDamage(SpellEffIndex /*effIndex*/) + { + if (!GetTriggeringSpell()) + return; + + Unit* target = GetHitUnit(); + + if (target->HasAura(GetTriggeringSpell()->Id)) + SetHitDamage(0); + else + if (InstanceScript* instance = target->GetInstanceScript()) + instance->SetData(DATA_POLARITY_SWITCHED, 1); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_thaddius_pos_neg_charge_SpellScript::HandleDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); + OnUnitTargetSelect += SpellUnitTargetFn(spell_thaddius_pos_neg_charge_SpellScript::HandleTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_thaddius_pos_neg_charge_SpellScript(); + } +}; + void AddSC_boss_thaddius() { new boss_thaddius(); new mob_stalagg(); new mob_feugen(); + new spell_thaddius_pos_neg_charge(); } diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp index 32cb279ce5f..9ae6f8d9776 100644 --- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp +++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp @@ -148,6 +148,8 @@ public: time_t maxHorsemenDiedTime; uint32 playerDied; + + uint32 PolaritySwitch; void Initialize() { @@ -166,8 +168,10 @@ public: kelthuzadGUID = 0; kelthuzadTriggerGUID = 0; - playerDied = 0; - gothikDoorState = GO_STATE_ACTIVE; + playerDied = 0; + gothikDoorState = GO_STATE_ACTIVE; + + PolaritySwitch = 0; memset(portalsGUID, 0, sizeof(portalsGUID)); } @@ -311,6 +315,9 @@ public: case DATA_ABOMINATION_KILLED: AbominationCount = value; break; + case DATA_POLARITY_SWITCHED: + PolaritySwitch = value; + break; } } @@ -440,6 +447,13 @@ public: if (AreAllEncoutersDone() && !playerDied) return true; return false; + // Criteria for achievement 2178: Shocking! (10-man) + case 7604: + // Criteria for achievement 2179: Shocking! (25-man) + case 7605: + if (!PolaritySwitch) + return true; + return false; } return false; } @@ -447,14 +461,14 @@ public: std::string GetSaveData() { std::ostringstream saveStream; - saveStream << GetBossSaveData() << gothikDoorState << ' ' << playerDied; + saveStream << GetBossSaveData() << gothikDoorState << ' ' << playerDied << ' ' << PolaritySwitch; return saveStream.str(); } void Load(const char * data) { std::istringstream loadStream(LoadBossState(data)); - uint32 temp, buff, buff2; + uint32 temp, buff, buff2, buff3; for (uint32 i = 0; i < MAX_BOSS_NUMBER; ++i) loadStream >> temp; @@ -463,6 +477,8 @@ public: gothikDoorState = GOState(buff); loadStream >> buff2; playerDied = buff2; + loadStream >> buff3; + PolaritySwitch = buff3; } }; diff --git a/src/server/scripts/Northrend/Naxxramas/naxxramas.h b/src/server/scripts/Northrend/Naxxramas/naxxramas.h index 43393aff844..34d465c775d 100644 --- a/src/server/scripts/Northrend/Naxxramas/naxxramas.h +++ b/src/server/scripts/Northrend/Naxxramas/naxxramas.h @@ -49,6 +49,8 @@ enum Data DATA_HORSEMEN2, DATA_HORSEMEN3, DATA_ABOMINATION_KILLED, + + DATA_POLARITY_SWITCHED, }; enum Data64 -- cgit v1.2.3 From 233d8919528879a26b1aa03373fee590f2307c9d Mon Sep 17 00:00:00 2001 From: kaelima Date: Wed, 11 Jan 2012 17:21:03 +0100 Subject: Scripts/Achievements: - Move achievement Shocking! to appropriate boss script instead of instance script. - Split the polarity spellscript into two and move to proper boss file - Fixed a typo in Loatheb's spore achievement. --- ...12_01_11_01_world_achievement_criteria_data.sql | 4 + .../2012_01_11_01_world_spell_script_names.sql | 4 + src/server/game/Scripting/ScriptLoader.cpp | 2 + .../scripts/Northrend/Naxxramas/boss_loatheb.cpp | 2 +- .../scripts/Northrend/Naxxramas/boss_thaddius.cpp | 81 +++++++++++++++--- .../Northrend/Naxxramas/instance_naxxramas.cpp | 20 +---- src/server/scripts/Northrend/Naxxramas/naxxramas.h | 2 - src/server/scripts/Outland/CMakeLists.txt | 1 + .../Mechanar/boss_mechano_lord_capacitus.cpp | 99 ++++++++++++++++++++++ 9 files changed, 182 insertions(+), 33 deletions(-) create mode 100644 sql/updates/world/2012_01_11_01_world_achievement_criteria_data.sql create mode 100644 sql/updates/world/2012_01_11_01_world_spell_script_names.sql create mode 100644 src/server/scripts/Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp (limited to 'src/server/scripts') diff --git a/sql/updates/world/2012_01_11_01_world_achievement_criteria_data.sql b/sql/updates/world/2012_01_11_01_world_achievement_criteria_data.sql new file mode 100644 index 00000000000..aa3ec94a5a8 --- /dev/null +++ b/sql/updates/world/2012_01_11_01_world_achievement_criteria_data.sql @@ -0,0 +1,4 @@ +DELETE FROM `achievement_criteria_data` WHERE `criteria_id` IN (7604, 7605) AND `type` IN (18,11); +INSERT INTO `achievement_criteria_data` (`criteria_id`,`type`,`value1`,`value2`,`ScriptName`) VALUES +(7604,11,0,0, 'achievement_polarity_switch'), +(7605,11,0,0, 'achievement_polarity_switch'); diff --git a/sql/updates/world/2012_01_11_01_world_spell_script_names.sql b/sql/updates/world/2012_01_11_01_world_spell_script_names.sql new file mode 100644 index 00000000000..4600f190c4e --- /dev/null +++ b/sql/updates/world/2012_01_11_01_world_spell_script_names.sql @@ -0,0 +1,4 @@ +DELETE FROM `spell_script_names` WHERE `spell_id` IN (39090, 39093); +INSERT INTO `spell_script_names`(`spell_id`,`ScriptName`) VALUES +(39090, 'spell_capacitus_polarity_shift'), +(39093, 'spell_capacitus_polarity_shift'); diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 6322151e792..c46721db6cd 100755 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -570,6 +570,7 @@ void AddSC_the_eye(); void AddSC_boss_gatewatcher_iron_hand(); //TK The Mechanar void AddSC_boss_nethermancer_sepethrea(); void AddSC_boss_pathaleon_the_calculator(); +void AddSC_boss_mechano_lord_capacitus(); void AddSC_instance_mechanar(); void AddSC_blades_edge_mountains(); @@ -1030,6 +1031,7 @@ void AddOutlandScripts() AddSC_boss_gatewatcher_iron_hand(); //TK The Mechanar AddSC_boss_nethermancer_sepethrea(); AddSC_boss_pathaleon_the_calculator(); + AddSC_boss_mechano_lord_capacitus(); AddSC_instance_mechanar(); AddSC_blades_edge_mountains(); diff --git a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp index 502c841540a..58d3a4240b2 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp @@ -82,7 +82,7 @@ class boss_loatheb : public CreatureScript _sporeLoserData = false; } - uint32 GetData(int32 id) + uint32 GetData(uint32 id) { if (id != DATA_ACHIEVEMENT_SPORE_LOSER) return 0; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp index 24ef5fdcd3e..be9168c6fd4 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp @@ -83,7 +83,11 @@ enum ThaddiusSpells SPELL_BALL_LIGHTNING = 28299, SPELL_CHAIN_LIGHTNING = 28167, H_SPELL_CHAIN_LIGHTNING = 54531, - SPELL_BERSERK = 27680 + SPELL_BERSERK = 27680, + SPELL_POSITIVE_CHARGE = 28062, + SPELL_POSITIVE_CHARGE_STACK = 29659, + SPELL_NEGATIVE_CHARGE = 28085, + SPELL_NEGATIVE_CHARGE_STACK = 29660 }; enum Events @@ -94,6 +98,11 @@ enum Events EVENT_BERSERK, }; +enum Achievement +{ + DATA_POLARITY_SWITCH = 76047605, +}; + class boss_thaddius : public CreatureScript { public: @@ -135,6 +144,7 @@ public: bool checkStalaggAlive; bool checkFeugenAlive; + bool polaritySwitch; uint32 uiAddsTimer; void KilledUnit(Unit* /*victim*/) @@ -194,6 +204,20 @@ public: me->SetReactState(REACT_AGGRESSIVE); } + void SetData(uint32 id, uint32 data) + { + if (id == DATA_POLARITY_SWITCH) + polaritySwitch = data ? true : false; + } + + uint32 GetData(uint32 id) + { + if (id != DATA_POLARITY_SWITCH) + return 0; + + return uint32(polaritySwitch); + } + void UpdateAI(const uint32 diff) { if (checkFeugenAlive && checkStalaggAlive) @@ -409,6 +433,24 @@ class spell_thaddius_pos_neg_charge : public SpellScriptLoader { PrepareSpellScript(spell_thaddius_pos_neg_charge_SpellScript); + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_POSITIVE_CHARGE)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_POSITIVE_CHARGE_STACK)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_NEGATIVE_CHARGE)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_NEGATIVE_CHARGE_STACK)) + return false; + return true; + } + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + void HandleTargets(std::list& targetList) { uint8 count = 0; @@ -417,16 +459,16 @@ class spell_thaddius_pos_neg_charge : public SpellScriptLoader if (Player* target = (*ihit)->ToPlayer()) if (target->HasAura(GetTriggeringSpell()->Id)) ++count; + if (count) { uint32 spellId = 0; - switch (GetSpellInfo()->Id) - { - case 28062: spellId = 29659; break; - case 28085: spellId = 29660; break; - case 39090: spellId = 39089; break; - case 39093: spellId = 39092; break; - } + + if (GetSpellInfo()->Id == SPELL_POSITIVE_CHARGE) + spellId = SPELL_POSITIVE_CHARGE_STACK; + else // if (GetSpellInfo()->Id == SPELL_NEGATIVE_CHARGE) + spellId = SPELL_NEGATIVE_CHARGE_STACK; + GetCaster()->SetAuraStack(spellId, GetCaster(), count); } } @@ -435,14 +477,17 @@ class spell_thaddius_pos_neg_charge : public SpellScriptLoader { if (!GetTriggeringSpell()) return; - + Unit* target = GetHitUnit(); - + Unit* caster = GetCaster(); + if (target->HasAura(GetTriggeringSpell()->Id)) SetHitDamage(0); else - if (InstanceScript* instance = target->GetInstanceScript()) - instance->SetData(DATA_POLARITY_SWITCHED, 1); + { + if (target->GetTypeId() == TYPEID_PLAYER && caster->IsAIEnabled) + caster->ToCreature()->AI()->SetData(DATA_POLARITY_SWITCH, 1); + } } void Register() @@ -458,10 +503,22 @@ class spell_thaddius_pos_neg_charge : public SpellScriptLoader } }; +class achievement_polarity_switch : public AchievementCriteriaScript +{ + public: + achievement_polarity_switch() : AchievementCriteriaScript("achievement_polarity_switch") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + return target && target->GetAI()->GetData(DATA_POLARITY_SWITCH); + } +}; + void AddSC_boss_thaddius() { new boss_thaddius(); new mob_stalagg(); new mob_feugen(); new spell_thaddius_pos_neg_charge(); + new achievement_polarity_switch(); } diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp index 9ae6f8d9776..c05d9a21850 100644 --- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp +++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp @@ -148,8 +148,6 @@ public: time_t maxHorsemenDiedTime; uint32 playerDied; - - uint32 PolaritySwitch; void Initialize() { @@ -170,8 +168,6 @@ public: playerDied = 0; gothikDoorState = GO_STATE_ACTIVE; - - PolaritySwitch = 0; memset(portalsGUID, 0, sizeof(portalsGUID)); } @@ -315,9 +311,6 @@ public: case DATA_ABOMINATION_KILLED: AbominationCount = value; break; - case DATA_POLARITY_SWITCHED: - PolaritySwitch = value; - break; } } @@ -447,13 +440,6 @@ public: if (AreAllEncoutersDone() && !playerDied) return true; return false; - // Criteria for achievement 2178: Shocking! (10-man) - case 7604: - // Criteria for achievement 2179: Shocking! (25-man) - case 7605: - if (!PolaritySwitch) - return true; - return false; } return false; } @@ -461,14 +447,14 @@ public: std::string GetSaveData() { std::ostringstream saveStream; - saveStream << GetBossSaveData() << gothikDoorState << ' ' << playerDied << ' ' << PolaritySwitch; + saveStream << GetBossSaveData() << gothikDoorState << ' ' << playerDied; return saveStream.str(); } void Load(const char * data) { std::istringstream loadStream(LoadBossState(data)); - uint32 temp, buff, buff2, buff3; + uint32 temp, buff, buff2; for (uint32 i = 0; i < MAX_BOSS_NUMBER; ++i) loadStream >> temp; @@ -477,8 +463,6 @@ public: gothikDoorState = GOState(buff); loadStream >> buff2; playerDied = buff2; - loadStream >> buff3; - PolaritySwitch = buff3; } }; diff --git a/src/server/scripts/Northrend/Naxxramas/naxxramas.h b/src/server/scripts/Northrend/Naxxramas/naxxramas.h index 34d465c775d..43393aff844 100644 --- a/src/server/scripts/Northrend/Naxxramas/naxxramas.h +++ b/src/server/scripts/Northrend/Naxxramas/naxxramas.h @@ -49,8 +49,6 @@ enum Data DATA_HORSEMEN2, DATA_HORSEMEN3, DATA_ABOMINATION_KILLED, - - DATA_POLARITY_SWITCHED, }; enum Data64 diff --git a/src/server/scripts/Outland/CMakeLists.txt b/src/server/scripts/Outland/CMakeLists.txt index ffd9332c8aa..229f7de72ec 100644 --- a/src/server/scripts/Outland/CMakeLists.txt +++ b/src/server/scripts/Outland/CMakeLists.txt @@ -45,6 +45,7 @@ set(scripts_STAT_SRCS Outland/CoilfangReservoir/underbog/boss_hungarfen.cpp Outland/CoilfangReservoir/underbog/boss_the_black_stalker.cpp Outland/shattrath_city.cpp + Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp Outland/TempestKeep/Mechanar/boss_pathaleon_the_calculator.cpp Outland/TempestKeep/Mechanar/boss_nethermancer_sepethrea.cpp Outland/TempestKeep/Mechanar/mechanar.h 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 new file mode 100644 index 00000000000..070c107e61d --- /dev/null +++ b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp @@ -0,0 +1,99 @@ +/* + * 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 . + */ + +//! TODO - Boss not scripted, just ported required spellscript from core + +enum Spells +{ + SPELL_POSITIVE_CHARGE = 39090, + SPELL_POSITIVE_CHARGE_STACK = 39089, + SPELL_NEGATIVE_CHARGE = 39093, + SPELL_NEGATIVE_CHARGE_STACK = 39092 +}; + +class spell_capacitus_polarity_shift : public SpellScriptLoader +{ + public: + spell_capacitus_polarity_shift() : SpellScriptLoader("spell_capacitus_polarity_shift") { } + + class spell_capacitus_polarity_shift_SpellScript : public SpellScript + { + PrepareSpellScript(spell_capacitus_polarity_shift_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_POSITIVE_CHARGE)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_POSITIVE_CHARGE_STACK)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_NEGATIVE_CHARGE)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_NEGATIVE_CHARGE_STACK)) + return false; + return true; + } + + void HandleTargets(std::list& targetList) + { + uint8 count = 0; + for (std::list::iterator ihit = targetList.begin(); ihit != targetList.end(); ++ihit) + if ((*ihit)->GetGUID() != GetCaster()->GetGUID()) + if (Player* target = (*ihit)->ToPlayer()) + if (target->HasAura(GetTriggeringSpell()->Id)) + ++count; + + if (count) + { + uint32 spellId = 0; + + if (GetSpellInfo()->Id == SPELL_POSITIVE_CHARGE) + spellId = SPELL_POSITIVE_CHARGE_STACK; + else // if (GetSpellInfo()->Id == SPELL_NEGATIVE_CHARGE) + spellId = SPELL_NEGATIVE_CHARGE_STACK; + + GetCaster()->SetAuraStack(spellId, GetCaster(), count); + } + } + + void HandleDamage(SpellEffIndex /*effIndex*/) + { + if (!GetTriggeringSpell()) + return; + + Unit* target = GetHitUnit(); + + if (target->HasAura(GetTriggeringSpell()->Id)) + SetHitDamage(0); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_capacitus_polarity_shift_SpellScript::HandleDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); + OnUnitTargetSelect += SpellUnitTargetFn(spell_capacitus_polarity_shift_SpellScript::HandleTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_capacitus_polarity_shift_SpellScript(); + } +}; + +void AddSC_boss_mechano_lord_capacitus() +{ + new spell_capacitus_polarity_shift(); +} -- cgit v1.2.3 From 2293d2d7dfab3470c6d1fbdb84d7df691ac93240 Mon Sep 17 00:00:00 2001 From: Machiavelli Date: Fri, 13 Jan 2012 16:43:49 +0100 Subject: Core/Movement: Prevent IdleMovementGenerator being put into MOTION_SLOT_IDLE and MOTION_SLOT_ACTIVE simultaneously --- src/server/game/Entities/Creature/Creature.cpp | 2 +- src/server/game/Entities/Creature/CreatureGroups.cpp | 2 +- src/server/game/Movement/MotionMaster.cpp | 9 ++++----- src/server/game/Movement/MotionMaster.h | 2 +- src/server/game/Server/Protocol/Handlers/PetHandler.cpp | 1 + src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp | 4 ++-- .../scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp | 3 ++- 7 files changed, 12 insertions(+), 11 deletions(-) (limited to 'src/server/scripts') diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 3e06f9e73db..ff627f78ea0 100755 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -715,7 +715,7 @@ void Creature::Motion_Initialize() i_motionMaster.Initialize(); } else if (m_formation->isFormed()) - i_motionMaster.MoveIdle(MOTION_SLOT_IDLE); //wait the order of leader + i_motionMaster.MoveIdle(); //wait the order of leader else i_motionMaster.Initialize(); } diff --git a/src/server/game/Entities/Creature/CreatureGroups.cpp b/src/server/game/Entities/Creature/CreatureGroups.cpp index 3a63c32fc1e..abf82dc5919 100755 --- a/src/server/game/Entities/Creature/CreatureGroups.cpp +++ b/src/server/game/Entities/Creature/CreatureGroups.cpp @@ -203,7 +203,7 @@ void CreatureGroup::FormationReset(bool dismiss) if (dismiss) itr->first->GetMotionMaster()->Initialize(); else - itr->first->GetMotionMaster()->MoveIdle(MOTION_SLOT_IDLE); + itr->first->GetMotionMaster()->MoveIdle(); sLog->outDebug(LOG_FILTER_UNITS, "Set %s movement for member GUID: %u", dismiss ? "default" : "idle", itr->first->GetGUIDLow()); } } diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index 51725c118ce..6660da146f0 100755 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -175,12 +175,11 @@ void MotionMaster::DelayedExpire() --i_top; } -void MotionMaster::MoveIdle(MovementSlot slot) +void MotionMaster::MoveIdle() { - //if (empty() || !isStatic(top())) - // push(&si_idleMovement); - if (!isStatic(Impl[slot])) - Mutate(&si_idleMovement, slot); + //! Should be preceded by MovementExpired or Clear if there's an overlying movementgenerator active + if (empty() || !isStatic(top())) + Mutate(&si_idleMovement, MOTION_SLOT_IDLE); } void MotionMaster::MoveRandom(float spawndist) diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h index 64026ea7b80..a972c3b06ce 100755 --- a/src/server/game/Movement/MotionMaster.h +++ b/src/server/game/Movement/MotionMaster.h @@ -142,7 +142,7 @@ class MotionMaster //: private std::stack DirectExpire(reset); } - void MoveIdle(MovementSlot slot = MOTION_SLOT_ACTIVE); + void MoveIdle(); void MoveTargetedHome(); void MoveRandom(float spawndist = 0.0f); void MoveFollow(Unit* target, float dist, float angle, MovementSlot slot = MOTION_SLOT_ACTIVE); diff --git a/src/server/game/Server/Protocol/Handlers/PetHandler.cpp b/src/server/game/Server/Protocol/Handlers/PetHandler.cpp index fc13ef802fd..68ce3153450 100755 --- a/src/server/game/Server/Protocol/Handlers/PetHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/PetHandler.cpp @@ -155,6 +155,7 @@ void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint16 spellid case COMMAND_STAY: //flat=1792 //STAY pet->AttackStop(); pet->InterruptNonMeleeSpells(false); + pet->GetMotionMaster()->Clear(false); pet->GetMotionMaster()->MoveIdle(); charmInfo->SetCommandState(COMMAND_STAY); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp index 25610341a2f..46c1cf425ed 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -638,7 +638,7 @@ class npc_spinestalker : public CreatureScript float moveTime = me->GetExactDist(&SpinestalkerFlyPos) / (me->GetSpeed(MOVE_FLIGHT) * 0.001f); me->m_Events.AddEvent(new FrostwyrmLandEvent(*me, SpinestalkerLandPos), me->m_Events.CalculateTime(uint64(moveTime) + 250)); me->SetDefaultMovementType(IDLE_MOTION_TYPE); - me->GetMotionMaster()->MoveIdle(MOTION_SLOT_IDLE); + me->GetMotionMaster()->MoveIdle(); me->StopMoving(); me->GetMotionMaster()->MovePoint(POINT_FROSTWYRM_FLY_IN, SpinestalkerFlyPos); } @@ -753,7 +753,7 @@ class npc_rimefang : public CreatureScript float moveTime = me->GetExactDist(&RimefangFlyPos) / (me->GetSpeed(MOVE_FLIGHT) * 0.001f); me->m_Events.AddEvent(new FrostwyrmLandEvent(*me, RimefangLandPos), me->m_Events.CalculateTime(uint64(moveTime) + 250)); me->SetDefaultMovementType(IDLE_MOTION_TYPE); - me->GetMotionMaster()->MoveIdle(MOTION_SLOT_IDLE); + me->GetMotionMaster()->MoveIdle(); me->StopMoving(); me->GetMotionMaster()->MovePoint(POINT_FROSTWYRM_FLY_IN, RimefangFlyPos); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp index 1fbdb7f4677..f2657e5b2ef 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -1656,7 +1656,8 @@ class npc_strangulate_vehicle : public CreatureScript switch (eventId) { case EVENT_TELEPORT: - me->GetMotionMaster()->MoveIdle(MOTION_SLOT_ACTIVE); + me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->MoveIdle(); if (TempSummon* summ = me->ToTempSummon()) { if (Unit* summoner = summ->GetSummoner()) -- cgit v1.2.3 From 6929fff8d63cc613008260ea65ffaf89401d6bac Mon Sep 17 00:00:00 2001 From: Venugh Date: Fri, 13 Jan 2012 21:13:18 +0100 Subject: Core/Scripts: Convert MillHouse Manastorm texts to creature_texts. --- .../world/2012_01_13_01_world_creature_texts.sql | 18 ++++++++ .../Outland/TempestKeep/arcatraz/arcatraz.cpp | 50 +++++++++++----------- 2 files changed, 44 insertions(+), 24 deletions(-) create mode 100644 sql/updates/world/2012_01_13_01_world_creature_texts.sql (limited to 'src/server/scripts') diff --git a/sql/updates/world/2012_01_13_01_world_creature_texts.sql b/sql/updates/world/2012_01_13_01_world_creature_texts.sql new file mode 100644 index 00000000000..f3edf965888 --- /dev/null +++ b/sql/updates/world/2012_01_13_01_world_creature_texts.sql @@ -0,0 +1,18 @@ +-- Remove old script text for npc_millhouse_manastorm +DELETE FROM `script_texts` WHERE `entry` IN (-1552010, -1552022); + +-- Add new creature_text for Millhouse ManaStorm +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +(20977, 0, 0, 'Where in Bonzo\'\'s brass buttons am I? And who are-- yaaghh, that\'\'s one mother of a headache!', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 1, 0, '"Lowly"? I don\'\'t care who you are friend, no one refers to the mighty Millhouse Manastorm as "Lowly"! I have no idea what goes on here, but I will gladly join your fight against this impudent imbecile! Prepare to defend yourself, cretin!', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 2, 0, 'I just need to get some things ready first. You guys go ahead and get started. I need to summon up some water...', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 3, 0, 'Fantastic! Next, some protective spells. Yes! Now we\'\'re cookin\'\'', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 4, 0, 'And of course i\'\'ll need some mana. You guys are gonna love this, just wait.', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 5, 0, 'Aaalllriiiight!! Who ordered up an extra large can of whoop-ass?', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 6, 0, 'I didn\'\'t even break a sweat on that one.', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 7, 0, 'You guys, feel free to jump in anytime.', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 8, 0, 'I\'\'m gonna light you up, sweet cheeks!', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 9, 0, 'Ice, ice, baby!', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 10, 0, 'Heal me! Oh, for the love of all that is holy, HEAL me! I\'\'m dying!', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 11, 0, 'You\'\'ll be hearing from my lawyer...', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 12, 0, 'Who\'\'s bad? Who\'\'s bad? That\'\'s right: we bad!', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'); \ No newline at end of file diff --git a/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp b/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp index 78acd88c894..50558d76ffc 100644 --- a/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp +++ b/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp @@ -38,19 +38,19 @@ EndContentData */ enum eMillhouseSays { - SAY_INTRO_1 = -1552010, - SAY_INTRO_2 = -1552011, - SAY_WATER = -1552012, - SAY_BUFFS = -1552013, - SAY_DRINK = -1552014, - SAY_READY = -1552015, - SAY_KILL_1 = -1552016, - SAY_KILL_2 = -1552017, - SAY_PYRO = -1552018, - SAY_ICEBLOCK = -1552019, - SAY_LOWHP = -1552020, - SAY_DEATH = -1552021, - SAY_COMPLETE = -1552022, + SAY_INTRO_1 = 0, + SAY_INTRO_2 = 1, + SAY_WATER = 2, + SAY_BUFFS = 3, + SAY_DRINK = 4, + SAY_READY = 5, + SAY_KILL_1 = 6, + SAY_KILL_2 = 7, + SAY_PYRO = 8, + SAY_ICEBLOCK = 9, + SAY_LOWHP = 10, + SAY_DEATH = 11, + SAY_COMPLETE = 12, }; enum eMillhouseSpells @@ -107,7 +107,7 @@ class npc_millhouse_manastorm : public CreatureScript Init = true; if (instance->GetData(TYPE_HARBINGERSKYRISS) == DONE) - DoScriptText(SAY_COMPLETE, me); + Talk(SAY_COMPLETE); } } @@ -126,12 +126,13 @@ class npc_millhouse_manastorm : public CreatureScript void KilledUnit(Unit* /*victim*/) { - DoScriptText(RAND(SAY_KILL_1, SAY_KILL_2), me); + Talk(SAY_KILL_1); + Talk(SAY_KILL_2); } void JustDied(Unit* /*victim*/) { - DoScriptText(SAY_DEATH, me); + Talk(SAY_DEATH); /*for questId 10886 (heroic mode only) if (instance && instance->GetData(TYPE_HARBINGERSKYRISS) != DONE) @@ -149,30 +150,30 @@ class npc_millhouse_manastorm : public CreatureScript switch (Phase) { case 1: - DoScriptText(SAY_INTRO_1, me); + Talk(SAY_INTRO_1); EventProgress_Timer = 18000; break; case 2: - DoScriptText(SAY_INTRO_2, me); + Talk(SAY_INTRO_2); EventProgress_Timer = 18000; break; case 3: - DoScriptText(SAY_WATER, me); + Talk(SAY_WATER); DoCast(me, SPELL_CONJURE_WATER); EventProgress_Timer = 7000; break; case 4: - DoScriptText(SAY_BUFFS, me); + Talk(SAY_BUFFS); DoCast(me, SPELL_ICE_ARMOR); EventProgress_Timer = 7000; break; case 5: - DoScriptText(SAY_DRINK, me); + Talk(SAY_DRINK); DoCast(me, SPELL_ARCANE_INTELLECT); EventProgress_Timer = 7000; break; case 6: - DoScriptText(SAY_READY, me); + Talk(SAY_READY); EventProgress_Timer = 6000; break; case 7: @@ -192,7 +193,7 @@ class npc_millhouse_manastorm : public CreatureScript return; if (!LowHp && HealthBelowPct(20)) { - DoScriptText(SAY_LOWHP, me); + Talk(SAY_LOWHP); LowHp = true; } @@ -201,7 +202,7 @@ class npc_millhouse_manastorm : public CreatureScript if (me->IsNonMeleeSpellCasted(false)) return; - DoScriptText(SAY_PYRO, me); + Talk(SAY_PYRO); DoCast(me->getVictim(), SPELL_PYROBLAST); Pyroblast_Timer = 40000; @@ -555,6 +556,7 @@ class mob_zerekethvoidzone : public CreatureScript return new mob_zerekethvoidzoneAI(creature); } }; + void AddSC_arcatraz() { new npc_millhouse_manastorm(); -- cgit v1.2.3 From e6b159f7ea13bed5054af4d370ed126b4622ccc4 Mon Sep 17 00:00:00 2001 From: Venugh Date: Fri, 13 Jan 2012 21:41:45 +0100 Subject: Core/Scripts: Correct rand change. thanks to Nayd for explain. --- sql/updates/world/2012_01_13_01_world_creature_texts.sql | 12 ++++++------ .../scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp | 16 +++++++--------- 2 files changed, 13 insertions(+), 15 deletions(-) (limited to 'src/server/scripts') diff --git a/sql/updates/world/2012_01_13_01_world_creature_texts.sql b/sql/updates/world/2012_01_13_01_world_creature_texts.sql index f3edf965888..317f4c862b3 100644 --- a/sql/updates/world/2012_01_13_01_world_creature_texts.sql +++ b/sql/updates/world/2012_01_13_01_world_creature_texts.sql @@ -10,9 +10,9 @@ INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`pr (20977, 4, 0, 'And of course i\'\'ll need some mana. You guys are gonna love this, just wait.', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), (20977, 5, 0, 'Aaalllriiiight!! Who ordered up an extra large can of whoop-ass?', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), (20977, 6, 0, 'I didn\'\'t even break a sweat on that one.', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), -(20977, 7, 0, 'You guys, feel free to jump in anytime.', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), -(20977, 8, 0, 'I\'\'m gonna light you up, sweet cheeks!', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), -(20977, 9, 0, 'Ice, ice, baby!', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), -(20977, 10, 0, 'Heal me! Oh, for the love of all that is holy, HEAL me! I\'\'m dying!', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), -(20977, 11, 0, 'You\'\'ll be hearing from my lawyer...', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), -(20977, 12, 0, 'Who\'\'s bad? Who\'\'s bad? That\'\'s right: we bad!', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'); \ No newline at end of file +(20977, 6, 1, 'You guys, feel free to jump in anytime.', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 7, 0, 'I\'\'m gonna light you up, sweet cheeks!', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 8, 0, 'Ice, ice, baby!', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 9, 0, 'Heal me! Oh, for the love of all that is holy, HEAL me! I\'\'m dying!', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 10, 0, 'You\'\'ll be hearing from my lawyer...', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 11, 0, 'Who\'\'s bad? Who\'\'s bad? That\'\'s right: we bad!', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'); diff --git a/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp b/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp index 50558d76ffc..0e1619ce723 100644 --- a/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp +++ b/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp @@ -44,13 +44,12 @@ enum eMillhouseSays SAY_BUFFS = 3, SAY_DRINK = 4, SAY_READY = 5, - SAY_KILL_1 = 6, - SAY_KILL_2 = 7, - SAY_PYRO = 8, - SAY_ICEBLOCK = 9, - SAY_LOWHP = 10, - SAY_DEATH = 11, - SAY_COMPLETE = 12, + SAY_KILL = 6, + SAY_PYRO = 7, + SAY_ICEBLOCK = 8, + SAY_LOWHP = 9, + SAY_DEATH = 10, + SAY_COMPLETE = 11, }; enum eMillhouseSpells @@ -126,8 +125,7 @@ class npc_millhouse_manastorm : public CreatureScript void KilledUnit(Unit* /*victim*/) { - Talk(SAY_KILL_1); - Talk(SAY_KILL_2); + Talk(SAY_KILL); } void JustDied(Unit* /*victim*/) -- cgit v1.2.3 From d359c87908303590354a3bd78b36316bf554e9f2 Mon Sep 17 00:00:00 2001 From: Venugh Date: Fri, 13 Jan 2012 21:59:21 +0100 Subject: Core/Scripts: Convert Warden Mellichar texts to creature_texts. --- .../world/2012_01_13_25_world_creature_texts.sql | 12 ++++++++ .../Outland/TempestKeep/arcatraz/arcatraz.cpp | 36 +++++++++++----------- 2 files changed, 30 insertions(+), 18 deletions(-) create mode 100644 sql/updates/world/2012_01_13_25_world_creature_texts.sql (limited to 'src/server/scripts') diff --git a/sql/updates/world/2012_01_13_25_world_creature_texts.sql b/sql/updates/world/2012_01_13_25_world_creature_texts.sql new file mode 100644 index 00000000000..252a6c75da3 --- /dev/null +++ b/sql/updates/world/2012_01_13_25_world_creature_texts.sql @@ -0,0 +1,12 @@ +-- Remove old script text for npc_warden_mellichar +DELETE FROM `script_texts` WHERE `entry` IN (-1552023, -1552030); + +-- Add new creature_text for Warden Mellichar +(20904, 0, 0, 'I knew the prince would be angry but, I... I have not been myself. I had to let them out! The great one speaks to me, you see. Wait--outsiders. Kael\'\'thas did not send you! Good... I\'\'ll just tell the prince you released the prisoners!', 0, 0, 100, 0, 0, 0, 'Warden Mellichar'), +(20904, 1, 0, 'The naaru kept some of the most dangerous beings in existence here in these cells. Let me introduce you to another...', 0, 0, 100, 0, 0, 0, 'Warden Mellichar'), +(20904, 2, 0, 'Yes, yes... another! Your will is mine!', 0, 0, 100, 0, 0, 0, 'Warden Mellichar'), +(20904, 3, 0, 'Behold another terrifying creature of incomprehensible power!', 0, 0, 100, 0, 0, 0, 'Warden Mellichar'), +(20904, 4, 0, 'What is this? A lowly gnome? I will do better, O\'\'great one.', 0, 0, 100, 0, 0, 0, 'Warden Mellichar'), +(20904, 5, 0, 'Anarchy! Bedlam! Oh, you are so wise! Yes, I see it now, of course!', 0, 0, 100, 0, 0, 0, 'Warden Mellichar'), +(20904, 6, 0, 'One final cell remains. Yes, O\'\'great one, right away!', 0, 0, 100, 0, 0, 0, 'Warden Mellichar'), +(20904, 7, 0, 'Welcome, O\'\'great one. I am your humble servant.', 0, 0, 100, 0, 0, 0, 'Warden Mellichar'); diff --git a/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp b/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp index 0e1619ce723..ce9bd57e829 100644 --- a/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp +++ b/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp @@ -231,14 +231,14 @@ class npc_millhouse_manastorm : public CreatureScript enum eWardenSays { - YELL_INTRO1 = -1552023, - YELL_INTRO2 = -1552024, - YELL_RELEASE1 = -1552025, - YELL_RELEASE2A = -1552026, - YELL_RELEASE2B = -1552027, - YELL_RELEASE3 = -1552028, - YELL_RELEASE4 = -1552029, - YELL_WELCOME = -1552030, + YELL_INTRO1 = 0, + YELL_INTRO2 = 1, + YELL_RELEASE1 = 2, + YELL_RELEASE2A = 3, + YELL_RELEASE2B = 4, + YELL_RELEASE3 = 5, + YELL_RELEASE4 = 6, + YELL_WELCOME = 7, }; enum eWardenUnits @@ -273,10 +273,10 @@ class npc_warden_mellichar : public CreatureScript { public: - npc_warden_mellichar() - : CreatureScript("npc_warden_mellichar") + npc_warden_mellichar() : CreatureScript("npc_warden_mellichar") { } + struct npc_warden_mellicharAI : public ScriptedAI { npc_warden_mellicharAI(Creature* creature) : ScriptedAI(creature) @@ -329,7 +329,7 @@ class npc_warden_mellichar : public CreatureScript void EnterCombat(Unit* /*who*/) { - DoScriptText(YELL_INTRO1, me); + Talk(YELL_INTRO1); DoCast(me, SPELL_BUBBLE_VISUAL); if (instance) @@ -436,7 +436,7 @@ class npc_warden_mellichar : public CreatureScript me->SummonCreature(ENTRY_MILLHOUSE, 413.292f, -148.378f, 42.56f, 6.27f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000); break; case 4: - DoScriptText(YELL_RELEASE2B, me); + Talk(YELL_RELEASE2B); break; case 5: switch (urand(0, 1)) @@ -462,7 +462,7 @@ class npc_warden_mellichar : public CreatureScript break; case 7: me->SummonCreature(ENTRY_SKYRISS, 445.763f, -191.639f, 44.64f, 1.60f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000); - DoScriptText(YELL_WELCOME, me); + Talk(YELL_WELCOME); break; } CanSpawn = false; @@ -473,17 +473,17 @@ class npc_warden_mellichar : public CreatureScript switch (Phase) { case 1: - DoScriptText(YELL_INTRO2, me); + Talk(YELL_INTRO2); EventProgress_Timer = 10000; ++Phase; break; case 2: - DoScriptText(YELL_RELEASE1, me); + Talk(YELL_RELEASE1); DoPrepareForPhase(); EventProgress_Timer = 7000; break; case 3: - DoScriptText(YELL_RELEASE2A, me); + Talk(YELL_RELEASE2A); DoPrepareForPhase(); EventProgress_Timer = 10000; break; @@ -492,12 +492,12 @@ class npc_warden_mellichar : public CreatureScript EventProgress_Timer = 15000; break; case 5: - DoScriptText(YELL_RELEASE3, me); + Talk(YELL_RELEASE3); DoPrepareForPhase(); EventProgress_Timer = 15000; break; case 6: - DoScriptText(YELL_RELEASE4, me); + Talk(YELL_RELEASE4); DoPrepareForPhase(); EventProgress_Timer = 15000; break; -- cgit v1.2.3 From b242a19ad5d4d560febde8a35f2cb183823869e4 Mon Sep 17 00:00:00 2001 From: Venugh Date: Fri, 13 Jan 2012 22:02:04 +0100 Subject: Core/Scripts: remove define from arcatraz. --- src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/server/scripts') diff --git a/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp b/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp index ce9bd57e829..db95f60f556 100644 --- a/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp +++ b/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp @@ -523,14 +523,16 @@ class npc_warden_mellichar : public CreatureScript # mob_zerekethvoidzone (this script probably not needed in future -> `creature_template_addon`.`auras`='36120 0') #####*/ -#define SPELL_VOID_ZONE_DAMAGE 36120 +enum ZerekethSpell +{ + SPELL_VOID_ZONE_DAMAGE = 36120, +}; class mob_zerekethvoidzone : public CreatureScript { public: - mob_zerekethvoidzone() - : CreatureScript("mob_zerekethvoidzone") + mob_zerekethvoidzone() : CreatureScript("mob_zerekethvoidzone") { } struct mob_zerekethvoidzoneAI : public ScriptedAI @@ -561,4 +563,3 @@ void AddSC_arcatraz() new npc_warden_mellichar(); new mob_zerekethvoidzone(); } - -- cgit v1.2.3 From b878e68f8aea64ac5071aac1d319aa968994cd05 Mon Sep 17 00:00:00 2001 From: svannon Date: Fri, 13 Jan 2012 22:13:10 +0100 Subject: Core/Script: remove unused script --- .../scripts/EasternKingdoms/silverpine_forest.cpp | 71 +--------------------- 1 file changed, 1 insertion(+), 70 deletions(-) (limited to 'src/server/scripts') diff --git a/src/server/scripts/EasternKingdoms/silverpine_forest.cpp b/src/server/scripts/EasternKingdoms/silverpine_forest.cpp index e166013a4b2..4d897c4f3b8 100644 --- a/src/server/scripts/EasternKingdoms/silverpine_forest.cpp +++ b/src/server/scripts/EasternKingdoms/silverpine_forest.cpp @@ -19,12 +19,11 @@ /* ScriptData SDName: Silverpine_Forest SD%Complete: 100 -SDComment: Quest support: 1886, 435, 452 +SDComment: Quest support: 435, 452 SDCategory: Silverpine Forest EndScriptData */ /* ContentData -npc_astor_hadren npc_deathstalker_erland pyrewood_ambush EndContentData */ @@ -32,73 +31,6 @@ EndContentData */ #include "ScriptPCH.h" #include "ScriptedEscortAI.h" -/*###### -## npc_astor_hadren -######*/ - -#define GOSSIP_HAH "You're Astor Hadren, right?" -#define GOSSIP_SAH "You've got something I need, Astor. And I'll be taking it now." - -class npc_astor_hadren : public CreatureScript -{ -public: - npc_astor_hadren() : CreatureScript("npc_astor_hadren") { } - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_astor_hadrenAI(creature); - } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*uiSender*/, uint32 uiAction) - { - player->PlayerTalkClass->ClearMenus(); - switch (uiAction) - { - case GOSSIP_ACTION_INFO_DEF + 1: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SAH, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(624, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - player->CLOSE_GOSSIP_MENU(); - creature->setFaction(21); - if (player) - CAST_AI(npc_astor_hadren::npc_astor_hadrenAI, creature->AI())->AttackStart(player); - break; - } - return true; - } - - bool OnGossipHello(Player* player, Creature* creature) - { - if (player->GetQuestStatus(1886) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HAH, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - player->SEND_GOSSIP_MENU(623, creature->GetGUID()); - - return true; - } - - struct npc_astor_hadrenAI : public ScriptedAI - { - npc_astor_hadrenAI(Creature* c) : ScriptedAI(c) {} - - void Reset() - { - me->setFaction(68); - } - - void EnterCombat(Unit* /*who*/) - { - } - - void JustDied(Unit* /*who*/) - { - me->setFaction(68); - } - }; - -}; - /*###### ## npc_deathstalker_erland ######*/ @@ -386,7 +318,6 @@ public: void AddSC_silverpine_forest() { - new npc_astor_hadren(); new npc_deathstalker_erland(); new pyrewood_ambush(); } -- cgit v1.2.3 From 46d1736d0dcbed8d41a892adb514ae99c7392de3 Mon Sep 17 00:00:00 2001 From: Venugh Date: Sat, 14 Jan 2012 00:20:03 +0100 Subject: Core/Scripts: Convert Torek script_texts to creature_text. Apply coding style in it. --- .../world/2012_01_13_06_world_creature_text.sql | 10 +++++ src/server/scripts/Kalimdor/ashenvale.cpp | 46 +++++++++++++--------- 2 files changed, 37 insertions(+), 19 deletions(-) create mode 100644 sql/updates/world/2012_01_13_06_world_creature_text.sql (limited to 'src/server/scripts') diff --git a/sql/updates/world/2012_01_13_06_world_creature_text.sql b/sql/updates/world/2012_01_13_06_world_creature_text.sql new file mode 100644 index 00000000000..8ad3ab63443 --- /dev/null +++ b/sql/updates/world/2012_01_13_06_world_creature_text.sql @@ -0,0 +1,10 @@ +-- Remove old script text for npc_torek +DELETE FROM `script_texts` WHERE `entry` IN (-1000106, -1000110); + +-- Add creature texts for Torek +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +(12858, 0, 0, 'Everyone ready?', 0, 0, 100, 0, 0, 0, 'Torek'), +(12858, 1, 0, 'Ok, Lets move out!', 0, 0, 100, 0, 0, 0, 'Torek'), +(12858, 2, 0, 'Prepare yourselves. Silverwing is just around the bend.', 0, 0, 100, 0, 0, 0, 'Torek'), +(12858, 3, 0, 'Silverwing is ours!', 0, 0, 100, 0, 0, 0, 'Torek'), +(12858, 4, 0, 'Go report that the outpost is taken. We will remain here.', 0, 0, 100, 0, 0, 0, 'Torek'); diff --git a/src/server/scripts/Kalimdor/ashenvale.cpp b/src/server/scripts/Kalimdor/ashenvale.cpp index e27d7287179..eacf5340f62 100644 --- a/src/server/scripts/Kalimdor/ashenvale.cpp +++ b/src/server/scripts/Kalimdor/ashenvale.cpp @@ -35,34 +35,42 @@ EndContentData */ # npc_torek ####*/ -#define SAY_READY -1000106 -#define SAY_MOVE -1000107 -#define SAY_PREPARE -1000108 -#define SAY_WIN -1000109 -#define SAY_END -1000110 +enum eTorekSays +{ + SAY_READY = 0, + SAY_MOVE = 1, + SAY_PREPARE = 2, + SAY_WIN = 3, + SAY_END = 4, +}; -#define SPELL_REND 11977 -#define SPELL_THUNDERCLAP 8078 +enum eTorekSpells +{ + SPELL_REND = 11977, + SPELL_THUNDERCLAP = 8078, +}; -#define QUEST_TOREK_ASSULT 6544 +enum +{ + QUEST_TOREK_ASSULT = 6544, -#define ENTRY_SPLINTERTREE_RAIDER 12859 -#define ENTRY_DURIEL 12860 -#define ENTRY_SILVERWING_SENTINEL 12896 -#define ENTRY_SILVERWING_WARRIOR 12897 + ENTRY_SPLINTERTREE_RAIDER = 12859, + ENTRY_DURIEL = 12860, + ENTRY_SILVERWING_SENTINEL = 12896, + ENTRY_SILVERWING_WARRIOR = 12897, +}; class npc_torek : public CreatureScript { public: - npc_torek() - : CreatureScript("npc_torek") + npc_torek() : CreatureScript("npc_torek") { } struct npc_torekAI : public npc_escortAI { - npc_torekAI(Creature* c) : npc_escortAI(c) {} + npc_torekAI(Creature* creature) : npc_escortAI(creature) {} uint32 Rend_Timer; uint32 Thunderclap_Timer; @@ -78,10 +86,10 @@ class npc_torek : public CreatureScript switch (i) { case 1: - DoScriptText(SAY_MOVE, me, player); + Talk(SAY_MOVE, player->GetGUID()); break; case 8: - DoScriptText(SAY_PREPARE, me, player); + Talk(SAY_PREPARE, player->GetGUID()); break; case 19: //TODO: verify location and creatures amount. @@ -96,7 +104,7 @@ class npc_torek : public CreatureScript player->GroupEventHappens(QUEST_TOREK_ASSULT, me); break; case 21: - DoScriptText(SAY_END, me, player); + Talk(SAY_END, player->GetGUID()); break; } } @@ -148,7 +156,7 @@ class npc_torek : public CreatureScript if (quest->GetQuestId() == QUEST_TOREK_ASSULT) { //TODO: find companions, make them follow Torek, at any time (possibly done by core/database in future?) - DoScriptText(SAY_READY, creature, player); + creature->AI()->Talk(SAY_READY, player->GetGUID()); creature->setFaction(113); if (npc_escortAI* pEscortAI = CAST_AI(npc_torekAI, creature->AI())) -- cgit v1.2.3 From ab923f71579f7e7bc35ac57f1acf0438ae47f7e6 Mon Sep 17 00:00:00 2001 From: Venugh Date: Sat, 14 Jan 2012 00:22:26 +0100 Subject: Core/Scripts: typo from last commit. thx Discovered. --- src/server/scripts/Kalimdor/ashenvale.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/server/scripts') diff --git a/src/server/scripts/Kalimdor/ashenvale.cpp b/src/server/scripts/Kalimdor/ashenvale.cpp index eacf5340f62..0fba8b2f1ab 100644 --- a/src/server/scripts/Kalimdor/ashenvale.cpp +++ b/src/server/scripts/Kalimdor/ashenvale.cpp @@ -35,7 +35,7 @@ EndContentData */ # npc_torek ####*/ -enum eTorekSays +enum TorekSays { SAY_READY = 0, SAY_MOVE = 1, @@ -44,7 +44,7 @@ enum eTorekSays SAY_END = 4, }; -enum eTorekSpells +enum TorekSpells { SPELL_REND = 11977, SPELL_THUNDERCLAP = 8078, -- cgit v1.2.3 From ebfa6bbcd18a93ef6516197040de670696f2c96d Mon Sep 17 00:00:00 2001 From: Nay Date: Sat, 14 Jan 2012 01:53:21 +0000 Subject: SQL: Fix remaining errors... *sighs* --- sql/updates/world/2012_01_13_03_gossip_menu.sql | 4 ++-- .../world/2012_01_13_04_world_creature_texts.sql | 27 +++++++++++----------- .../world/2012_01_13_05_world_creature_texts.sql | 17 +++++++------- .../world/2012_01_13_06_world_creature_text.sql | 11 +++++---- src/server/scripts/Kalimdor/ashenvale.cpp | 2 +- 5 files changed, 32 insertions(+), 29 deletions(-) (limited to 'src/server/scripts') diff --git a/sql/updates/world/2012_01_13_03_gossip_menu.sql b/sql/updates/world/2012_01_13_03_gossip_menu.sql index 26788eeb123..98dda69bf1a 100644 --- a/sql/updates/world/2012_01_13_03_gossip_menu.sql +++ b/sql/updates/world/2012_01_13_03_gossip_menu.sql @@ -17,7 +17,7 @@ INSERT INTO `gossip_menu` (`entry`,`text_id`) VALUES (8696,10946); -- Creature Gossip_menu_id Update from sniff UPDATE `creature_template` SET `gossip_menu_id`=8701 WHERE `entry`=23309; -- Creature Gossip_menu_option Update from sniff -DELETE FROM `gossip_menu_option` WHERE `menu_id` IN (8701,8695,8700,8699,8698,8697) AND `id` IN (0); +DELETE FROM `gossip_menu_option` WHERE `menu_id` IN (8701,8695,8700,8699,8698,8697) AND `id`=0; INSERT INTO `gossip_menu_option` (`menu_id`,`id`,`option_icon`,`option_text`,`option_id`,`npc_option_npcflag`,`action_menu_id`,`action_poi_id`,`box_coded`,`box_money`,`box_text`) VALUES (8701,0,0, 'I am here for you, overseer.',1,1,8695,0,0,0, ''), (8695,0,0, 'How dare you question an overseer of the Dragonmaw!',1,1,8700,0,0,0, ''), @@ -52,7 +52,7 @@ INSERT INTO `creature_loot_template` (`entry`, `item`, `ChanceOrQuestChance`, `l (23286,32726,15,1,0,1,1), (23324,32726,15,1,0,1,1); -- Loot Conditions by mweinelt -DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=1 AND `SourceGroup` IN (23286,23324); AND `SourceEntry`=32726; +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=1 AND `SourceGroup` IN (23286,23324) AND `SourceEntry`=32726; INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES (1,23286,32726,0,5,1015,4,0,0, '', 'Murkblood Escape Plans - when Netherwing friendly'), (1,23324,32726,0,5,1015,4,0,0, '', 'Murkblood Escape Plans - when Netherwing friendly'), diff --git a/sql/updates/world/2012_01_13_04_world_creature_texts.sql b/sql/updates/world/2012_01_13_04_world_creature_texts.sql index eb6e849fc6a..ffab5673873 100644 --- a/sql/updates/world/2012_01_13_04_world_creature_texts.sql +++ b/sql/updates/world/2012_01_13_04_world_creature_texts.sql @@ -2,17 +2,18 @@ DELETE FROM `script_texts` WHERE `entry` IN (-1552010, -1552022); -- Add new creature_text for Millhouse ManaStorm +DELETE FROM `creature_text` WHERE `entry`=20977; INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES -(20977, 0, 0, 'Where in Bonzo\'\'s brass buttons am I? And who are-- yaaghh, that\'s one mother of a headache!', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), -(20977, 1, 0, '"Lowly"? I don\'t care who you are friend, no one refers to the mighty Millhouse Manastorm as "Lowly"! I have no idea what goes on here, but I will gladly join your fight against this impudent imbecile! Prepare to defend yourself, cretin!', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), -(20977, 2, 0, 'I just need to get some things ready first. You guys go ahead and get started. I need to summon up some water...', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), -(20977, 3, 0, 'Fantastic! Next, some protective spells. Yes! Now we\'re cookin\'', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), -(20977, 4, 0, 'And of course i\'ll need some mana. You guys are gonna love this, just wait.', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), -(20977, 5, 0, 'Aaalllriiiight!! Who ordered up an extra large can of whoop-ass?', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), -(20977, 6, 0, 'I didn\'t even break a sweat on that one.', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), -(20977, 6, 1, 'You guys, feel free to jump in anytime.', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), -(20977, 7, 0, 'I\'m gonna light you up, sweet cheeks!', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), -(20977, 8, 0, 'Ice, ice, baby!', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), -(20977, 9, 0, 'Heal me! Oh, for the love of all that is holy, HEAL me! I\'m dying!', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), -(20977, 10, 0, 'You\'ll be hearing from my lawyer...', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), -(20977, 11, 0, 'Who\'s bad? Who\'s bad? That\'s right: we bad!', 0, 0, 100, 0, 0, 0, 'Millhouse Manastorm'); +(20977, 0, 0, 'Where in Bonzo''s brass buttons am I? And who are-- yaaghh, that''s one mother of a headache!', 12, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 1, 0, '"Lowly"? I don''t care who you are friend, no one refers to the mighty Millhouse Manastorm as "Lowly"! I have no idea what goes on here, but I will gladly join your fight against this impudent imbecile! Prepare to defend yourself, cretin!', 12, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 2, 0, 'I just need to get some things ready first. You guys go ahead and get started. I need to summon up some water...', 12, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 3, 0, 'Fantastic! Next, some protective spells. Yes! Now we''re cookin''', 12, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 4, 0, 'And of course I''ll need some mana. You guys are gonna love this, just wait.', 12, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 5, 0, 'Aaalllriiiight!! Who ordered up an extra large can of whoop-ass?', 12, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 6, 0, 'I didn''t even break a sweat on that one.', 12, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 6, 1, 'You guys, feel free to jump in anytime.', 12, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 7, 0, 'I''m gonna light you up, sweet cheeks!', 12, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 8, 0, 'Ice, ice, baby!', 12, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 9, 0, 'Heal me! Oh, for the love of all that is holy, HEAL me! I''m dying!', 12, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 10, 0, 'You''ll be hearing from my lawyer...', 12, 0, 100, 0, 0, 0, 'Millhouse Manastorm'), +(20977, 11, 0, 'Who''s bad? Who''s bad? That''s right: we bad!', 12, 0, 100, 0, 0, 0, 'Millhouse Manastorm'); diff --git a/sql/updates/world/2012_01_13_05_world_creature_texts.sql b/sql/updates/world/2012_01_13_05_world_creature_texts.sql index a606f9a84e5..87aee698a11 100644 --- a/sql/updates/world/2012_01_13_05_world_creature_texts.sql +++ b/sql/updates/world/2012_01_13_05_world_creature_texts.sql @@ -2,13 +2,14 @@ DELETE FROM `script_texts` WHERE `entry` IN (-1552023, -1552030); -- Add new creature_text for Warden Mellichar +DELETE FROM `creature_text` WHERE `entry`=20904; INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES -(20904, 0, 0, 'I knew the prince would be angry but, I... I have not been myself. I had to let them out! The great one speaks to me, you see. Wait--outsiders. Kael\'thas did not send you! Good... I\'ll just tell the prince you released the prisoners!', 0, 0, 100, 0, 0, 0, 'Warden Mellichar'), -(20904, 1, 0, 'The naaru kept some of the most dangerous beings in existence here in these cells. Let me introduce you to another...', 0, 0, 100, 0, 0, 0, 'Warden Mellichar'), -(20904, 2, 0, 'Yes, yes... another! Your will is mine!', 0, 0, 100, 0, 0, 0, 'Warden Mellichar'), -(20904, 3, 0, 'Behold another terrifying creature of incomprehensible power!', 0, 0, 100, 0, 0, 0, 'Warden Mellichar'), -(20904, 4, 0, 'What is this? A lowly gnome? I will do better, O\'great one.', 0, 0, 100, 0, 0, 0, 'Warden Mellichar'), -(20904, 5, 0, 'Anarchy! Bedlam! Oh, you are so wise! Yes, I see it now, of course!', 0, 0, 100, 0, 0, 0, 'Warden Mellichar'), -(20904, 6, 0, 'One final cell remains. Yes, O\'great one, right away!', 0, 0, 100, 0, 0, 0, 'Warden Mellichar'), -(20904, 7, 0, 'Welcome, O\'great one. I am your humble servant.', 0, 0, 100, 0, 0, 0, 'Warden Mellichar'); +(20904, 0, 0, 'I knew the prince would be angry but, I... I have not been myself. I had to let them out! The great one speaks to me, you see. Wait--outsiders. Kael''thas did not send you! Good... I''ll just tell the prince you released the prisoners!', 14, 0, 100, 0, 0, 0, 'Warden Mellichar'), +(20904, 1, 0, 'The naaru kept some of the most dangerous beings in existence here in these cells. Let me introduce you to another...', 14, 0, 100, 0, 0, 0, 'Warden Mellichar'), +(20904, 2, 0, 'Yes, yes... another! Your will is mine!', 14, 0, 100, 0, 0, 0, 'Warden Mellichar'), +(20904, 3, 0, 'Behold another terrifying creature of incomprehensible power!', 14, 0, 100, 0, 0, 0, 'Warden Mellichar'), +(20904, 4, 0, 'What is this? A lowly gnome? I will do better, O great one.', 14, 0, 100, 0, 0, 0, 'Warden Mellichar'), +(20904, 5, 0, 'Anarchy! Bedlam! Oh, you are so wise! Yes, I see it now, of course!', 14, 0, 100, 0, 0, 0, 'Warden Mellichar'), +(20904, 6, 0, 'One final cell remains. Yes, O great one, right away!', 14, 0, 100, 0, 0, 0, 'Warden Mellichar'), +(20904, 7, 0, 'Welcome, O great one. I am your humble servant.', 14, 0, 100, 0, 0, 0, 'Warden Mellichar'); diff --git a/sql/updates/world/2012_01_13_06_world_creature_text.sql b/sql/updates/world/2012_01_13_06_world_creature_text.sql index 8ad3ab63443..99429cfad5f 100644 --- a/sql/updates/world/2012_01_13_06_world_creature_text.sql +++ b/sql/updates/world/2012_01_13_06_world_creature_text.sql @@ -2,9 +2,10 @@ DELETE FROM `script_texts` WHERE `entry` IN (-1000106, -1000110); -- Add creature texts for Torek +DELETE FROM `creature_text` WHERE `entry`=12858; INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES -(12858, 0, 0, 'Everyone ready?', 0, 0, 100, 0, 0, 0, 'Torek'), -(12858, 1, 0, 'Ok, Lets move out!', 0, 0, 100, 0, 0, 0, 'Torek'), -(12858, 2, 0, 'Prepare yourselves. Silverwing is just around the bend.', 0, 0, 100, 0, 0, 0, 'Torek'), -(12858, 3, 0, 'Silverwing is ours!', 0, 0, 100, 0, 0, 0, 'Torek'), -(12858, 4, 0, 'Go report that the outpost is taken. We will remain here.', 0, 0, 100, 0, 0, 0, 'Torek'); +(12858, 0, 0, 'Everyone ready?', 12, 0, 100, 0, 0, 0, 'Torek'), +(12858, 1, 0, 'Ok, Lets move out!', 12, 0, 100, 0, 0, 0, 'Torek'), +(12858, 2, 0, 'Prepare yourselves. Silverwing is just around the bend.', 12, 0, 100, 0, 0, 0, 'Torek'), +(12858, 3, 0, 'Silverwing is ours!', 12, 0, 100, 0, 0, 0, 'Torek'), +(12858, 4, 0, 'Go report that the outpost is taken. We will remain here.', 12, 0, 100, 0, 0, 0, 'Torek'); diff --git a/src/server/scripts/Kalimdor/ashenvale.cpp b/src/server/scripts/Kalimdor/ashenvale.cpp index 0fba8b2f1ab..5d26653a1a8 100644 --- a/src/server/scripts/Kalimdor/ashenvale.cpp +++ b/src/server/scripts/Kalimdor/ashenvale.cpp @@ -50,7 +50,7 @@ enum TorekSpells SPELL_THUNDERCLAP = 8078, }; -enum +enum TorekMisc { QUEST_TOREK_ASSULT = 6544, -- cgit v1.2.3 From d9a75b38281a080e01a50466175d8f94373a5386 Mon Sep 17 00:00:00 2001 From: zxbiohazardzx Date: Sat, 14 Jan 2012 09:40:00 +0100 Subject: Core/Scripts: remove obsolete scripts for Orsonn and Kodian related to #4788 --- src/server/scripts/Northrend/grizzly_hills.cpp | 107 ------------------------- 1 file changed, 107 deletions(-) (limited to 'src/server/scripts') diff --git a/src/server/scripts/Northrend/grizzly_hills.cpp b/src/server/scripts/Northrend/grizzly_hills.cpp index de0c6a909ad..9eb73463795 100644 --- a/src/server/scripts/Northrend/grizzly_hills.cpp +++ b/src/server/scripts/Northrend/grizzly_hills.cpp @@ -16,115 +16,9 @@ * with this program. If not, see . */ -/* ScriptData -SDName: Grizzly_Hills -SD%Complete: 80 -SDComment: Quest support: 12231, 12247 -SDCategory: Grizzly Hills -EndScriptData */ - -/* ContentData -npc_orsonn_and_kodian -EndContentData */ - #include "ScriptPCH.h" #include "ScriptedEscortAI.h" -#define GOSSIP_ITEM1 "You're free to go Orsonn, but first tell me what's wrong with the furbolg." -#define GOSSIP_ITEM2 "What happened then?" -#define GOSSIP_ITEM3 "Thank you, Son of Ursoc. I'll see what can be done." -#define GOSSIP_ITEM4 "Who was this stranger?" -#define GOSSIP_ITEM5 "Thank you, Kodian. I'll do what I can." - -enum eEnums -{ - GOSSIP_TEXTID_ORSONN1 = 12793, - GOSSIP_TEXTID_ORSONN2 = 12794, - GOSSIP_TEXTID_ORSONN3 = 12796, - - GOSSIP_TEXTID_KODIAN1 = 12797, - GOSSIP_TEXTID_KODIAN2 = 12798, - - NPC_ORSONN = 27274, - NPC_KODIAN = 27275, - - //trigger creatures - NPC_ORSONN_CREDIT = 27322, - NPC_KODIAN_CREDIT = 27321, - - QUEST_CHILDREN_OF_URSOC = 12247, - QUEST_THE_BEAR_GODS_OFFSPRING = 12231 -}; - -class npc_orsonn_and_kodian : public CreatureScript -{ -public: - npc_orsonn_and_kodian() : CreatureScript("npc_orsonn_and_kodian") { } - - bool OnGossipHello(Player* player, Creature* creature) - { - if (creature->isQuestGiver()) - player->PrepareQuestMenu(creature->GetGUID()); - - if (player->GetQuestStatus(QUEST_CHILDREN_OF_URSOC) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(QUEST_THE_BEAR_GODS_OFFSPRING) == QUEST_STATUS_INCOMPLETE) - { - switch (creature->GetEntry()) - { - case NPC_ORSONN: - if (!player->GetReqKillOrCastCurrentCount(QUEST_CHILDREN_OF_URSOC, NPC_ORSONN_CREDIT) || !player->GetReqKillOrCastCurrentCount(QUEST_THE_BEAR_GODS_OFFSPRING, NPC_ORSONN_CREDIT)) - { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ORSONN1, creature->GetGUID()); - return true; - } - break; - case NPC_KODIAN: - if (!player->GetReqKillOrCastCurrentCount(QUEST_CHILDREN_OF_URSOC, NPC_KODIAN_CREDIT) || !player->GetReqKillOrCastCurrentCount(QUEST_THE_BEAR_GODS_OFFSPRING, NPC_KODIAN_CREDIT)) - { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_KODIAN1, creature->GetGUID()); - return true; - } - break; - } - } - - player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); - return true; - } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*uiSender*/, uint32 uiAction) - { - player->PlayerTalkClass->ClearMenus(); - switch (uiAction) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ORSONN2, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_ORSONN3, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->CLOSE_GOSSIP_MENU(); - player->TalkedToCreature(NPC_ORSONN_CREDIT, creature->GetGUID()); - break; - - case GOSSIP_ACTION_INFO_DEF+4: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_KODIAN2, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - player->CLOSE_GOSSIP_MENU(); - player->TalkedToCreature(NPC_KODIAN_CREDIT, creature->GetGUID()); - break; - } - - return true; - } -}; - /*###### ## Quest 12027: Mr. Floppy's Perilous Adventure ######*/ @@ -801,7 +695,6 @@ public: void AddSC_grizzly_hills() { - new npc_orsonn_and_kodian; new npc_emily; new npc_mrfloppy; new npc_outhouse_bunny; -- cgit v1.2.3 From dbbac0bdaae4b6d8a0125999962c4a686092bd80 Mon Sep 17 00:00:00 2001 From: Machiavelli Date: Sat, 14 Jan 2012 15:34:41 +0100 Subject: Core/Movement: Implement spline movement subsystem. Spline movement controls movements of server-side controlled units (monster movement, taxi movement, etc). Proper implementation of effects such as charge, jump, cyclic movement will rely on it. However, need improve our states system before. Technical changes: * Added linear, catmullrom and bezier3 splines which based on client's algorthims. They can be reused for proper transport position interpolation. * Precission increased. There are no more position desync issues since client's position calculation formulas used. * Now possible to move by paths with multiple points, send whole path to client. -- Original author of research and implementation: SilverIce. Massive kudos. Original port for Trinity (ref #4629) Chaplain and Venugh With the following incremental fixes during my review: - Restore flightmaster end grid pre-loading - Fix uninitialized Creature::m_path_id - Add missing trinity_string entries for .movegens command - Fix a bug in WaypointMovementGenerator that would trigger unexpected pausing at waypoints for various amounts of time Known issues: - Errors like WaypointMovementGenerator::LoadPath creature XXX (Entry: YYYYY GUID: ZZZZZZ) doesn't have waypoint path id: 0. This is caused by bad DB data. This commit didn't "break" it. Do not forget to re-run CMake before compiling. --- .../world/2011_01_14_03_world_trinity_string.sql | 6 + src/server/game/AI/CoreAI/GuardAI.cpp | 4 +- src/server/game/AI/CoreAI/PetAI.cpp | 9 +- src/server/game/AI/EventAI/CreatureEventAI.cpp | 5 +- src/server/game/AI/ScriptedAI/ScriptedCreature.cpp | 3 +- .../game/AI/ScriptedAI/ScriptedFollowerAI.cpp | 4 +- src/server/game/AI/SmartScripts/SmartScript.cpp | 6 +- src/server/game/CMakeLists.txt | 2 + src/server/game/Chat/Commands/Level3.cpp | 61 +-- src/server/game/Entities/Creature/Creature.cpp | 72 ++-- src/server/game/Entities/Creature/Creature.h | 4 +- .../game/Entities/Creature/CreatureGroups.cpp | 4 +- src/server/game/Entities/GameObject/GameObject.cpp | 2 +- src/server/game/Entities/Object/Object.cpp | 139 +++---- src/server/game/Entities/Object/Object.h | 3 + src/server/game/Entities/Player/Player.cpp | 38 +- src/server/game/Entities/Player/Player.h | 1 - src/server/game/Entities/Unit/Unit.cpp | 252 ++++--------- src/server/game/Entities/Unit/Unit.h | 126 ++----- src/server/game/Maps/Map.cpp | 18 + src/server/game/Maps/Map.h | 2 + src/server/game/Maps/MapManager.cpp | 1 - src/server/game/Miscellaneous/Language.h | 12 +- src/server/game/Movement/DestinationHolder.cpp | 20 - src/server/game/Movement/DestinationHolder.h | 65 ---- src/server/game/Movement/DestinationHolderImp.h | 215 ----------- src/server/game/Movement/MotionMaster.cpp | 160 ++++---- src/server/game/Movement/MotionMaster.h | 15 +- src/server/game/Movement/MovementGenerator.cpp | 1 - src/server/game/Movement/MovementGenerator.h | 2 - .../ConfusedMovementGenerator.cpp | 124 +++--- .../MovementGenerators/ConfusedMovementGenerator.h | 13 +- .../FleeingMovementGenerator.cpp | 123 +++--- .../MovementGenerators/FleeingMovementGenerator.h | 7 +- .../MovementGenerators/HomeMovementGenerator.cpp | 57 ++- .../MovementGenerators/HomeMovementGenerator.h | 12 +- .../MovementGenerators/PointMovementGenerator.cpp | 104 +++--- .../MovementGenerators/PointMovementGenerator.h | 30 +- .../MovementGenerators/RandomMovementGenerator.cpp | 188 ++++------ .../MovementGenerators/RandomMovementGenerator.h | 12 +- .../TargetedMovementGenerator.cpp | 357 ++++++++++-------- .../MovementGenerators/TargetedMovementGenerator.h | 92 +++-- .../WaypointMovementGenerator.cpp | 416 +++++++++------------ .../MovementGenerators/WaypointMovementGenerator.h | 90 +++-- src/server/game/Movement/Spline/MoveSpline.cpp | 316 ++++++++++++++++ src/server/game/Movement/Spline/MoveSpline.h | 127 +++++++ src/server/game/Movement/Spline/MoveSplineFlag.h | 143 +++++++ src/server/game/Movement/Spline/MoveSplineInit.cpp | 119 ++++++ src/server/game/Movement/Spline/MoveSplineInit.h | 170 +++++++++ .../game/Movement/Spline/MoveSplineInitArgs.h | 67 ++++ .../game/Movement/Spline/MovementPacketBuilder.cpp | 188 ++++++++++ .../game/Movement/Spline/MovementPacketBuilder.h | 37 ++ src/server/game/Movement/Spline/MovementTypedefs.h | 81 ++++ src/server/game/Movement/Spline/MovementUtil.cpp | 208 +++++++++++ src/server/game/Movement/Spline/Spline.cpp | 307 +++++++++++++++ src/server/game/Movement/Spline/Spline.h | 212 +++++++++++ src/server/game/Movement/Spline/SplineImpl.h | 97 +++++ src/server/game/Movement/Traveller.h | 152 -------- src/server/game/Scripting/MapScripts.cpp | 10 +- .../game/Server/Protocol/Handlers/TaxiHandler.cpp | 1 - src/server/game/Spells/Auras/SpellAuraEffects.cpp | 6 +- src/server/game/Spells/SpellEffects.cpp | 17 +- src/server/scripts/Commands/cs_npc.cpp | 5 +- .../EasternKingdoms/ScarletEnclave/chapter1.cpp | 2 +- .../EasternKingdoms/ZulAman/boss_akilzon.cpp | 2 +- src/server/scripts/EasternKingdoms/undercity.cpp | 4 +- .../TrialOfTheCrusader/boss_anubarak_trial.cpp | 6 +- .../FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp | 2 +- .../IcecrownCitadel/boss_blood_prince_council.cpp | 2 +- .../IcecrownCitadel/boss_deathbringer_saurfang.cpp | 4 +- .../IcecrownCitadel/boss_the_lich_king.cpp | 20 +- .../Northrend/IcecrownCitadel/icecrown_citadel.cpp | 2 +- .../Northrend/Nexus/EyeOfEternity/boss_malygos.cpp | 2 +- .../Ulduar/HallsOfLightning/boss_volkhan.cpp | 4 +- .../Ulduar/HallsOfStone/boss_krystallus.cpp | 2 +- .../Ulduar/Ulduar/boss_assembly_of_iron.cpp | 2 +- .../UtgardeKeep/UtgardePinnacle/boss_skadi.cpp | 2 +- .../UtgardeKeep/UtgardePinnacle/boss_svala.cpp | 27 +- .../ManaTombs/boss_nexusprince_shaffar.cpp | 2 +- .../scripts/Outland/BlackTemple/boss_illidan.cpp | 2 +- .../scripts/Outland/GruulsLair/boss_gruul.cpp | 2 +- .../Outland/TempestKeep/Eye/boss_kaelthas.cpp | 4 +- src/server/scripts/World/guards.cpp | 2 +- src/server/shared/Utilities/Timer.h | 2 +- 84 files changed, 3325 insertions(+), 1912 deletions(-) create mode 100644 sql/updates/world/2011_01_14_03_world_trinity_string.sql delete mode 100755 src/server/game/Movement/DestinationHolder.cpp delete mode 100755 src/server/game/Movement/DestinationHolder.h delete mode 100755 src/server/game/Movement/DestinationHolderImp.h create mode 100644 src/server/game/Movement/Spline/MoveSpline.cpp create mode 100644 src/server/game/Movement/Spline/MoveSpline.h create mode 100644 src/server/game/Movement/Spline/MoveSplineFlag.h create mode 100644 src/server/game/Movement/Spline/MoveSplineInit.cpp create mode 100644 src/server/game/Movement/Spline/MoveSplineInit.h create mode 100644 src/server/game/Movement/Spline/MoveSplineInitArgs.h create mode 100644 src/server/game/Movement/Spline/MovementPacketBuilder.cpp create mode 100644 src/server/game/Movement/Spline/MovementPacketBuilder.h create mode 100644 src/server/game/Movement/Spline/MovementTypedefs.h create mode 100644 src/server/game/Movement/Spline/MovementUtil.cpp create mode 100644 src/server/game/Movement/Spline/Spline.cpp create mode 100644 src/server/game/Movement/Spline/Spline.h create mode 100644 src/server/game/Movement/Spline/SplineImpl.h delete mode 100755 src/server/game/Movement/Traveller.h (limited to 'src/server/scripts') diff --git a/sql/updates/world/2011_01_14_03_world_trinity_string.sql b/sql/updates/world/2011_01_14_03_world_trinity_string.sql new file mode 100644 index 00000000000..7dab007f774 --- /dev/null +++ b/sql/updates/world/2011_01_14_03_world_trinity_string.sql @@ -0,0 +1,6 @@ +DELETE FROM `trinity_string` WHERE `entry` IN(1139,1140,1141,1142); +INSERT INTO `trinity_string` (`entry`,`content_default`) VALUES +(1139,' Follow player %s (lowguid %u)'), +(1140,' Follow creature %s (lowguid %u)'), +(1141,' Follow '), +(1142,' Effect movement'); diff --git a/src/server/game/AI/CoreAI/GuardAI.cpp b/src/server/game/AI/CoreAI/GuardAI.cpp index 54061274408..b78fec7c142 100755 --- a/src/server/game/AI/CoreAI/GuardAI.cpp +++ b/src/server/game/AI/CoreAI/GuardAI.cpp @@ -115,8 +115,8 @@ void GuardAI::EnterEvadeMode() me->CombatStop(true); i_state = STATE_NORMAL; - // Remove TargetedMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE) + // Remove ChaseMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead + if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) me->GetMotionMaster()->MoveTargetedHome(); } diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp index 60151e4865a..015e20415b1 100755 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -417,10 +417,9 @@ void PetAI::MovementInform(uint32 moveType, uint32 data) me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveIdle(); } + break; } - break; - - case TARGETED_MOTION_TYPE: + case FOLLOW_MOTION_TYPE: { // If data is owner's GUIDLow then we've reached follow point, // otherwise we're probably chasing a creature @@ -430,11 +429,9 @@ void PetAI::MovementInform(uint32 moveType, uint32 data) me->GetCharmInfo()->SetIsReturning(false); me->GetCharmInfo()->SetIsFollowing(true); me->GetCharmInfo()->SetIsCommandAttack(false); - me->AddUnitState(UNIT_STAT_FOLLOW); } + break; } - break; - default: break; } diff --git a/src/server/game/AI/EventAI/CreatureEventAI.cpp b/src/server/game/AI/EventAI/CreatureEventAI.cpp index c7590ebb512..c507262bd3f 100755 --- a/src/server/game/AI/EventAI/CreatureEventAI.cpp +++ b/src/server/game/AI/EventAI/CreatureEventAI.cpp @@ -475,7 +475,7 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 //Melee current victim if flag not set if (!(action.cast.castFlags & CAST_NO_MELEE_IF_OOM)) { - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE) + if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) { m_AttackDistance = 0.0f; m_AttackAngle = 0.0f; @@ -483,7 +483,6 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 me->GetMotionMaster()->MoveChase(me->getVictim(), m_AttackDistance, m_AttackAngle); } } - } else { @@ -595,7 +594,7 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 me->ClearUnitState(UNIT_STAT_MELEE_ATTACKING); me->SendMeleeAttackStop(victim); } - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE) + if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) me->GetMotionMaster()->MoveIdle(); } } diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index e3518cb6921..1b6fde6d132 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -298,7 +298,8 @@ void ScriptedAI::DoModifyThreatPercent(Unit* unit, int32 pct) void ScriptedAI::DoTeleportTo(float x, float y, float z, uint32 time) { me->Relocate(x, y, z); - me->SendMonsterMove(x, y, z, time); + float speed = me->GetDistance(x, y, z) / ((float)time * 0.001f); + me->MonsterMoveWithSpeed(x, y, z, speed); } void ScriptedAI::DoTeleportTo(const float position[4]) diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp index 1e0b212dd45..53747d0c799 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp @@ -167,7 +167,7 @@ void FollowerAI::EnterEvadeMode() { sLog->outDebug(LOG_FILTER_TSCR, "TSCR: FollowerAI left combat, returning to CombatStartPosition."); - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE) + if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) { float fPosX, fPosY, fPosZ; me->GetPosition(fPosX, fPosY, fPosZ); @@ -176,7 +176,7 @@ void FollowerAI::EnterEvadeMode() } else { - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE) + if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) me->GetMotionMaster()->MoveTargetedHome(); } diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 9cea61c0d2b..4328eafc962 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -1273,11 +1273,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u ObjectList* targets = GetTargets(e, unit); if (e.GetTargetType() == SMART_TARGET_SELF) - me->SetFacing(me->GetHomePosition().GetOrientation(), NULL); + me->SetFacingTo(me->GetHomePosition().GetOrientation()); else if (e.GetTargetType() == SMART_TARGET_POSITION) - me->SetFacing(e.target.o, NULL); + me->SetFacingTo(e.target.o); else if (targets && !targets->empty()) - me->SetFacing(0, (*targets->begin())); + me->SetFacingToObject(*targets->begin()); delete targets; break; diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index 117a8f680ee..658e9a15cc8 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -102,6 +102,7 @@ set(game_STAT_SRCS include_directories( ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/dep/mersennetwister ${CMAKE_SOURCE_DIR}/dep/SFMT ${CMAKE_SOURCE_DIR}/dep/zlib @@ -170,6 +171,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/Maps ${CMAKE_CURRENT_SOURCE_DIR}/Miscellaneous ${CMAKE_CURRENT_SOURCE_DIR}/Movement + ${CMAKE_CURRENT_SOURCE_DIR}/Movement/Spline ${CMAKE_CURRENT_SOURCE_DIR}/Movement/MovementGenerators ${CMAKE_CURRENT_SOURCE_DIR}/Movement/Waypoints ${CMAKE_CURRENT_SOURCE_DIR}/OutdoorPvP diff --git a/src/server/game/Chat/Commands/Level3.cpp b/src/server/game/Chat/Commands/Level3.cpp index d23a429471f..cb3eb825354 100755 --- a/src/server/game/Chat/Commands/Level3.cpp +++ b/src/server/game/Chat/Commands/Level3.cpp @@ -3692,6 +3692,9 @@ bool ChatHandler::HandleMovegensCommand(const char* /*args*/) PSendSysMessage(LANG_MOVEGENS_LIST, (unit->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), unit->GetGUIDLow()); MotionMaster* mm = unit->GetMotionMaster(); + float x,y,z; + mm->GetDestination(x,y,z); + for (uint8 i = 0; i < MAX_MOTION_SLOT; ++i) { MovementGenerator* mg = mm->GetMotionSlot(i); @@ -3707,48 +3710,55 @@ bool ChatHandler::HandleMovegensCommand(const char* /*args*/) case WAYPOINT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_WAYPOINT); break; case ANIMAL_RANDOM_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_ANIMAL_RANDOM); break; case CONFUSED_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_CONFUSED); break; - case TARGETED_MOTION_TYPE: + case CHASE_MOTION_TYPE: { + Unit* target = NULL; if (unit->GetTypeId() == TYPEID_PLAYER) - { - TargetedMovementGenerator const* mgen = static_cast const*>(mg); - Unit* target = mgen->GetTarget(); - if (target) - PSendSysMessage(LANG_MOVEGENS_TARGETED_PLAYER, target->GetName(), target->GetGUIDLow()); - else - SendSysMessage(LANG_MOVEGENS_TARGETED_NULL); - } + target = static_cast const*>(mg)->GetTarget(); else - { - TargetedMovementGenerator const* mgen = static_cast const*>(mg); - Unit* target = mgen->GetTarget(); - if (target) - PSendSysMessage(LANG_MOVEGENS_TARGETED_CREATURE, target->GetName(), target->GetGUIDLow()); - else - SendSysMessage(LANG_MOVEGENS_TARGETED_NULL); - } + target = static_cast const*>(mg)->GetTarget(); + + if (!target) + SendSysMessage(LANG_MOVEGENS_CHASE_NULL); + else if (target->GetTypeId() == TYPEID_PLAYER) + PSendSysMessage(LANG_MOVEGENS_CHASE_PLAYER, target->GetName(), target->GetGUIDLow()); + else + PSendSysMessage(LANG_MOVEGENS_CHASE_CREATURE, target->GetName(), target->GetGUIDLow()); break; } + case FOLLOW_MOTION_TYPE: + { + Unit* target = NULL; + if (unit->GetTypeId() == TYPEID_PLAYER) + target = static_cast const*>(mg)->GetTarget(); + else + target = static_cast const*>(mg)->GetTarget(); + + if (!target) + SendSysMessage(LANG_MOVEGENS_FOLLOW_NULL); + else if (target->GetTypeId() == TYPEID_PLAYER) + PSendSysMessage(LANG_MOVEGENS_FOLLOW_PLAYER, target->GetName(), target->GetGUIDLow()); + else + PSendSysMessage(LANG_MOVEGENS_FOLLOW_CREATURE, target->GetName(), target->GetGUIDLow()); + break; + } case HOME_MOTION_TYPE: + { if (unit->GetTypeId() == TYPEID_UNIT) - { - float x, y, z; - mg->GetDestination(x, y, z); PSendSysMessage(LANG_MOVEGENS_HOME_CREATURE, x, y, z); - } else SendSysMessage(LANG_MOVEGENS_HOME_PLAYER); break; + } case FLIGHT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_FLIGHT); break; case POINT_MOTION_TYPE: { - float x, y, z; - mg->GetDestination(x, y, z); PSendSysMessage(LANG_MOVEGENS_POINT, x, y, z); break; } case FLEEING_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_FEAR); break; case DISTRACT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_DISTRACT); break; + case EFFECT_MOTION_TYPE: SendSysMessage(LANG_MOVEGENS_EFFECT); break; default: PSendSysMessage(LANG_MOVEGENS_UNKNOWN, mg->GetMovementGeneratorType()); break; @@ -4040,19 +4050,14 @@ bool ChatHandler::HandleComeToMeCommand(const char *args) if (!newFlagStr) return false; - uint32 newFlags = (uint32)strtoul(newFlagStr, NULL, 0); - Creature* caster = getSelectedCreature(); if (!caster) { - m_session->GetPlayer()->SetUnitMovementFlags(newFlags); SendSysMessage(LANG_SELECT_CREATURE); SetSentErrorMessage(true); return false; } - caster->SetUnitMovementFlags(newFlags); - Player* player = m_session->GetPlayer(); caster->GetMotionMaster()->MovePoint(0, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index ff627f78ea0..23865dd9e41 100755 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -48,6 +48,8 @@ #include "Vehicle.h" #include "SpellAuraEffects.h" #include "Group.h" +#include "MoveSplineInit.h" +#include "MoveSpline.h" // apply implementation of the singletons TrainerSpell const* TrainerSpellData::Find(uint32 spell_id) const @@ -143,7 +145,7 @@ m_PlayerDamageReq(0), m_lootMoney(0), m_lootRecipient(0), m_lootRecipientGroup(0 m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_reactState(REACT_AGGRESSIVE), m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0), m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), -m_creatureInfo(NULL), m_creatureData(NULL), m_formation(NULL) +m_creatureInfo(NULL), m_creatureData(NULL), m_formation(NULL), m_path_id(0) { m_regenTimer = CREATURE_REGEN_INTERVAL; m_valuesCount = UNIT_END; @@ -332,6 +334,7 @@ bool Creature::InitEntry(uint32 Entry, uint32 /*team*/, const CreatureData* data SetSpeed(MOVE_FLIGHT, 1.0f); // using 1.0 rate SetFloatValue(OBJECT_FIELD_SCALE_X, cinfo->scale); + SetLevitate(canFly()); // checked at loading m_defaultMovementType = MovementGeneratorType(cinfo->MovementType); @@ -435,6 +438,17 @@ void Creature::Update(uint32 diff) m_vehicleKit->Reset(); } + if (IsInWater()) + { + if (canSwim()) + AddUnitMovementFlag(MOVEMENTFLAG_SWIMMING); + } + else + { + if (canWalk()) + RemoveUnitMovementFlag(MOVEMENTFLAG_SWIMMING); + } + switch (m_deathState) { case JUST_ALIVED: @@ -472,9 +486,7 @@ void Creature::Update(uint32 diff) } case CORPSE: { - m_Events.Update(diff); - _UpdateSpells(diff); - + Unit::Update(diff); // deathstate changed on spells update, prevent problems if (m_deathState != CORPSE) break; @@ -565,9 +577,6 @@ void Creature::Update(uint32 diff) m_regenTimer = CREATURE_REGEN_INTERVAL; break; } - case DEAD_FALLING: - GetMotionMaster()->UpdateMotion(diff); - break; default: break; } @@ -945,7 +954,8 @@ void Creature::AI_SendMoveToPacket(float x, float y, float z, uint32 time, uint3 m_startMove = getMSTime(); m_moveTime = time;*/ - SendMonsterMove(x, y, z, time); + float speed = GetDistance(x, y, z) / ((float)time * 0.001f); + MonsterMoveWithSpeed(x, y, z, speed); } Player* Creature::GetLootRecipient() const @@ -1507,8 +1517,8 @@ void Creature::setDeathState(DeathState s) if (m_formation && m_formation->getLeader() == this) m_formation->FormationReset(true); - if ((canFly() || IsFlying()) && FallGround()) - return; + if ((canFly() || IsFlying())) + i_motionMaster.MoveFall(); Unit::setDeathState(CORPSE); } @@ -1520,7 +1530,7 @@ void Creature::setDeathState(DeathState s) SetLootRecipient(NULL); ResetPlayerDamageReq(); CreatureTemplate const* cinfo = GetCreatureInfo(); - AddUnitMovementFlag(MOVEMENTFLAG_WALKING); + SetWalk(true); if (GetCreatureInfo()->InhabitType & INHABIT_AIR) AddUnitMovementFlag(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_FLYING); if (GetCreatureInfo()->InhabitType & INHABIT_WATER) @@ -1536,24 +1546,6 @@ void Creature::setDeathState(DeathState s) } } -bool Creature::FallGround() -{ - // Let's abort after we called this function one time - if (getDeathState() == DEAD_FALLING) - return false; - - float x, y, z; - GetPosition(x, y, z); - // use larger distance for vmap height search than in most other cases - float ground_Z = GetMap()->GetHeight(x, y, z, true, MAX_FALL_DISTANCE); - if (fabs(ground_Z - z) < 0.1f) - return false; - - GetMotionMaster()->MoveFall(ground_Z, EVENT_FALL_GROUND); - Unit::setDeathState(DEAD_FALLING); - return true; -} - void Creature::Respawn(bool force) { DestroyForNearbyPlayers(); @@ -2415,3 +2407,25 @@ bool Creature::IsDungeonBoss() const CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(GetEntry()); return cinfo && (cinfo->flags_extra & CREATURE_FLAG_EXTRA_DUNGEON_BOSS); } + +void Creature::SetWalk(bool enable) +{ + if (enable) + AddUnitMovementFlag(MOVEMENTFLAG_WALKING); + else + RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); + WorldPacket data(enable ? SMSG_SPLINE_MOVE_SET_WALK_MODE : SMSG_SPLINE_MOVE_SET_RUN_MODE, 9); + data.append(GetPackGUID()); + SendMessageToSet(&data, true); +} + +void Creature::SetLevitate(bool enable) +{ + if (enable) + AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + else + RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + WorldPacket data(enable ? SMSG_SPLINE_MOVE_GRAVITY_DISABLE : SMSG_SPLINE_MOVE_GRAVITY_ENABLE, 9); + data.append(GetPackGUID()); + SendMessageToSet(&data, true); +} diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index adad02653bf..05339f1da53 100755 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -520,6 +520,9 @@ class Creature : public Unit, public GridObject, public MapCreature void AI_SendMoveToPacket(float x, float y, float z, uint32 time, uint32 MovementFlags, uint8 type); CreatureAI* AI() const { return (CreatureAI*)i_AI; } + void SetWalk(bool enable); + void SetLevitate(bool enable); + uint32 GetShieldBlockValue() const //dunno mob block value { return (getLevel()/2 + uint32(GetStat(STAT_STRENGTH)/20)); @@ -573,7 +576,6 @@ class Creature : public Unit, public GridObject, public MapCreature const char* GetNameForLocaleIdx(LocaleConstant locale_idx) const; void setDeathState(DeathState s); // override virtual Unit::setDeathState - bool FallGround(); bool LoadFromDB(uint32 guid, Map* map) { return LoadCreatureFromDB(guid, map, false); } bool LoadCreatureFromDB(uint32 guid, Map* map, bool addToMap = true); diff --git a/src/server/game/Entities/Creature/CreatureGroups.cpp b/src/server/game/Entities/Creature/CreatureGroups.cpp index abf82dc5919..f440fd497fc 100755 --- a/src/server/game/Entities/Creature/CreatureGroups.cpp +++ b/src/server/game/Entities/Creature/CreatureGroups.cpp @@ -212,10 +212,12 @@ void CreatureGroup::FormationReset(bool dismiss) void CreatureGroup::LeaderMoveTo(float x, float y, float z) { + //! To do: This should probably get its own movement generator or use WaypointMovementGenerator. + //! If the leader's path is known, member's path can be plotted as well using formation offsets. if (!m_leader) return; - float pathangle = atan2(m_leader->GetPositionY() - y, m_leader->GetPositionX() - x); + float pathangle = atan2(m_leader->GetPositionY() - y, m_leader->GetPositionX() - x); for (CreatureGroupMemberType::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) { diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 22f001d0224..fd094938da8 100755 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1869,4 +1869,4 @@ void GameObject::SetLootState(LootState s) { m_lootState = s; AI()->OnStateChanged(s); -} \ No newline at end of file +} diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 3cd02d05a90..5c034f1a42a 100755 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -45,6 +45,7 @@ #include "TemporarySummon.h" #include "Totem.h" #include "OutdoorPvPMgr.h" +#include "MovementPacketBuilder.h" uint32 GuidHigh2TypeId(uint32 guid_hi) { @@ -312,78 +313,17 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint16 flags) const *data << ((Unit*)this)->GetSpeed(MOVE_WALK); *data << ((Unit*)this)->GetSpeed(MOVE_RUN); - *data << ((Unit*)this)->GetSpeed(MOVE_SWIM_BACK); - *data << ((Unit*)this)->GetSpeed(MOVE_SWIM); *data << ((Unit*)this)->GetSpeed(MOVE_RUN_BACK); + *data << ((Unit*)this)->GetSpeed(MOVE_SWIM); + *data << ((Unit*)this)->GetSpeed(MOVE_SWIM_BACK); *data << ((Unit*)this)->GetSpeed(MOVE_FLIGHT); *data << ((Unit*)this)->GetSpeed(MOVE_FLIGHT_BACK); *data << ((Unit*)this)->GetSpeed(MOVE_TURN_RATE); *data << ((Unit*)this)->GetSpeed(MOVE_PITCH_RATE); - const Player* player = ToPlayer(); - // 0x08000000 - if (player && player->isInFlight()) - { - uint32 flags3 = SPLINEFLAG_GLIDE; - - *data << uint32(flags3); // splines flag? - - if (flags3 & 0x20000) // may be orientation - { - *data << (float)0; - } - else - { - if (flags3 & 0x8000) // probably x, y, z coords there - { - *data << (float)0; - *data << (float)0; - *data << (float)0; - } - - if (flags3 & 0x10000) // probably guid there - { - *data << uint64(0); - } - } - - FlightPathMovementGenerator *fmg = - (FlightPathMovementGenerator*)(player->GetMotionMaster()->top()); - TaxiPathNodeList const& path = fmg->GetPath(); - - float x, y, z; - player->GetPosition(x, y, z); - - uint32 inflighttime = uint32(path.GetPassedLength(fmg->GetCurrentNode(), x, y, z) * 32); - uint32 traveltime = uint32(path.GetTotalLength() * 32); - - *data << uint32(inflighttime); // passed move time? - *data << uint32(traveltime); // full move time? - *data << uint32(0); // ticks count? - - *data << float(0); // added in 3.1 - *data << float(0); // added in 3.1 - *data << float(0); // added in 3.1 - - *data << uint32(0); // added in 3.1 - - uint32 poscount = uint32(path.size()); - *data << uint32(poscount); // points count - - for (uint32 i = 0; i < poscount; ++i) - { - *data << float(path[i].x); - *data << float(path[i].y); - *data << float(path[i].z); - } - - *data << uint8(0); // added in 3.0.8 - - *data << float(path[poscount-1].x); - *data << float(path[poscount-1].y); - *data << float(path[poscount-1].z); - } + if (((Unit*)this)->m_movementInfo.GetMovementFlags() & MOVEMENTFLAG_SPLINE_ENABLED) + Movement::PacketBuilder::WriteCreate(*((Unit*)this)->movespline, *data); } else { @@ -487,7 +427,7 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint16 flags) const // 0x200 if (flags & UPDATEFLAG_ROTATION) { - *data << uint64(((GameObject*)this)->GetRotation()); + *data << int64(((GameObject*)this)->GetRotation()); } } @@ -1595,6 +1535,70 @@ void WorldObject::UpdateGroundPositionZ(float x, float y, float &z) const z = new_z+ 0.05f; // just to be sure that we are not a few pixel under the surface } +void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const +{ + switch (GetTypeId()) + { + case TYPEID_UNIT: + { + // non fly unit don't must be in air + // non swim unit must be at ground (mostly speedup, because it don't must be in water and water level check less fast + if (!((Creature const*)this)->canFly()) + { + bool canSwim = ((Creature const*)this)->canSwim(); + float ground_z = z; + float max_z = canSwim + ? GetBaseMap()->GetWaterOrGroundLevel(x, y, z, &ground_z, !((Unit const*)this)->HasAuraType(SPELL_AURA_WATER_WALK)) + : ((ground_z = GetBaseMap()->GetHeight(x, y, z, true))); + if (max_z > INVALID_HEIGHT) + { + if (z > max_z) + z = max_z; + else if (z < ground_z) + z = ground_z; + } + } + else + { + float ground_z = GetBaseMap()->GetHeight(x, y, z, true); + if (z < ground_z) + z = ground_z; + } + break; + } + case TYPEID_PLAYER: + { + // for server controlled moves playr work same as creature (but it can always swim) + if (!((Player const*)this)->canFly()) + { + float ground_z = z; + float max_z = GetBaseMap()->GetWaterOrGroundLevel(x, y, z, &ground_z, !((Unit const*)this)->HasAuraType(SPELL_AURA_WATER_WALK)); + if (max_z > INVALID_HEIGHT) + { + if (z > max_z) + z = max_z; + else if (z < ground_z) + z = ground_z; + } + } + else + { + float ground_z = GetBaseMap()->GetHeight(x, y, z, true); + if (z < ground_z) + z = ground_z; + } + break; + } + default: + { + float ground_z = GetBaseMap()->GetHeight(x, y, z, true); + if(ground_z > INVALID_HEIGHT) + z = ground_z; + break; + } + } +} + bool Position::IsPositionValid() const { return Trinity::IsValidMapCoord(m_positionX, m_positionY, m_positionZ, m_orientation); @@ -2033,7 +2037,8 @@ void Unit::BuildHeartBeatMsg(WorldPacket* data) const void WorldObject::SendMessageToSet(WorldPacket* data, bool self) { - SendMessageToSetInRange(data, GetVisibilityRange(), self); + if (IsInWorld()) + SendMessageToSetInRange(data, GetVisibilityRange(), self); } void WorldObject::SendMessageToSetInRange(WorldPacket* data, float dist, bool /*self*/) diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 3f78ec662e8..4cc298e4349 100755 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -497,7 +497,9 @@ struct MovementInfo } uint32 GetMovementFlags() { return flags; } + void SetMovementFlags(uint32 flag) { flags = flag; } void AddMovementFlag(uint32 flag) { flags |= flag; } + void RemoveMovementFlag(uint32 flag) { flags &= ~flag; } bool HasMovementFlag(uint32 flag) const { return flags & flag; } uint16 GetExtraMovementFlags() { return flags2; } @@ -615,6 +617,7 @@ class WorldObject : public Object, public WorldLocation return (m_valuesCount > UNIT_FIELD_COMBATREACH) ? m_floatValues[UNIT_FIELD_COMBATREACH] : DEFAULT_WORLD_OBJECT_SIZE; } void UpdateGroundPositionZ(float x, float y, float &z) const; + void UpdateAllowedPositionZ(float x, float y, float &z) const; void GetRandomPoint(const Position &srcPos, float distance, float &rand_x, float &rand_y, float &rand_z) const; void GetRandomPoint(const Position &srcPos, float distance, Position &pos) const diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 7f7facfaff1..46f903ee71a 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -2101,6 +2101,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati // reset movement flags at teleport, because player will continue move with these flags after teleport SetUnitMovementFlags(0); + DisableSpline(); if (m_transport) { @@ -5148,43 +5149,10 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness) } } -/** - * FallMode = 0 implies that the player is dying, or already dead, and the proper death state will be set. - * = 1 simply causes the player to plummet towards the ground, and not suffer any damage. - * = 2 causes the player to plummet towards the ground, and causes falling damage, regardless - * of any auras that might of prevented fall damage. - */ -bool Player::FallGround(uint8 FallMode) -{ - // Let's abort after we called this function one time - if (getDeathState() == DEAD_FALLING && FallMode == 0) - return false; - - float x, y, z; - GetPosition(x, y, z); - float ground_Z = GetMap()->GetHeight(x, y, z); - float z_diff = 0.0f; - if ((z_diff = fabs(ground_Z - z)) < 0.1f) - return false; - - GetMotionMaster()->MoveFall(ground_Z, EVENT_FALL_GROUND); - - // Below formula for falling damage is from Player::HandleFall - if (FallMode == 2 && z_diff >= 14.57f) - { - uint32 damage = std::min(GetMaxHealth(), (uint32)((0.018f * z_diff - 0.2426f) * GetMaxHealth() * sWorld->getRate(RATE_DAMAGE_FALL))); - if (damage) - EnvironmentalDamage(DAMAGE_FALL, damage); - } - else if (FallMode == 0) - Unit::setDeathState(DEAD_FALLING); - return true; -} - void Player::KillPlayer() { if (IsFlying() && !GetTransport()) - FallGround(); + i_motionMaster.MoveFall(); SetMovement(MOVE_ROOT); @@ -21474,8 +21442,6 @@ void Player::SendInitialVisiblePackets(Unit* target) SendAurasForTarget(target); if (target->isAlive()) { - if (target->GetMotionMaster()->GetCurrentMovementGeneratorType() != IDLE_MOTION_TYPE) - target->SendMonsterMoveWithSpeedToCurrentDestination(this); if (target->HasUnitState(UNIT_STAT_MELEE_ATTACKING) && target->getVictim()) target->SendMeleeAttackStart(target->getVictim()); } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 21c87a993dc..aa1d4e8185e 100755 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1964,7 +1964,6 @@ class Player : public Unit, public GridObject Corpse* GetCorpse() const; void SpawnCorpseBones(); void CreateCorpse(); - bool FallGround(uint8 FallMode = 0); void KillPlayer(); uint32 GetResurrectionSpellId(); void ResurrectPlayer(float restore_percent, bool applySickness = false); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 2d6e8f1b724..63aa7771063 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -45,16 +45,16 @@ #include "InstanceSaveMgr.h" #include "GridNotifiersImpl.h" #include "CellImpl.h" -#include "Path.h" #include "CreatureGroups.h" #include "PetAI.h" #include "PassiveAI.h" -#include "Traveller.h" #include "TemporarySummon.h" #include "Vehicle.h" #include "Transport.h" #include "InstanceScript.h" #include "SpellInfo.h" +#include "MoveSplineInit.h" +#include "MoveSpline.h" #include @@ -62,9 +62,9 @@ float baseMoveSpeed[MAX_MOVE_TYPE] = { 2.5f, // MOVE_WALK 7.0f, // MOVE_RUN - 2.5f, // MOVE_RUN_BACK + 4.5f, // MOVE_RUN_BACK 4.722222f, // MOVE_SWIM - 4.5f, // MOVE_SWIM_BACK + 2.5f, // MOVE_SWIM_BACK 3.141594f, // MOVE_TURN_RATE 7.0f, // MOVE_FLIGHT 4.5f, // MOVE_FLIGHT_BACK @@ -73,9 +73,9 @@ float baseMoveSpeed[MAX_MOVE_TYPE] = float playerBaseMoveSpeed[MAX_MOVE_TYPE] = { 2.5f, // MOVE_WALK 7.0f, // MOVE_RUN - 2.5f, // MOVE_RUN_BACK + 4.5f, // MOVE_RUN_BACK 4.722222f, // MOVE_SWIM - 4.5f, // MOVE_SWIM_BACK + 2.5f, // MOVE_SWIM_BACK 3.141594f, // MOVE_TURN_RATE 7.0f, // MOVE_FLIGHT 4.5f, // MOVE_FLIGHT_BACK @@ -148,7 +148,7 @@ Unit::Unit(bool isWorldObject): WorldObject(isWorldObject), m_movedPlayer(NULL), m_lastSanctuaryTime(0), IsAIEnabled(false), NeedChangeAI(false), m_ControlledByPlayer(false), i_AI(NULL), i_disabledAI(NULL), m_procDeep(0), m_removedAurasCount(0), i_motionMaster(this), m_ThreatManager(this), m_vehicle(NULL), -m_vehicleKit(NULL), m_unitTypeMask(UNIT_MASK_NONE), m_HostileRefManager(this) +m_vehicleKit(NULL), m_unitTypeMask(UNIT_MASK_NONE), m_HostileRefManager(this), movespline(new Movement::MoveSpline()) { #ifdef _MSC_VER #pragma warning(default:4355) @@ -280,6 +280,7 @@ Unit::~Unit() delete m_charmInfo; delete m_vehicleKit; + delete movespline; ASSERT(!m_duringRemoveFromWorld); ASSERT(!m_attacking); @@ -346,6 +347,7 @@ void Unit::Update(uint32 p_time) ModifyAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, HealthAbovePct(75)); } + UpdateSplineMovement(p_time); i_motionMaster.UpdateMotion(p_time); } @@ -357,151 +359,46 @@ bool Unit::haveOffhandWeapon() const return m_canDualWield; } -void Unit::SendMonsterMoveWithSpeedToCurrentDestination(Player* player) +void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed) { - float x, y, z; - if (GetMotionMaster()->GetDestination(x, y, z)) - SendMonsterMoveWithSpeed(x, y, z, 0, player); -} - -void Unit::SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime, Player* player) -{ - if (!transitTime) - { - if (GetTypeId() == TYPEID_PLAYER) - { - Traveller traveller(*(Player*)this); - transitTime = traveller.GetTotalTrevelTimeTo(x, y, z); - } - else - { - Traveller traveller(*ToCreature()); - transitTime = traveller.GetTotalTrevelTimeTo(x, y, z); - } - } - //float orientation = (float)atan2((double)dy, (double)dx); - SendMonsterMove(x, y, z, transitTime, player); + Movement::MoveSplineInit init(*this); + init.MoveTo(x,y,z); + init.SetVelocity(speed); + init.Launch(); } -void Unit::SetFacing(float ori, WorldObject* obj) +void Unit::UpdateSplineMovement(uint32 t_diff) { - SetOrientation(obj ? GetAngle(obj) : ori); - - WorldPacket data(SMSG_MONSTER_MOVE, (1+12+4+1+(obj ? 8 : 4)+4+4+4+12+GetPackGUID().size())); - data.append(GetPackGUID()); - data << uint8(0); // unk - data << GetPositionX() << GetPositionY() << GetPositionZ(); - data << getMSTime(); - if (obj) - { - data << uint8(SPLINETYPE_FACING_TARGET); - data << uint64(obj->GetGUID()); - } - else - { - data << uint8(SPLINETYPE_FACING_ANGLE); - data << ori; - } - data << uint32(SPLINEFLAG_NONE); - data << uint32(0); // move time 0 - data << uint32(1); // one point - data << GetPositionX() << GetPositionY() << GetPositionZ(); - SendMessageToSet(&data, true); -} - -void Unit::SendMonsterStop(bool on_death) -{ - WorldPacket data(SMSG_MONSTER_MOVE, (17 + GetPackGUID().size())); - data.append(GetPackGUID()); - data << uint8(0); // new in 3.1 - data << GetPositionX() << GetPositionY() << GetPositionZ(); - data << getMSTime(); - - if (on_death == true) - { - data << uint8(0); - data << uint32((GetUnitMovementFlags() & MOVEMENTFLAG_LEVITATING) ? SPLINEFLAG_FLYING : SPLINEFLAG_WALKING); - data << uint32(0); // Time in between points - data << uint32(1); // 1 single waypoint - data << GetPositionX() << GetPositionY() << GetPositionZ(); - } - else - data << uint8(1); - - SendMessageToSet(&data, true); - - ClearUnitState(UNIT_STAT_MOVE); -} - -void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint32 Time, Player* player) -{ - WorldPacket data(SMSG_MONSTER_MOVE, 1+12+4+1+4+4+4+12+GetPackGUID().size()); - data.append(GetPackGUID()); - - data << uint8(0); // new in 3.1 - data << GetPositionX() << GetPositionY() << GetPositionZ(); - data << getMSTime(); - - data << uint8(0); - data << uint32((GetUnitMovementFlags() & MOVEMENTFLAG_LEVITATING) ? SPLINEFLAG_FLYING : SPLINEFLAG_WALKING); - data << Time; // Time in between points - data << uint32(1); // 1 single waypoint - data << NewPosX << NewPosY << NewPosZ; // the single waypoint Point B - - if (player) - player->GetSession()->SendPacket(&data); - else - SendMessageToSet(&data, true); - - AddUnitState(UNIT_STAT_MOVE); -} + enum{ + POSITION_UPDATE_DELAY = 400, + }; -void Unit::SendMonsterMove(MonsterMoveData const& moveData, Player* player) -{ - WorldPacket data(SMSG_MONSTER_MOVE, GetPackGUID().size() + 1 + 12 + 4 + 1 + 4 + 8 + 4 + 4 + 12); - data.append(GetPackGUID()); + if (movespline->Finalized()) + return; - data << uint8(0); // new in 3.1 - data << GetPositionX() << GetPositionY() << GetPositionZ(); - data << getMSTime(); + movespline->updateState(t_diff); + bool arrived = movespline->Finalized(); - data << uint8(0); - data << moveData.SplineFlag; + if (arrived) + DisableSpline(); - if (moveData.SplineFlag & SPLINEFLAG_ANIMATIONTIER) + m_movesplineTimer.Update(t_diff); + if (m_movesplineTimer.Passed() || arrived) { - data << uint8(moveData.AnimationState); - data << uint32(0); - } + m_movesplineTimer.Reset(POSITION_UPDATE_DELAY); + Movement::Location loc = movespline->ComputePosition(); - data << moveData.Time; - - if (moveData.SplineFlag & SPLINEFLAG_TRAJECTORY) - { - data << moveData.SpeedZ; - data << uint32(0); // walk time after jump + if (GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->UpdatePosition(loc.x,loc.y,loc.z,loc.orientation); + else + GetMap()->CreatureRelocation((Creature*)this,loc.x,loc.y,loc.z,loc.orientation); } - - data << uint32(1); // waypoint count - data << moveData.DestLocation.GetPositionX(); - data << moveData.DestLocation.GetPositionY(); - data << moveData.DestLocation.GetPositionZ(); - - if (player) - player->GetSession()->SendPacket(&data); - else - SendMessageToSet(&data, true); } -void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint32 MoveFlags, uint32 time, float speedZ, Player* player) +void Unit::DisableSpline() { - MonsterMoveData data; - data.DestLocation.Relocate(NewPosX, NewPosY, NewPosZ); - data.SplineFlag = MoveFlags; - data.Time = time; - data.SpeedZ = speedZ; - - SendMonsterMove(data, player); + m_movementInfo.RemoveMovementFlag(MovementFlags(MOVEMENTFLAG_SPLINE_ENABLED|MOVEMENTFLAG_FORWARD)); + movespline->_Interrupt(); } void Unit::SendMonsterMoveExitVehicle(Position const* newPos) @@ -3106,17 +3003,6 @@ bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const return IsWithinDistInMap(target, distance) && !HasInArc(2 * M_PI - arc, target); } -void Unit::SetFacingToObject(WorldObject* pObject) -{ - // update orientation at server - SetOrientation(GetAngle(pObject)); - - // and client - WorldPacket data; - BuildHeartBeatMsg(&data); - SendMessageToSet(&data, false); -} - bool Unit::isInAccessiblePlaceFor(Creature const* c) const { if (IsInWater()) @@ -12744,7 +12630,7 @@ void Unit::setDeathState(DeathState s) ClearDiminishings(); GetMotionMaster()->Clear(false); GetMotionMaster()->MoveIdle(); - SendMonsterStop(true); + StopMoving(); // without this when removing IncreaseMaxHealth aura player may stuck with 1 hp // do not why since in IncreaseMaxHealth currenthealth is checked SetHealth(0); @@ -13565,7 +13451,7 @@ void Unit::SetHealth(uint32 val) { if (getDeathState() == JUST_DIED) val = 0; - else if (GetTypeId() == TYPEID_PLAYER && (getDeathState() == DEAD || getDeathState() == DEAD_FALLING)) + else if (GetTypeId() == TYPEID_PLAYER && getDeathState() == DEAD) val = 1; else { @@ -14682,22 +14568,20 @@ void Unit::StopMoving() { ClearUnitState(UNIT_STAT_MOVING); - // send explicit stop packet - // rely on vmaps here because for example stormwind is in air - //float z = sMapMgr->GetBaseMap(GetMapId())->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true); - //if (fabs(GetPositionZ() - z) < 2.0f) - // Relocate(GetPositionX(), GetPositionY(), z); - //Relocate(GetPositionX(), GetPositionY(), GetPositionZ()); + // not need send any packets if not in world + if (!IsInWorld()) + return; - if (!(GetUnitMovementFlags() & MOVEMENTFLAG_ONTRANSPORT)) - SendMonsterStop(); + Movement::MoveSplineInit init(*this); + init.SetFacing(GetOrientation()); + init.Launch(); } void Unit::SendMovementFlagUpdate() { WorldPacket data; BuildHeartBeatMsg(&data); - SendMessageToSet(&data, false); + SendMessageToSet(&data, true); } bool Unit::IsSitState() const @@ -17097,7 +16981,7 @@ void Unit::_ExitVehicle(Position const* exitPosition) WorldPacket data2; BuildHeartBeatMsg(&data2); - SendMessageToSet(&data2, false); + SendMessageToSet(&data2, true); if (vehicle->GetBase()->HasUnitTypeMask(UNIT_MASK_MINION)) if (((Minion*)vehicle->GetBase())->GetOwner() == this) @@ -17116,25 +17000,6 @@ void Unit::_ExitVehicle(Position const* exitPosition) void Unit::BuildMovementPacket(ByteBuffer *data) const { - switch (GetTypeId()) - { - case TYPEID_UNIT: - if (canFly()) - const_cast(this)->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); - break; - case TYPEID_PLAYER: - // remove unknown, unused etc flags for now - const_cast(this)->RemoveUnitMovementFlag(MOVEMENTFLAG_SPLINE_ENABLED); - if (isInFlight()) - { - WPAssert(const_cast(this)->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE); - const_cast(this)->AddUnitMovementFlag(MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_SPLINE_ENABLED); - } - break; - default: - break; - } - *data << uint32(GetUnitMovementFlags()); // movement flags *data << uint16(m_movementInfo.flags2); // 2.3.0 *data << uint32(getMSTime()); // time @@ -17198,13 +17063,13 @@ void Unit::SetFlying(bool apply) void Unit::NearTeleportTo(float x, float y, float z, float orientation, bool casting /*= false*/) { + DisableSpline(); if (GetTypeId() == TYPEID_PLAYER) ToPlayer()->TeleportTo(GetMapId(), x, y, z, orientation, TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (casting ? TELE_TO_SPELL : 0)); else { - // FIXME: this interrupts spell visual - DestroyForNearbyPlayers(); UpdatePosition(x, y, z, orientation, true); + SendMovementFlagUpdate(); } } @@ -17486,3 +17351,26 @@ bool CharmInfo::IsReturning() { return m_isReturning; } + +void Unit::SetInFront(Unit const* target) +{ + if (!HasUnitState(UNIT_STAT_CANNOT_TURN)) + SetOrientation(GetAngle(target)); +} + +void Unit::SetFacingTo(float ori) +{ + Movement::MoveSplineInit init(*this); + init.SetFacing(ori); + init.Launch(); +} + +void Unit::SetFacingToObject(WorldObject* pObject) +{ + // never face when already moving + if (!IsStopped()) + return; + + // TODO: figure out under what conditions creature will move towards object instead of facing it where it currently is. + SetFacingTo(GetAngle(pObject)); +} diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 5a6b34bc380..b64a2e210bc 100755 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -465,7 +465,6 @@ enum DeathState CORPSE = 2, DEAD = 3, JUST_ALIVED = 4, - DEAD_FALLING= 5 }; enum UnitState @@ -493,13 +492,22 @@ enum UnitState UNIT_STAT_MOVE = 0x00100000, UNIT_STAT_ROTATING = 0x00200000, UNIT_STAT_EVADE = 0x00400000, + UNIT_STAT_ROAMING_MOVE = 0x00800000, + UNIT_STAT_CONFUSED_MOVE = 0x01000000, + UNIT_STAT_FLEEING_MOVE = 0x02000000, + UNIT_STAT_CHASE_MOVE = 0x04000000, + UNIT_STAT_FOLLOW_MOVE = 0x08000000, UNIT_STAT_UNATTACKABLE = (UNIT_STAT_IN_FLIGHT | UNIT_STAT_ONVEHICLE), - UNIT_STAT_MOVING = (UNIT_STAT_ROAMING | UNIT_STAT_CHASE), + //UNIT_STAT_MOVING = (UNIT_STAT_ROAMING | UNIT_STAT_CHASE), + // for real move using movegen check and stop (except unstoppable flight) + UNIT_STAT_MOVING = UNIT_STAT_ROAMING_MOVE | UNIT_STAT_CONFUSED_MOVE | UNIT_STAT_FLEEING_MOVE| UNIT_STAT_CHASE_MOVE | UNIT_STAT_FOLLOW_MOVE , UNIT_STAT_CONTROLLED = (UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING), UNIT_STAT_LOST_CONTROL = (UNIT_STAT_CONTROLLED | UNIT_STAT_JUMPING | UNIT_STAT_CHARGING), UNIT_STAT_SIGHTLESS = (UNIT_STAT_LOST_CONTROL | UNIT_STAT_EVADE), UNIT_STAT_CANNOT_AUTOATTACK = (UNIT_STAT_LOST_CONTROL | UNIT_STAT_CASTING), UNIT_STAT_CANNOT_TURN = (UNIT_STAT_LOST_CONTROL | UNIT_STAT_ROTATING), + // stay by different reasons + UNIT_STAT_NOT_MOVE = UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DIED | UNIT_STAT_DISTRACTED, UNIT_STAT_ALL_STATE = 0xffffffff //(UNIT_STAT_STOPPED | UNIT_STAT_MOVING | UNIT_STAT_IN_COMBAT | UNIT_STAT_IN_FLIGHT) }; @@ -719,59 +727,18 @@ enum MovementFlags2 MOVEMENTFLAG2_UNK15 = 0x00004000, MOVEMENTFLAG2_UNK16 = 0x00008000, }; + enum SplineFlags { - SPLINEFLAG_NONE = 0x00000000, - SPLINEFLAG_FORWARD = 0x00000001, - SPLINEFLAG_BACKWARD = 0x00000002, - SPLINEFLAG_STRAFE_LEFT = 0x00000004, - SPLINEFLAG_STRAFE_RIGHT = 0x00000008, - SPLINEFLAG_LEFT = 0x00000010, - SPLINEFLAG_RIGHT = 0x00000020, - SPLINEFLAG_PITCH_UP = 0x00000040, - SPLINEFLAG_PITCH_DOWN = 0x00000080, - SPLINEFLAG_DONE = 0x00000100, - SPLINEFLAG_FALLING = 0x00000200, - SPLINEFLAG_NO_SPLINE = 0x00000400, - SPLINEFLAG_TRAJECTORY = 0x00000800, - SPLINEFLAG_WALKING = 0x00001000, - SPLINEFLAG_FLYING = 0x00002000, - SPLINEFLAG_KNOCKBACK = 0x00004000, - SPLINEFLAG_FINAL_POINT = 0x00008000, - SPLINEFLAG_FINAL_TARGET = 0x00010000, - SPLINEFLAG_FINAL_FACING = 0x00020000, - SPLINEFLAG_CATMULL_ROM = 0x00040000, - SPLINEFLAG_UNKNOWN20 = 0x00080000, - SPLINEFLAG_UNKNOWN21 = 0x00100000, - SPLINEFLAG_ANIMATIONTIER = 0x00200000, - SPLINEFLAG_UNKNOWN23 = 0x00400000, - SPLINEFLAG_TRANSPORT = 0x00800000, - SPLINEFLAG_EXIT_VEHICLE = 0x01000000, - SPLINEFLAG_UNKNOWN26 = 0x02000000, - SPLINEFLAG_UNKNOWN27 = 0x04000000, - SPLINEFLAG_UNKNOWN28 = 0x08000000, - SPLINEFLAG_UNKNOWN29 = 0x10000000, - SPLINEFLAG_ANIMATION = 0x20000000, - SPLINEFLAG_UNKNOWN31 = 0x40000000, - SPLINEFLAG_UNKNOWN32 = 0x80000000, - - SPLINEFLAG_GLIDE = SPLINEFLAG_WALKING | SPLINEFLAG_FLYING, -}; - -enum SplineMode -{ - SPLINEMODE_LINEAR = 0, - SPLINEMODE_CATMULL_ROM = 1, - SPLINEMODE_BEZIER3 = 2 + SPLINEFLAG_WALKMODE = 0x00001000, + SPLINEFLAG_FLYING = 0x00002000, + SPLINEFLAG_TRANSPORT = 0x00800000, + SPLINEFLAG_EXIT_VEHICLE = 0x01000000, }; enum SplineType { - SPLINETYPE_NORMAL = 0, - SPLINETYPE_STOP = 1, - SPLINETYPE_FACING_SPOT = 2, - SPLINETYPE_FACING_TARGET = 3, - SPLINETYPE_FACING_ANGLE = 4 + SPLINETYPE_FACING_ANGLE = 4, }; enum UnitTypeMask @@ -789,6 +756,10 @@ enum UnitTypeMask UNIT_MASK_ACCESSORY = 0x00000200, }; +namespace Movement{ + class MoveSpline; +} + enum DiminishingLevels { DIMINISHING_LEVEL_1 = 0, @@ -1628,20 +1599,18 @@ class Unit : public WorldObject void JumpTo(float speedXY, float speedZ, bool forward = true); void JumpTo(WorldObject* obj, float speedZ); - void SetFacing(float ori, WorldObject* obj = NULL); - void SendMonsterStop(bool on_death = false); - void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint32 Time, Player* player = NULL); - void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint32 MoveFlags, uint32 time, float speedZ, Player* player = NULL); - void SendMonsterMove(MonsterMoveData const& moveData, Player* receiver = NULL); + void MonsterMoveWithSpeed(float x, float y, float z, float speed); + //void SetFacing(float ori, WorldObject* obj = NULL); void SendMonsterMoveExitVehicle(Position const* newPos); //void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player = NULL); void SendMonsterMoveTransport(Unit* vehicleOwner); - void SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime = 0, Player* player = NULL); - void SendMonsterMoveWithSpeedToCurrentDestination(Player* player = NULL); void SendMovementFlagUpdate(); + bool IsLevitating() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_LEVITATING);} + bool IsWalking() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING);} - template - void SendMonsterMoveByPath(Path const& path, uint32 start, uint32 end); + void SetInFront(Unit const* target); + void SetFacingTo(float ori); + void SetFacingToObject(WorldObject* pObject); void SendChangeCurrentVictimOpcode(HostileReference* pHostileReference); void SendClearThreatListOpcode(); @@ -1951,13 +1920,7 @@ class Unit : public WorldObject void SetBaseWeaponDamage(WeaponAttackType attType, WeaponDamageRange damageRange, float value) { m_weaponDamage[attType][damageRange] = value; } bool isInFrontInMap(Unit const* target, float distance, float arc = M_PI) const; - void SetInFront(Unit const* target) - { - if (!HasUnitState(UNIT_STAT_CANNOT_TURN)) - SetOrientation(GetAngle(target)); - } bool isInBackInMap(Unit const* target, float distance, float arc = M_PI) const; - void SetFacingToObject(WorldObject* pObject); // Visibility system bool IsVisible() const { return (m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GM) > SEC_PLAYER) ? false : true; } @@ -2232,6 +2195,9 @@ class Unit : public WorldObject SetUInt64Value(UNIT_FIELD_TARGET, 0); } + // Movement info + Movement::MoveSpline * movespline; + protected: explicit Unit (bool isWorldObject); @@ -2303,6 +2269,8 @@ class Unit : public WorldObject bool IsAlwaysVisibleFor(WorldObject const* seer) const; bool IsAlwaysDetectableFor(WorldObject const* seer) const; + + void DisableSpline(); private: bool IsTriggeredAtSpellProcEvent(Unit* pVictim, Aura* aura, SpellInfo const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const* & spellProcEvent); bool HandleDummyAuraProc(Unit* pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown); @@ -2316,6 +2284,8 @@ class Unit : public WorldObject bool HandleAuraRaidProcFromChargeWithValue(AuraEffect* triggeredByAura); bool HandleAuraRaidProcFromCharge(AuraEffect* triggeredByAura); + void UpdateSplineMovement(uint32 t_diff); + // player or player's pet float GetCombatRatingReduction(CombatRating cr) const; uint32 GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const; @@ -2330,6 +2300,7 @@ class Unit : public WorldObject uint32 m_state; // Even derived shouldn't modify uint32 m_CombatTimer; uint32 m_lastManaUse; // msecs + TimeTrackerSmall m_movesplineTimer; Diminishing m_Diminishing; // Manage all Units that are threatened by us @@ -2382,31 +2353,4 @@ namespace Trinity const bool m_ascending; }; } - -template -inline void Unit::SendMonsterMoveByPath(Path const& path, uint32 start, uint32 end) -{ - uint32 traveltime = uint32(path.GetTotalLength(start, end) * 32); - uint32 pathSize = end - start; - WorldPacket data(SMSG_MONSTER_MOVE, (GetPackGUID().size()+1+4+4+4+4+1+4+4+4+pathSize*4*3)); - data.append(GetPackGUID()); - data << uint8(0); - data << GetPositionX(); - data << GetPositionY(); - data << GetPositionZ(); - data << uint32(getMSTime()); - data << uint8(0); - data << uint32(((GetUnitMovementFlags() & MOVEMENTFLAG_LEVITATING) || isInFlight()) ? (SPLINEFLAG_FLYING|SPLINEFLAG_WALKING) : SPLINEFLAG_WALKING); - data << uint32(traveltime); - data << uint32(pathSize); - - for (uint32 i = start; i < end; ++i) - { - data << float(path[i].x); - data << float(path[i].y); - data << float(path[i].z); - } - - SendMessageToSet(&data, true); -} #endif diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index b2f8e5608a7..df5ec540427 100755 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -1539,6 +1539,24 @@ inline GridMap* Map::GetGrid(float x, float y) return GridMaps[gx][gy]; } +float Map::GetWaterOrGroundLevel(float x, float y, float z, float* ground /*= NULL*/, bool swim /*= false*/) const +{ + if (const_cast(this)->GetGrid(x, y)) + { + // we need ground level (including grid height version) for proper return water level in point + float ground_z = GetHeight(x, y, z, true, 50.0f); + if (ground) + *ground = ground_z; + + LiquidData liquid_status; + + ZLiquidStatus res = getLiquidStatus(x, y, ground_z, MAP_ALL_LIQUIDS, &liquid_status); + return res ? ( swim ? liquid_status.level - 2.0f : liquid_status.level) : ground_z; + } + + return VMAP_INVALID_HEIGHT_VALUE; +} + float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const { // find raw .map surface under Z coordinates diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 9f6b936541e..f3b45bd8f37 100755 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -424,6 +424,8 @@ class Map : public GridRefManager InstanceMap* ToInstanceMap(){ if (IsDungeon()) return reinterpret_cast(this); else return NULL; } const InstanceMap* ToInstanceMap() const { if (IsDungeon()) return (const InstanceMap*)((InstanceMap*)this); else return NULL; } + float GetWaterOrGroundLevel(float x, float y, float z, float* ground = NULL, bool swim = false) const; + private: void LoadMapAndVMap(int gx, int gy); void LoadVMap(int gx, int gy); diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp index afb5aa5660f..0fb28008c1e 100755 --- a/src/server/game/Maps/MapManager.cpp +++ b/src/server/game/Maps/MapManager.cpp @@ -25,7 +25,6 @@ #include "GridDefines.h" #include "MapInstanced.h" #include "InstanceScript.h" -#include "DestinationHolderImp.h" #include "Config.h" #include "World.h" #include "CellImpl.h" diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 66610adc1f0..e751dbf92fe 100755 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -492,9 +492,9 @@ enum TrinityStrings LANG_MOVEGENS_WAYPOINT = 529, LANG_MOVEGENS_ANIMAL_RANDOM = 530, LANG_MOVEGENS_CONFUSED = 531, - LANG_MOVEGENS_TARGETED_PLAYER = 532, - LANG_MOVEGENS_TARGETED_CREATURE = 533, - LANG_MOVEGENS_TARGETED_NULL = 534, + LANG_MOVEGENS_CHASE_PLAYER = 532, + LANG_MOVEGENS_CHASE_CREATURE = 533, + LANG_MOVEGENS_CHASE_NULL = 534, LANG_MOVEGENS_HOME_CREATURE = 535, LANG_MOVEGENS_HOME_PLAYER = 536, LANG_MOVEGENS_FLIGHT = 537, @@ -807,7 +807,11 @@ enum TrinityStrings LANG_CHAR_NOT_BANNED = 1136, LANG_DEV_ON = 1137, LANG_DEV_OFF = 1138, - // Room for more level 3 1139-1199 not used + LANG_MOVEGENS_FOLLOW_PLAYER = 1139, + LANG_MOVEGENS_FOLLOW_CREATURE = 1140, + LANG_MOVEGENS_FOLLOW_NULL = 1141, + LANG_MOVEGENS_EFFECT = 1142, + // Room for more level 3 1143-1199 not used // Debug commands LANG_CINEMATIC_NOT_EXIST = 1200, diff --git a/src/server/game/Movement/DestinationHolder.cpp b/src/server/game/Movement/DestinationHolder.cpp deleted file mode 100755 index 4b763112968..00000000000 --- a/src/server/game/Movement/DestinationHolder.cpp +++ /dev/null @@ -1,20 +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 "DestinationHolder.h" - diff --git a/src/server/game/Movement/DestinationHolder.h b/src/server/game/Movement/DestinationHolder.h deleted file mode 100755 index 5ae4ee88ce3..00000000000 --- a/src/server/game/Movement/DestinationHolder.h +++ /dev/null @@ -1,65 +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 TRINITY_DESTINATION_HOLDER_H -#define TRINITY_DESTINATION_HOLDER_H - -#include "Define.h" -#include "Timer.h" - -class WorldObject; -class Map; - -#define TRAVELLER_UPDATE_INTERVAL 300 - -template -class DestinationHolder -{ - TimeTrackerSmall i_tracker; - uint32 i_totalTravelTime; - uint32 i_timeElapsed; - bool i_destSet; - float i_fromX, i_fromY, i_fromZ; - float i_destX, i_destY, i_destZ; - - public: - DestinationHolder() : i_tracker(TRAVELLER_UPDATE_INTERVAL), i_totalTravelTime(0), i_timeElapsed(0), - i_destSet(false), i_fromX(0), i_fromY(0), i_fromZ(0), i_destX(0), i_destY(0), i_destZ(0) {} - - uint32 SetDestination(TRAVELLER &traveller, float dest_x, float dest_y, float dest_z, bool sendMove = true); - void GetDestination(float &x, float &y, float &z) const { x = i_destX; y = i_destY; z = i_destZ; } - bool UpdateExpired(void) const { return i_tracker.Passed(); } - void ResetUpdate(uint32 t = TRAVELLER_UPDATE_INTERVAL) { i_tracker.Reset(t); } - uint32 GetTotalTravelTime(void) const { return i_totalTravelTime; } - void IncreaseTravelTime(uint32 increment) { i_totalTravelTime += increment; } - void ResetTravelTime() { i_totalTravelTime = 0; } - bool HasDestination(void) const { return i_destSet; } - float GetDestinationDiff(float x, float y, float z) const; - bool HasArrived(void) const { return (i_totalTravelTime == 0 || i_timeElapsed >= i_totalTravelTime); } - bool UpdateTraveller(TRAVELLER &traveller, uint32 diff, bool micro_movement=false); - uint32 StartTravel(TRAVELLER &traveller, bool sendMove = true); - void GetLocationNow(const Map* map, float &x, float &y, float &z, bool is3D = false) const; - void GetLocationNowNoMicroMovement(float &x, float &y, float &z) const; // For use without micro movement - float GetDistance3dFromDestSq(const WorldObject &obj) const; - - private: - void _findOffSetPoint(float x1, float y1, float x2, float y2, float offset, float &x, float &y); - -}; -#endif - diff --git a/src/server/game/Movement/DestinationHolderImp.h b/src/server/game/Movement/DestinationHolderImp.h deleted file mode 100755 index 4d6e6f0c741..00000000000 --- a/src/server/game/Movement/DestinationHolderImp.h +++ /dev/null @@ -1,215 +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 TRINITY_DESTINATIONHOLDERIMP_H -#define TRINITY_DESTINATIONHOLDERIMP_H - -#include "MapManager.h" -#include "DestinationHolder.h" - -#include - -template -void -DestinationHolder::_findOffSetPoint(float x1, float y1, float x2, float y2, float offset, float &x, float &y) -{ - /* given the point (x1, y1) and (x2, y2).. need to find the point (x, y) on the same line - * such that the distance from (x, y) to (x2, y2) is offset. - * Let the distance of p1 to p2 = d.. then the ratio of offset/d = (x2-x)/(x2-x1) - * hence x = x2 - (offset/d)*(x2-x1) - * like wise offset/d = (y2-y)/(y2-y1); - */ - if (offset == 0) - { - x = x2; - y = y2; - } - else - { - double x_diff = double(x2 - x1); - double y_diff = double(y2 - y1); - double distance_d = (double)((x_diff*x_diff) + (y_diff * y_diff)); - if (distance_d == 0) - { - x = x2; - y = y2; - } - else - { - distance_d = ::sqrt(distance_d); // starting distance - double distance_ratio = (double)(distance_d - offset)/(double)distance_d; - // line above has revised formula which is more correct, I think - x = (float)(x1 + (distance_ratio*x_diff)); - y = (float)(y1 + (distance_ratio*y_diff)); - } - } -} - -template -uint32 -DestinationHolder::SetDestination(TRAVELLER &traveller, float dest_x, float dest_y, float dest_z, bool sendMove) -{ - i_destSet = true; - i_destX = dest_x; - i_destY = dest_y; - i_destZ = dest_z; - - return StartTravel(traveller, sendMove); -} - -template -uint32 -DestinationHolder::StartTravel(TRAVELLER &traveller, bool sendMove) -{ - if (!i_destSet) return 0; - - i_fromX = traveller.GetPositionX(); - i_fromY = traveller.GetPositionY(); - i_fromZ = traveller.GetPositionZ(); - - i_totalTravelTime = traveller.GetTotalTrevelTimeTo(i_destX, i_destY, i_destZ); - i_timeElapsed = 0; - if (sendMove) - traveller.MoveTo(i_destX, i_destY, i_destZ, i_totalTravelTime); - return i_totalTravelTime; -} - -template -bool -DestinationHolder::UpdateTraveller(TRAVELLER &traveller, uint32 diff, bool micro_movement) -{ - i_timeElapsed += diff; - - // Update every TRAVELLER_UPDATE_INTERVAL - i_tracker.Update(diff); - if (!i_tracker.Passed()) - return false; - else - ResetUpdate(); - - if (!i_destSet) return true; - - float x, y, z; - if (!micro_movement) - GetLocationNowNoMicroMovement(x, y, z); - else - { - if (!traveller.GetTraveller().HasUnitState(UNIT_STAT_MOVING | UNIT_STAT_IN_FLIGHT)) - return true; - - if (traveller.GetTraveller().HasUnitState(UNIT_STAT_IN_FLIGHT)) - GetLocationNow(traveller.GetTraveller().GetBaseMap(), x, y, z, true); // Should reposition Object with right Coord, so I can bypass some Grid Relocation - else - GetLocationNow(traveller.GetTraveller().GetBaseMap(), x, y, z, false); - - // Change movement computation to micro movement based on last tick coords, this makes system work - // even on multiple floors zones without hugh vmaps usage ;) - - // Take care of underrun of uint32 - if (i_totalTravelTime >= i_timeElapsed) - i_totalTravelTime -= i_timeElapsed; // Consider only the remaining part - else - i_totalTravelTime = 0; - - i_timeElapsed = 0; - i_fromX = x; // and change origine - i_fromY = y; // then I take into account only micro movement - i_fromZ = z; - } - - if (traveller.GetTraveller().GetPositionX() != x || traveller.GetTraveller().GetPositionY() != y || traveller.GetTraveller().GetPositionZ() != z) - { - float ori = traveller.GetTraveller().GetAngle(x, y); - traveller.Relocation(x, y, z, ori); - } - - return true; -} - -template -void -DestinationHolder::GetLocationNow(const Map* map, float &x, float &y, float &z, bool is3D) const -{ - if (HasArrived()) - { - x = i_destX; - y = i_destY; - z = i_destZ; - } - else if (HasDestination()) - { - double percent_passed = (double)i_timeElapsed / (double)i_totalTravelTime; - const float distanceX = (float)((i_destX - i_fromX) * percent_passed); - const float distanceY = (float)((i_destY - i_fromY) * percent_passed); - const float distanceZ = (float)((i_destZ - i_fromZ) * percent_passed); - x = i_fromX + distanceX; - y = i_fromY + distanceY; - float z2 = i_fromZ + distanceZ; - // All that is not finished but previous code neither... Traveller need be able to swim. - if (is3D) - z = z2; - else - { - //That part is good for mob Walking on the floor. But the floor is not always what we thought. - z = map->GetHeight(x, y, i_fromZ, false); // Disable cave check - const float groundDist = sqrt(distanceX*distanceX + distanceY*distanceY); - const float zDist = fabs(i_fromZ - z) + 0.000001f; - const float slope = groundDist / zDist; - if (slope < 1.0f) // This prevents the ground returned by GetHeight to be used when in cave - z = z2; // a climb or jump of more than 45 is denied - } - } -} - -template -float -DestinationHolder::GetDistance3dFromDestSq(const WorldObject &obj) const -{ - float x, y, z; - obj.GetPosition(x, y, z); - return (i_destX-x)*(i_destX-x)+(i_destY-y)*(i_destY-y)+(i_destZ-z)*(i_destZ-z); -} - -template -float -DestinationHolder::GetDestinationDiff(float x, float y, float z) const -{ - return sqrt(((x-i_destX)*(x-i_destX)) + ((y-i_destY)*(y-i_destY)) + ((z-i_destZ)*(z-i_destZ))); -} - -template -void -DestinationHolder::GetLocationNowNoMicroMovement(float &x, float &y, float &z) const -{ - if (HasArrived()) - { - x = i_destX; - y = i_destY; - z = i_destZ; - } - else - { - double percent_passed = (double)i_timeElapsed / (double)i_totalTravelTime; - x = (float)(i_fromX + ((i_destX - i_fromX) * percent_passed)); - y = (float)(i_fromY + ((i_destY - i_fromY) * percent_passed)); - z = (float)(i_fromZ + ((i_destZ - i_fromZ) * percent_passed)); - } -} - -#endif - diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index 6660da146f0..2656d882009 100755 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -19,7 +19,6 @@ #include "MotionMaster.h" #include "CreatureAISelector.h" #include "Creature.h" -#include "Traveller.h" #include "ConfusedMovementGenerator.h" #include "FleeingMovementGenerator.h" @@ -29,7 +28,8 @@ #include "TargetedMovementGenerator.h" #include "WaypointMovementGenerator.h" #include "RandomMovementGenerator.h" - +#include "MoveSpline.h" +#include "MoveSplineInit.h" #include inline bool isStatic(MovementGenerator *mv) @@ -193,16 +193,23 @@ void MotionMaster::MoveRandom(float spawndist) void MotionMaster::MoveTargetedHome() { - //if (i_owner->HasUnitState(UNIT_STAT_FLEEING)) - // return; - Clear(false); - if (i_owner->GetTypeId() == TYPEID_UNIT) + if (i_owner->GetTypeId()==TYPEID_UNIT && !((Creature*)i_owner)->GetCharmerOrOwnerGUID()) { sLog->outStaticDebug("Creature (Entry: %u GUID: %u) targeted home", i_owner->GetEntry(), i_owner->GetGUIDLow()); Mutate(new HomeMovementGenerator(), MOTION_SLOT_ACTIVE); } + else if (i_owner->GetTypeId()==TYPEID_UNIT && ((Creature*)i_owner)->GetCharmerOrOwnerGUID()) + { + sLog->outStaticDebug("Pet or controlled creature (Entry: %u GUID: %u) targeting home", i_owner->GetEntry(), i_owner->GetGUIDLow() ); + Unit *target = ((Creature*)i_owner)->GetCharmerOrOwner(); + if (target) + { + sLog->outStaticDebug("Following %s (GUID: %u)", target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : ((Creature*)target)->GetDBTableGUIDLow() ); + Mutate(new FollowMovementGenerator(*target,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE), MOTION_SLOT_ACTIVE); + } + } else { sLog->outError("Player (GUID: %u) attempt targeted home", i_owner->GetGUIDLow()); @@ -230,14 +237,14 @@ void MotionMaster::MoveChase(Unit* target, float dist, float angle) if (!target || target == i_owner || i_owner->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE)) return; - i_owner->ClearUnitState(UNIT_STAT_FOLLOW); + //i_owner->ClearUnitState(UNIT_STAT_FOLLOW); if (i_owner->GetTypeId() == TYPEID_PLAYER) { sLog->outStaticDebug("Player (GUID: %u) chase to %s (GUID: %u)", i_owner->GetGUIDLow(), target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow()); - Mutate(new TargetedMovementGenerator(*target, dist, angle), MOTION_SLOT_ACTIVE); + Mutate(new ChaseMovementGenerator(*target,dist,angle), MOTION_SLOT_ACTIVE); } else { @@ -245,7 +252,7 @@ void MotionMaster::MoveChase(Unit* target, float dist, float angle) i_owner->GetEntry(), i_owner->GetGUIDLow(), target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow()); - Mutate(new TargetedMovementGenerator(*target, dist, angle), MOTION_SLOT_ACTIVE); + Mutate(new ChaseMovementGenerator(*target,dist,angle), MOTION_SLOT_ACTIVE); } } @@ -255,13 +262,13 @@ void MotionMaster::MoveFollow(Unit* target, float dist, float angle, MovementSlo if (!target || target == i_owner || i_owner->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE)) return; - i_owner->AddUnitState(UNIT_STAT_FOLLOW); + //i_owner->AddUnitState(UNIT_STAT_FOLLOW); if (i_owner->GetTypeId() == TYPEID_PLAYER) { sLog->outStaticDebug("Player (GUID: %u) follow to %s (GUID: %u)", i_owner->GetGUIDLow(), target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow()); - Mutate(new TargetedMovementGenerator(*target, dist, angle), slot); + Mutate(new FollowMovementGenerator(*target,dist,angle), slot); } else { @@ -269,7 +276,7 @@ void MotionMaster::MoveFollow(Unit* target, float dist, float angle, MovementSlo i_owner->GetEntry(), i_owner->GetGUIDLow(), target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow()); - Mutate(new TargetedMovementGenerator(*target, dist, angle), slot); + Mutate(new FollowMovementGenerator(*target,dist,angle), slot); } } @@ -290,54 +297,32 @@ void MotionMaster::MovePoint(uint32 id, float x, float y, float z) void MotionMaster::MoveLand(uint32 id, Position const& pos, float speed) { - if (i_owner->GetTypeId() != TYPEID_UNIT) - return; - - uint32 moveFlag = SPLINEFLAG_FLYING | SPLINEFLAG_ANIMATIONTIER; - uint32 moveTime = uint32(i_owner->GetExactDist(&pos) / speed) * IN_MILLISECONDS; - - // CHARGING state makes the unit use m_TempSpeed and JUMPING prevents sending movement packet in PointMovementGenerator - i_owner->AddUnitState(UNIT_STAT_CHARGING | UNIT_STAT_JUMPING); - i_owner->m_TempSpeed = speed; - float x, y, z; pos.GetPosition(x, y, z); - sLog->outStaticDebug("Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)", i_owner->GetEntry(), id, x, y, z); - Mutate(new PointMovementGenerator(id, x, y, z), MOTION_SLOT_ACTIVE); - MonsterMoveData data; - data.DestLocation.Relocate(pos); - data.SplineFlag = moveFlag; - data.Time = moveTime; - data.AnimationState = ANIMATION_ON_GROUND; + sLog->outStaticDebug("Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)", i_owner->GetEntry(), id, x, y, z); - i_owner->SendMonsterMove(data); + Movement::MoveSplineInit init(*i_owner); + init.MoveTo(x,y,z); + init.SetVelocity(speed); + init.SetAnimation(Movement::ToGround); + init.Launch(); + Mutate(new EffectMovementGenerator(id), MOTION_SLOT_CONTROLLED); } void MotionMaster::MoveTakeoff(uint32 id, Position const& pos, float speed) { - if (i_owner->GetTypeId() != TYPEID_UNIT) - return; - - uint32 moveFlag = SPLINEFLAG_FLYING | SPLINEFLAG_ANIMATIONTIER; - uint32 moveTime = uint32(i_owner->GetExactDist(&pos) / speed) * IN_MILLISECONDS; - - // CHARGING state makes the unit use m_TempSpeed and JUMPING prevents sending movement packet in PointMovementGenerator - i_owner->AddUnitState(UNIT_STAT_CHARGING | UNIT_STAT_JUMPING); - i_owner->m_TempSpeed = speed; - float x, y, z; pos.GetPosition(x, y, z); - sLog->outStaticDebug("Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)", i_owner->GetEntry(), id, x, y, z); - Mutate(new PointMovementGenerator(id, x, y, z), MOTION_SLOT_ACTIVE); - MonsterMoveData data; - data.DestLocation.Relocate(pos); - data.SplineFlag = moveFlag; - data.Time = moveTime; - data.AnimationState = ANIMATION_FLYING; + sLog->outStaticDebug("Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)", i_owner->GetEntry(), id, x, y, z); - i_owner->SendMonsterMove(data); + Movement::MoveSplineInit init(*i_owner); + init.MoveTo(x,y,z); + init.SetVelocity(speed); + init.SetAnimation(Movement::ToFly); + init.Launch(); + Mutate(new EffectMovementGenerator(id), MOTION_SLOT_CONTROLLED); } void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ) @@ -347,7 +332,9 @@ void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, floa return; float x, y, z; - float dist = speedXY * speedZ * 0.1f; + float moveTimeHalf = speedZ / Movement::gravity; + float dist = 2 * moveTimeHalf * speedXY; + i_owner->GetNearPoint(i_owner, x, y, z, i_owner->GetObjectSize(), dist, i_owner->GetAngle(srcX, srcY) + M_PI); MoveJump(x, y, z, speedXY, speedZ); } @@ -359,35 +346,48 @@ void MotionMaster::MoveJumpTo(float angle, float speedXY, float speedZ) return; float x, y, z; - float dist = speedXY * speedZ * 0.1f; + + float moveTimeHalf = speedZ / Movement::gravity; + float dist = 2 * moveTimeHalf * speedXY; i_owner->GetClosePoint(x, y, z, i_owner->GetObjectSize(), dist, angle); MoveJump(x, y, z, speedXY, speedZ); } -void MotionMaster::MoveJump(float x, float y, float z, float speedXY, float speedZ) +void MotionMaster::MoveJump(float x, float y, float z, float speedXY, float speedZ, uint32 id) { - uint32 moveFlag = SPLINEFLAG_TRAJECTORY | SPLINEFLAG_WALKING; - uint32 time = uint32(speedZ * 100); + sLog->outStaticDebug("Unit (GUID: %u) jump to point (X: %f Y: %f Z: %f)", i_owner->GetGUIDLow(), x, y, z); - // Instantly interrupt non melee spells being casted - if (i_owner->IsNonMeleeSpellCasted(true)) - i_owner->InterruptNonMeleeSpells(true); + float moveTimeHalf = speedZ / Movement::gravity; + float max_height = -Movement::computeFallElevation(moveTimeHalf,false,-speedZ); - i_owner->AddUnitState(UNIT_STAT_CHARGING | UNIT_STAT_JUMPING); - i_owner->m_TempSpeed = speedXY; - if (i_owner->GetTypeId() == TYPEID_PLAYER) - { - sLog->outStaticDebug("Player (GUID: %u) jump to point (X: %f Y: %f Z: %f)", i_owner->GetGUIDLow(), x, y, z); - Mutate(new PointMovementGenerator(0, x, y, z), MOTION_SLOT_CONTROLLED); - } - else + Movement::MoveSplineInit init(*i_owner); + init.MoveTo(x,y,z); + init.SetParabolic(max_height,0); + init.SetVelocity(speedXY); + init.Launch(); + Mutate(new EffectMovementGenerator(id), MOTION_SLOT_CONTROLLED); +} + +void MotionMaster::MoveFall() +{ + // use larger distance for vmap height search than in most other cases + float tz = i_owner->GetMap()->GetHeight(i_owner->GetPositionX(), i_owner->GetPositionY(), i_owner->GetPositionZ(), true, MAX_FALL_DISTANCE); + if (tz <= INVALID_HEIGHT) { - sLog->outStaticDebug("Creature (Entry: %u GUID: %u) jump to point (X: %f Y: %f Z: %f)", - i_owner->GetEntry(), i_owner->GetGUIDLow(), x, y, z); - Mutate(new PointMovementGenerator(0, x, y, z), MOTION_SLOT_CONTROLLED); + sLog->outStaticDebug("MotionMaster::MoveFall: unable retrive a proper height at map %u (x: %f, y: %f, z: %f).", + i_owner->GetMap()->GetId(), i_owner->GetPositionX(), i_owner->GetPositionX(), i_owner->GetPositionZ()); + return; } - i_owner->SendMonsterMove(x, y, z, moveFlag, time, speedZ); + // Abort too if the ground is very near + if (fabs(i_owner->GetPositionZ() - tz) < 0.1f) + return; + + Movement::MoveSplineInit init(*i_owner); + init.MoveTo(i_owner->GetPositionX(),i_owner->GetPositionY(),tz); + init.SetFall(); + init.Launch(); + Mutate(new EffectMovementGenerator(0), MOTION_SLOT_CONTROLLED); } void MotionMaster::MoveCharge(float x, float y, float z, float speed, uint32 id) @@ -395,29 +395,19 @@ void MotionMaster::MoveCharge(float x, float y, float z, float speed, uint32 id) if (Impl[MOTION_SLOT_CONTROLLED] && Impl[MOTION_SLOT_CONTROLLED]->GetMovementGeneratorType() != DISTRACT_MOTION_TYPE) return; - i_owner->AddUnitState(UNIT_STAT_CHARGING); - i_owner->m_TempSpeed = speed; if (i_owner->GetTypeId() == TYPEID_PLAYER) { sLog->outStaticDebug("Player (GUID: %u) charge point (X: %f Y: %f Z: %f)", i_owner->GetGUIDLow(), x, y, z); - Mutate(new PointMovementGenerator(id, x, y, z), MOTION_SLOT_CONTROLLED); + Mutate(new PointMovementGenerator(id, x, y, z, speed), MOTION_SLOT_CONTROLLED); } else { sLog->outStaticDebug("Creature (Entry: %u GUID: %u) charge point (X: %f Y: %f Z: %f)", i_owner->GetEntry(), i_owner->GetGUIDLow(), x, y, z); - Mutate(new PointMovementGenerator(id, x, y, z), MOTION_SLOT_CONTROLLED); + Mutate(new PointMovementGenerator(id, x, y, z, speed), MOTION_SLOT_CONTROLLED); } } -void MotionMaster::MoveFall(float z, uint32 id) -{ - i_owner->SetFlying(false); - i_owner->SendMovementFlagUpdate(); - //AddUnitMovementFlag(MOVEMENTFLAG_FALLING); - MoveCharge(i_owner->GetPositionX(), i_owner->GetPositionY(), z, SPEED_CHARGE, id); -} - void MotionMaster::MoveSeekAssistance(float x, float y, float z) { if (i_owner->GetTypeId() == TYPEID_PLAYER) @@ -561,7 +551,7 @@ void MotionMaster::MovePath(uint32 path_id, bool repeatable) //i_owner->GetTypeId() == TYPEID_PLAYER ? //Mutate(new WaypointMovementGenerator(path_id, repeatable)): - Mutate(new WaypointMovementGenerator(path_id, repeatable), MOTION_SLOT_IDLE); + Mutate(new WaypointMovementGenerator(path_id, repeatable), MOTION_SLOT_IDLE); sLog->outStaticDebug("%s (GUID: %u) start moving over path(Id:%u, repeatable: %s)", i_owner->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature", @@ -632,8 +622,12 @@ void MotionMaster::DelayedDelete(_Ty curr) bool MotionMaster::GetDestination(float &x, float &y, float &z) { - if (empty()) + if (i_owner->movespline->Finalized()) return false; - return top()->GetDestination(x, y, z); + const G3D::Vector3& dest = i_owner->movespline->FinalDestination(); + x = dest.x; + y = dest.y; + z = dest.z; + return true; } diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h index a972c3b06ce..00f1701e591 100755 --- a/src/server/game/Movement/MotionMaster.h +++ b/src/server/game/Movement/MotionMaster.h @@ -39,7 +39,7 @@ enum MovementGeneratorType MAX_DB_MOTION_TYPE = 3, // *** this and below motion types can't be set in DB. ANIMAL_RANDOM_MOTION_TYPE = MAX_DB_MOTION_TYPE, // AnimalRandomMovementGenerator.h CONFUSED_MOTION_TYPE = 4, // ConfusedMovementGenerator.h - TARGETED_MOTION_TYPE = 5, // TargetedMovementGenerator.h + CHASE_MOTION_TYPE = 5, // TargetedMovementGenerator.h HOME_MOTION_TYPE = 6, // HomeMovementGenerator.h FLIGHT_MOTION_TYPE = 7, // WaypointMovementGenerator.h POINT_MOTION_TYPE = 8, // PointMovementGenerator.h @@ -48,8 +48,10 @@ enum MovementGeneratorType ASSISTANCE_MOTION_TYPE= 11, // PointMovementGenerator.h (first part of flee for assistance) ASSISTANCE_DISTRACT_MOTION_TYPE = 12, // IdleMovementGenerator.h (second part of flee for assistance) TIMED_FLEEING_MOTION_TYPE = 13, // FleeingMovementGenerator.h (alt.second part of flee for assistance) - ROTATE_MOTION_TYPE = 14, - NULL_MOTION_TYPE = 15, + FOLLOW_MOTION_TYPE = 14, + ROTATE_MOTION_TYPE = 15, + EFFECT_MOTION_TYPE = 16, + NULL_MOTION_TYPE = 17, }; enum MovementSlot @@ -86,7 +88,6 @@ class MotionMaster //: private std::stack typedef std::vector<_Ty> ExpireList; int i_top; - bool empty() const { return (i_top < 0); } void pop() { Impl[i_top] = NULL; --i_top; } void push(_Ty _Val) { ++i_top; Impl[i_top] = _Val; } @@ -107,6 +108,7 @@ class MotionMaster //: private std::stack void Initialize(); void InitDefault(); + bool empty() const { return (i_top < 0); } int size() const { return i_top + 1; } _Ty top() const { return Impl[i_top]; } _Ty GetMotionSlot(int slot) const { return Impl[slot]; } @@ -158,10 +160,11 @@ class MotionMaster //: private std::stack void MoveTakeoff(uint32 id, Position const& pos, float speed); void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE, uint32 id = EVENT_CHARGE); - void MoveFall(float z, uint32 id = 0); void MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ); void MoveJumpTo(float angle, float speedXY, float speedZ); - void MoveJump(float x, float y, float z, float speedXY, float speedZ); + void MoveJump(float x, float y, float z, float speedXY, float speedZ, uint32 id = 0); + void MoveFall(); + void MoveSeekAssistance(float x, float y, float z); void MoveSeekAssistanceDistract(uint32 timer); void MoveTaxiFlight(uint32 path, uint32 pathnode); diff --git a/src/server/game/Movement/MovementGenerator.cpp b/src/server/game/Movement/MovementGenerator.cpp index 103b8876959..73921ea86ff 100755 --- a/src/server/game/Movement/MovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerator.cpp @@ -21,4 +21,3 @@ MovementGenerator::~MovementGenerator() { } - diff --git a/src/server/game/Movement/MovementGenerator.h b/src/server/game/Movement/MovementGenerator.h index 06450d938ae..dd9ba32f337 100755 --- a/src/server/game/Movement/MovementGenerator.h +++ b/src/server/game/Movement/MovementGenerator.h @@ -43,8 +43,6 @@ class MovementGenerator virtual MovementGeneratorType GetMovementGeneratorType() = 0; virtual void unitSpeedChanged() { } - - virtual bool GetDestination(float& /*x*/, float& /*y*/, float& /*z*/) const { return false; } }; template diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp index bf5c8bafc49..ac09f2d403a 100755 --- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp @@ -18,10 +18,10 @@ #include "Creature.h" #include "MapManager.h" -#include "Opcodes.h" #include "ConfusedMovementGenerator.h" -#include "DestinationHolderImp.h" #include "VMapFactory.h" +#include "MoveSplineInit.h" +#include "MoveSpline.h" #ifdef MAP_BASED_RAND_GEN #define rand_norm() unit.rand_norm() @@ -31,8 +31,8 @@ template void ConfusedMovementGenerator::Initialize(T &unit) { - float const wanderDistance = 4; - float x, y, z; + const float wander_distance=4; + float x,y,z; x = unit.GetPositionX(); y = unit.GetPositionY(); z = unit.GetPositionZ(); @@ -44,52 +44,33 @@ void ConfusedMovementGenerator::Initialize(T &unit) bool is_water_ok, is_land_ok; _InitSpecific(unit, is_water_ok, is_land_ok); - for (uint8 idx = 0; idx <= MAX_CONF_WAYPOINTS; ++idx) + for (uint8 idx = 0; idx < MAX_CONF_WAYPOINTS + 1; ++idx) { - float wanderX = x + wanderDistance * (float)rand_norm() - wanderDistance/2; - float wanderY = y + wanderDistance * (float)rand_norm() - wanderDistance/2; - Trinity::NormalizeMapCoord(wanderX); - Trinity::NormalizeMapCoord(wanderY); + const float wanderX=wander_distance*(float)rand_norm() - wander_distance/2; + const float wanderY=wander_distance*(float)rand_norm() - wander_distance/2; - float new_z = map->GetHeight(wanderX, wanderY, z, true); - if (new_z > INVALID_HEIGHT && unit.IsWithinLOS(wanderX, wanderY, new_z)) - { - // Don't move in water if we're not already in - // Don't move on land if we're not already on it either - bool is_water_now = map->IsInWater(x, y, z); - bool is_water_next = map->IsInWater(wanderX, wanderY, new_z); - if ((is_water_now && !is_water_next && !is_land_ok) || (!is_water_now && is_water_next && !is_water_ok)) - { - i_waypoints[idx][0] = idx > 0 ? i_waypoints[idx-1][0] : x; // Back to previous location - i_waypoints[idx][1] = idx > 0 ? i_waypoints[idx-1][1] : y; - i_waypoints[idx][2] = idx > 0 ? i_waypoints[idx-1][2] : z; - continue; - } - - // Taken from FleeingMovementGenerator - if (!(new_z - z) || wanderDistance / fabs(new_z - z) > 1.0f) - { - i_waypoints[idx][0] = wanderX; - i_waypoints[idx][1] = wanderY; - i_waypoints[idx][2] = new_z; - continue; - } - } - else // Back to previous location + i_waypoints[idx][0] = x + wanderX; + i_waypoints[idx][1] = y + wanderY; + + // prevent invalid coordinates generation + Trinity::NormalizeMapCoord(i_waypoints[idx][0]); + Trinity::NormalizeMapCoord(i_waypoints[idx][1]); + + bool is_water = map->IsInWater(i_waypoints[idx][0],i_waypoints[idx][1],z); + // if generated wrong path just ignore + if ((is_water && !is_water_ok) || (!is_water && !is_land_ok)) { i_waypoints[idx][0] = idx > 0 ? i_waypoints[idx-1][0] : x; i_waypoints[idx][1] = idx > 0 ? i_waypoints[idx-1][1] : y; - i_waypoints[idx][2] = idx > 0 ? i_waypoints[idx-1][2] : z; - continue; } + + unit.UpdateAllowedPositionZ(i_waypoints[idx][0], i_waypoints[idx][1], z); + i_waypoints[idx][2] = z; } - unit.SetTarget(0); - unit.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); - unit.CastStop(); unit.StopMoving(); - unit.AddUnitMovementFlag(MOVEMENTFLAG_WALKING); // Should actually be splineflag - unit.AddUnitState(UNIT_STAT_CONFUSED); + unit.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); + unit.AddUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE); } template<> @@ -111,69 +92,70 @@ void ConfusedMovementGenerator::Reset(T &unit) { i_nextMove = 1; i_nextMoveTime.Reset(0); - i_destinationHolder.ResetUpdate(); unit.StopMoving(); + unit.AddUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE); } template -bool ConfusedMovementGenerator::Update(T &unit, const uint32 diff) +bool ConfusedMovementGenerator::Update(T &unit, const uint32 &diff) { - if (!&unit) - return true; - if (unit.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED)) return true; if (i_nextMoveTime.Passed()) { // currently moving, update location - Traveller traveller(unit); - if (i_destinationHolder.UpdateTraveller(traveller, diff)) + unit.AddUnitState(UNIT_STAT_CONFUSED_MOVE); + + if (unit.movespline->Finalized()) { - if (i_destinationHolder.HasArrived()) - { - // arrived, stop and wait a bit - unit.ClearUnitState(UNIT_STAT_MOVE); - - i_nextMove = urand(1, MAX_CONF_WAYPOINTS); - i_nextMoveTime.Reset(urand(100, 1000)); - } + i_nextMove = urand(1,MAX_CONF_WAYPOINTS); + i_nextMoveTime.Reset(urand(0, 1500-1)); // TODO: check the minimum reset time, should be probably higher } } else { // waiting for next move i_nextMoveTime.Update(diff); - if (i_nextMoveTime.Passed()) + if(i_nextMoveTime.Passed() ) { // start moving - ASSERT(i_nextMove <= MAX_CONF_WAYPOINTS); - const float x = i_waypoints[i_nextMove][0]; - const float y = i_waypoints[i_nextMove][1]; - const float z = i_waypoints[i_nextMove][2]; - Traveller traveller(unit); - i_destinationHolder.SetDestination(traveller, x, y, z); + unit.AddUnitState(UNIT_STAT_CONFUSED_MOVE); + + ASSERT( i_nextMove <= MAX_CONF_WAYPOINTS ); + float x = i_waypoints[i_nextMove][0]; + float y = i_waypoints[i_nextMove][1]; + float z = i_waypoints[i_nextMove][2]; + Movement::MoveSplineInit init(unit); + init.MoveTo(x, y, z); + init.SetWalk(true); + init.Launch(); } } + return true; } -template -void ConfusedMovementGenerator::Finalize(T &unit) +template<> +void ConfusedMovementGenerator::Finalize(Player &unit) { unit.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); - unit.ClearUnitState(UNIT_STAT_CONFUSED); + unit.ClearUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE); +} - if (unit.GetTypeId() == TYPEID_UNIT && unit.getVictim()) +template<> +void ConfusedMovementGenerator::Finalize(Creature &unit) +{ + unit.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); + unit.ClearUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE); + if (unit.getVictim()) unit.SetTarget(unit.getVictim()->GetGUID()); } template void ConfusedMovementGenerator::Initialize(Player &player); template void ConfusedMovementGenerator::Initialize(Creature &creature); -template void ConfusedMovementGenerator::Finalize(Player &player); -template void ConfusedMovementGenerator::Finalize(Creature &creature); template void ConfusedMovementGenerator::Reset(Player &player); template void ConfusedMovementGenerator::Reset(Creature &creature); -template bool ConfusedMovementGenerator::Update(Player &player, const uint32 diff); -template bool ConfusedMovementGenerator::Update(Creature &creature, const uint32 diff); +template bool ConfusedMovementGenerator::Update(Player &player, const uint32 &diff); +template bool ConfusedMovementGenerator::Update(Creature &creature, const uint32 &diff); diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h index d3981ee2dcf..b9f96bb785d 100755 --- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h @@ -20,8 +20,7 @@ #define TRINITY_CONFUSEDGENERATOR_H #include "MovementGenerator.h" -#include "DestinationHolder.h" -#include "Traveller.h" +#include "Timer.h" #define MAX_CONF_WAYPOINTS 24 @@ -35,21 +34,13 @@ class ConfusedMovementGenerator void Initialize(T &); void Finalize(T &); void Reset(T &); - bool Update(T &, const uint32); - - bool GetDestination(float &x, float &y, float &z) const - { - if (i_destinationHolder.HasArrived()) return false; - i_destinationHolder.GetDestination(x, y, z); - return true; - } + bool Update(T &, const uint32 &); MovementGeneratorType GetMovementGeneratorType() { return CONFUSED_MOTION_TYPE; } private: void _InitSpecific(T &, bool &, bool &); TimeTracker i_nextMoveTime; float i_waypoints[MAX_CONF_WAYPOINTS+1][3]; - DestinationHolder< Traveller > i_destinationHolder; uint32 i_nextMove; }; #endif diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp index d2b3fcee384..458e6f9a62c 100755 --- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp @@ -20,8 +20,9 @@ #include "CreatureAI.h" #include "MapManager.h" #include "FleeingMovementGenerator.h" -#include "DestinationHolderImp.h" #include "ObjectAccessor.h" +#include "MoveSplineInit.h" +#include "MoveSpline.h" #define MIN_QUIET_DISTANCE 28.0f #define MAX_QUIET_DISTANCE 43.0f @@ -43,25 +44,12 @@ FleeingMovementGenerator::_setTargetLocation(T &owner) if (!_getPoint(owner, x, y, z)) return; - owner.AddUnitState(UNIT_STAT_FLEEING | UNIT_STAT_ROAMING); - Traveller traveller(owner); - i_destinationHolder.SetDestination(traveller, x, y, z); -} - -template<> -bool FleeingMovementGenerator::GetDestination(float &x, float &y, float &z) const -{ - if (i_destinationHolder.HasArrived()) - return false; + owner.AddUnitState(UNIT_STAT_FLEEING_MOVE); - i_destinationHolder.GetDestination(x, y, z); - return true; -} - -template<> -bool FleeingMovementGenerator::GetDestination(float & /*x*/, float & /*y*/, float & /*z*/) const -{ - return false; + Movement::MoveSplineInit init(owner); + init.MoveTo(x,y,z); + init.SetWalk(false); + init.Launch(); } template @@ -75,10 +63,10 @@ FleeingMovementGenerator::_getPoint(T &owner, float &x, float &y, float &z) y = owner.GetPositionY(); z = owner.GetPositionZ(); - float temp_x, temp_y, angle = 0; + float temp_x, temp_y, angle; const Map* _map = owner.GetBaseMap(); //primitive path-finding - for (uint8 i = 0; i < 18; ++i) + for(uint8 i = 0; i < 18; ++i) { if (i_only_forward && i > 2) break; @@ -143,11 +131,11 @@ FleeingMovementGenerator::_getPoint(T &owner, float &x, float &y, float &z) distance /= 4; break; case 15: - angle = i_cur_angle + static_cast(M_PI*3/4); + angle = i_cur_angle + static_cast(3*M_PI/4); distance /= 2; break; case 16: - angle = i_cur_angle - static_cast(M_PI*3/4); + angle = i_cur_angle - static_cast(3*M_PI/4); distance /= 2; break; case 17: @@ -161,9 +149,9 @@ FleeingMovementGenerator::_getPoint(T &owner, float &x, float &y, float &z) Trinity::NormalizeMapCoord(temp_y); if (owner.IsWithinLOS(temp_x, temp_y, z)) { - bool is_water_now = _map->IsInWater(x, y, z); + bool is_water_now = _map->IsInWater(x,y,z); - if (is_water_now && _map->IsInWater(temp_x, temp_y, z)) + if (is_water_now && _map->IsInWater(temp_x,temp_y,z)) { x = temp_x; y = temp_y; @@ -181,8 +169,8 @@ FleeingMovementGenerator::_getPoint(T &owner, float &x, float &y, float &z) if (!(new_z - z) || distance / fabs(new_z - z) > 1.0f) { - float new_z_left = _map->GetHeight(temp_x + (float)(cos(angle+M_PI/2)), temp_y + (float)(sin(angle+M_PI/2)), z, true); - float new_z_right = _map->GetHeight(temp_x + (float)(cos(angle-M_PI/2)), temp_y + (float)(sin(angle-M_PI/2)), z, true); + float new_z_left = _map->GetHeight(temp_x + 1.0f*cos(angle+static_cast(M_PI/2)),temp_y + 1.0f*sin(angle+static_cast(M_PI/2)),z,true); + float new_z_right = _map->GetHeight(temp_x + 1.0f*cos(angle-static_cast(M_PI/2)),temp_y + 1.0f*sin(angle-static_cast(M_PI/2)),z,true); if (fabs(new_z_left - new_z) < 1.2f && fabs(new_z_right - new_z) < 1.2f) { x = temp_x; @@ -194,7 +182,7 @@ FleeingMovementGenerator::_getPoint(T &owner, float &x, float &y, float &z) } } i_to_distance_from_caster = 0.0f; - i_nextCheckTime.Reset(urand(500, 1000)); + i_nextCheckTime.Reset( urand(500,1000) ); return false; } @@ -213,12 +201,12 @@ FleeingMovementGenerator::_setMoveData(T &owner) (i_last_distance_from_caster < i_to_distance_from_caster && cur_dist_xyz > i_to_distance_from_caster) || // if we reach bigger distance (cur_dist_xyz > MAX_QUIET_DISTANCE) || // if we are too far - (i_last_distance_from_caster > MIN_QUIET_DISTANCE && cur_dist_xyz < MIN_QUIET_DISTANCE)) + (i_last_distance_from_caster > MIN_QUIET_DISTANCE && cur_dist_xyz < MIN_QUIET_DISTANCE) ) // if we leave 'quiet zone' { // we are very far or too close, stopping i_to_distance_from_caster = 0.0f; - i_nextCheckTime.Reset(urand(500, 1000)); + i_nextCheckTime.Reset( urand(500,1000) ); return false; } else @@ -232,9 +220,7 @@ FleeingMovementGenerator::_setMoveData(T &owner) float cur_dist; float angle_to_caster; - Unit* fright = ObjectAccessor::GetUnit(owner, i_frightGUID); - - if (fright) + if (Unit* fright = ObjectAccessor::GetUnit(owner, i_frightGUID)) { cur_dist = fright->GetDistance(&owner); if (cur_dist < cur_dist_xyz) @@ -284,7 +270,7 @@ FleeingMovementGenerator::_setMoveData(T &owner) i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + (float)rand_norm()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f); } - int8 sign = rand_norm() > 0.5f ? 1 : -1; + int8 sign = (float)rand_norm() > 0.5f ? 1 : -1; i_cur_angle = sign*angle + angle_to_caster; // current distance @@ -300,14 +286,12 @@ FleeingMovementGenerator::Initialize(T &owner) if (!&owner) return; - _Init(owner); - owner.CastStop(); - owner.AddUnitState(UNIT_STAT_FLEEING | UNIT_STAT_ROAMING); owner.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); - owner.SetTarget(0); - owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); + owner.AddUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE); - if (Unit* fright = ObjectAccessor::GetUnit(owner, i_frightGUID)) + _Init(owner); + + if (Unit *fright = ObjectAccessor::GetUnit(owner, i_frightGUID)) { i_caster_x = fright->GetPositionX(); i_caster_y = fright->GetPositionY(); @@ -334,6 +318,7 @@ FleeingMovementGenerator::_Init(Creature &owner) if (!&owner) return; + //owner.SetTargetGuid(ObjectGuid()); is_water_ok = owner.canSwim(); is_land_ok = owner.canWalk(); } @@ -346,51 +331,44 @@ FleeingMovementGenerator::_Init(Player &) is_land_ok = true; } -template -void -FleeingMovementGenerator::Finalize(T &owner) +template<> +void FleeingMovementGenerator::Finalize(Player &owner) +{ + owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); + owner.ClearUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE); +} + +template<> +void FleeingMovementGenerator::Finalize(Creature &owner) { owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); - owner.ClearUnitState(UNIT_STAT_FLEEING | UNIT_STAT_ROAMING); - if (owner.GetTypeId() == TYPEID_UNIT && owner.getVictim()) + owner.ClearUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE); + if (owner.getVictim()) owner.SetTarget(owner.getVictim()->GetGUID()); } template -void -FleeingMovementGenerator::Reset(T &owner) +void FleeingMovementGenerator::Reset(T &owner) { Initialize(owner); } template bool -FleeingMovementGenerator::Update(T &owner, const uint32 time_diff) +FleeingMovementGenerator::Update(T &owner, const uint32 &time_diff) { if (!&owner || !owner.isAlive()) return false; if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED)) + { + owner.ClearUnitState(UNIT_STAT_FLEEING_MOVE); return true; - - Traveller traveller(owner); + } i_nextCheckTime.Update(time_diff); - - if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || !i_destinationHolder.HasDestination()) - { + if (i_nextCheckTime.Passed() && owner.movespline->Finalized()) _setTargetLocation(owner); - return true; - } - if (i_destinationHolder.UpdateTraveller(traveller, time_diff)) - { - i_destinationHolder.ResetUpdate(50); - if (i_nextCheckTime.Passed() && i_destinationHolder.HasArrived()) - { - _setTargetLocation(owner); - return true; - } - } return true; } @@ -402,17 +380,15 @@ template bool FleeingMovementGenerator::_getPoint(Player &, float &, flo template bool FleeingMovementGenerator::_getPoint(Creature &, float &, float &, float &); template void FleeingMovementGenerator::_setTargetLocation(Player &); template void FleeingMovementGenerator::_setTargetLocation(Creature &); -template void FleeingMovementGenerator::Finalize(Player &); -template void FleeingMovementGenerator::Finalize(Creature &); template void FleeingMovementGenerator::Reset(Player &); template void FleeingMovementGenerator::Reset(Creature &); -template bool FleeingMovementGenerator::Update(Player &, const uint32); -template bool FleeingMovementGenerator::Update(Creature &, const uint32); +template bool FleeingMovementGenerator::Update(Player &, const uint32 &); +template bool FleeingMovementGenerator::Update(Creature &, const uint32 &); void TimedFleeingMovementGenerator::Finalize(Unit &owner) { owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); - owner.ClearUnitState(UNIT_STAT_FLEEING | UNIT_STAT_ROAMING); + owner.ClearUnitState(UNIT_STAT_FLEEING|UNIT_STAT_FLEEING_MOVE); if (Unit* victim = owner.getVictim()) { if (owner.isAlive()) @@ -429,13 +405,20 @@ bool TimedFleeingMovementGenerator::Update(Unit & owner, const uint32 time_diff) return false; if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED)) + { + owner.ClearUnitState(UNIT_STAT_FLEEING_MOVE); return true; + } + + i_totalFleeTime.Update(time_diff); + if (i_totalFleeTime.Passed()) + return false; i_totalFleeTime.Update(time_diff); if (i_totalFleeTime.Passed()) return false; - // This calls grant-parent Update method hiden by FleeingMovementGenerator::Update(Creature &, const uint32) version + // This calls grant-parent Update method hiden by FleeingMovementGenerator::Update(Creature &, const uint32 &) version // This is done instead of casting Unit& to Creature& and call parent method, then we can use Unit directly return MovementGeneratorMedium< Creature, FleeingMovementGenerator >::Update(owner, time_diff); } diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h index 4d4631fe932..750db52bb5a 100755 --- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h @@ -20,8 +20,6 @@ #define TRINITY_FLEEINGMOVEMENTGENERATOR_H #include "MovementGenerator.h" -#include "DestinationHolder.h" -#include "Traveller.h" template class FleeingMovementGenerator @@ -33,8 +31,7 @@ class FleeingMovementGenerator void Initialize(T &); void Finalize(T &); void Reset(T &); - bool Update(T &, const uint32); - bool GetDestination(float &x, float &y, float &z) const; + bool Update(T &, const uint32 &); MovementGeneratorType GetMovementGeneratorType() { return FLEEING_MOTION_TYPE; } @@ -56,8 +53,6 @@ class FleeingMovementGenerator float i_cur_angle; uint64 i_frightGUID; TimeTracker i_nextCheckTime; - - DestinationHolder< Traveller > i_destinationHolder; }; class TimedFleeingMovementGenerator diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp index 16153dd6ccb..84997d6d1ae 100755 --- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp @@ -19,22 +19,16 @@ #include "HomeMovementGenerator.h" #include "Creature.h" #include "CreatureAI.h" -#include "Traveller.h" -#include "DestinationHolderImp.h" #include "WorldPacket.h" +#include "MoveSplineInit.h" +#include "MoveSpline.h" void HomeMovementGenerator::Initialize(Creature & owner) { - owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); owner.AddUnitState(UNIT_STAT_EVADE); _setTargetLocation(owner); } -void HomeMovementGenerator::Finalize(Creature & owner) -{ - owner.ClearUnitState(UNIT_STAT_EVADE); -} - void HomeMovementGenerator::Reset(Creature &) { } @@ -47,42 +41,35 @@ void HomeMovementGenerator::_setTargetLocation(Creature & owner) if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED)) return; - float x, y, z; - owner.GetHomePosition(x, y, z, ori); + Movement::MoveSplineInit init(owner); + float x, y, z, o; + // at apply we can select more nice return points base at current movegen + //if (owner.GetMotionMaster()->empty() || !owner.GetMotionMaster()->top()->GetResetPosition(owner,x,y,z)) + //{ + owner.GetHomePosition(x, y, z, o); + init.SetFacing(o); + //} + init.MoveTo(x,y,z); + init.SetWalk(false); + init.Launch(); - CreatureTraveller traveller(owner); - - uint32 travel_time = i_destinationHolder.SetDestination(traveller, x, y, z); - modifyTravelTime(travel_time); - owner.ClearUnitState(uint32(UNIT_STAT_ALL_STATE & ~UNIT_STAT_EVADE)); + arrived = false; + owner.ClearUnitState(UNIT_STAT_ALL_STATE & ~UNIT_STAT_EVADE); } bool HomeMovementGenerator::Update(Creature &owner, const uint32 time_diff) { - CreatureTraveller traveller(owner); - i_destinationHolder.UpdateTraveller(traveller, time_diff); + arrived = owner.movespline->Finalized(); + return !arrived; +} - if (time_diff > i_travel_timer) +void HomeMovementGenerator::Finalize(Creature& owner) +{ + if (arrived) { - owner.AddUnitMovementFlag(MOVEMENTFLAG_WALKING); - - // restore orientation of not moving creature at returning to home - if (owner.GetDefaultMovementType() == IDLE_MOTION_TYPE) - { - //sLog->outDebug("Entering HomeMovement::GetDestination(z, y, z)"); - owner.SetOrientation(ori); - WorldPacket packet; - owner.BuildHeartBeatMsg(&packet); - owner.SendMessageToSet(&packet, false); - } - owner.ClearUnitState(UNIT_STAT_EVADE); + owner.SetWalk(true); owner.LoadCreaturesAddon(true); owner.AI()->JustReachedHome(); - return false; } - - i_travel_timer -= time_diff; - - return true; } diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h index ba34899dee5..c724edc91ff 100755 --- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h @@ -20,8 +20,6 @@ #define TRINITY_HOMEMOVEMENTGENERATOR_H #include "MovementGenerator.h" -#include "DestinationHolder.h" -#include "Traveller.h" class Creature; @@ -34,24 +32,18 @@ class HomeMovementGenerator { public: - HomeMovementGenerator() {} + HomeMovementGenerator() : arrived(false) {} ~HomeMovementGenerator() {} void Initialize(Creature &); void Finalize(Creature &); void Reset(Creature &); bool Update(Creature &, const uint32); - void modifyTravelTime(uint32 travel_time) { i_travel_timer = travel_time; } MovementGeneratorType GetMovementGeneratorType() { return HOME_MOTION_TYPE; } - bool GetDestination(float& x, float& y, float& z) const { i_destinationHolder.GetDestination(x, y, z); return true; } - private: void _setTargetLocation(Creature &); - DestinationHolder< Traveller > i_destinationHolder; - - float ori; - uint32 i_travel_timer; + bool arrived; }; #endif diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp index af2207ae141..505615c07b8 100755 --- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp @@ -20,61 +20,59 @@ #include "Errors.h" #include "Creature.h" #include "CreatureAI.h" -#include "DestinationHolderImp.h" #include "World.h" +#include "MoveSplineInit.h" +#include "MoveSpline.h" //----- Point Movement Generator template void PointMovementGenerator::Initialize(T &unit) { - unit.StopMoving(); - Traveller traveller(unit); - // OLD: knockback effect has UNIT_STAT_JUMPING set, so if here we disable sentmonstermove there will be creature position sync problem between client and server - // NEW: reactivated this check - UNIT_STAT_JUMPING is only used in MoveJump, which sends its own packet - i_destinationHolder.SetDestination(traveller, i_x, i_y, i_z, /*true*/ !unit.HasUnitState(UNIT_STAT_JUMPING)); + if (!unit.IsStopped()) + unit.StopMoving(); + + unit.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE); + Movement::MoveSplineInit init(unit); + init.MoveTo(i_x, i_y, i_z); + if (speed > 0.0f) + init.SetVelocity(speed); + init.Launch(); } template -bool PointMovementGenerator::Update(T &unit, const uint32 diff) +bool PointMovementGenerator::Update(T &unit, const uint32 &diff) { if (!&unit) return false; - if (unit.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED)) + if(unit.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED)) { - if (unit.HasUnitState(UNIT_STAT_CHARGING)) - return false; - else - return true; + unit.ClearUnitState(UNIT_STAT_ROAMING_MOVE); + return true; } - Traveller traveller(unit); - - i_destinationHolder.UpdateTraveller(traveller, diff); - - if (i_destinationHolder.HasArrived()) - { - unit.ClearUnitState(UNIT_STAT_MOVE); - arrived = true; - return false; - } - else if (!unit.HasUnitState(UNIT_STAT_MOVE) && !unit.HasUnitState(UNIT_STAT_JUMPING)) - { - i_destinationHolder.StartTravel(traveller); - } - - return true; + unit.AddUnitState(UNIT_STAT_ROAMING_MOVE); + return !unit.movespline->Finalized(); } template void PointMovementGenerator:: Finalize(T &unit) { - if (unit.HasUnitState(UNIT_STAT_CHARGING)) - unit.ClearUnitState(UNIT_STAT_CHARGING | UNIT_STAT_JUMPING); - if (arrived) // without this crash! + unit.ClearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE); + + if (unit.movespline->Finalized()) MovementInform(unit); } +template +void PointMovementGenerator::Reset(T &unit) +{ + if (!unit.IsStopped()) + unit.StopMoving(); + + unit.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE); +} + template void PointMovementGenerator::MovementInform(T & /*unit*/) { @@ -82,22 +80,23 @@ void PointMovementGenerator::MovementInform(T & /*unit*/) template <> void PointMovementGenerator::MovementInform(Creature &unit) { - if (id == EVENT_FALL_GROUND) - { - unit.setDeathState(JUST_DIED); - unit.SetFlying(true); - } - unit.AI()->MovementInform(POINT_MOTION_TYPE, id); + //if (id == EVENT_FALL_GROUND) + //{ + // unit.setDeathState(JUST_DIED); + // unit.SetFlying(true); + //} + if (unit.AI()) + unit.AI()->MovementInform(POINT_MOTION_TYPE, id); } template void PointMovementGenerator::Initialize(Player&); -template bool PointMovementGenerator::Update(Player &, const uint32 diff); -template void PointMovementGenerator::MovementInform(Player&); -template void PointMovementGenerator::Finalize(Player&); - template void PointMovementGenerator::Initialize(Creature&); -template bool PointMovementGenerator::Update(Creature&, const uint32 diff); +template void PointMovementGenerator::Finalize(Player&); template void PointMovementGenerator::Finalize(Creature&); +template void PointMovementGenerator::Reset(Player&); +template void PointMovementGenerator::Reset(Creature&); +template bool PointMovementGenerator::Update(Player &, const uint32 &); +template bool PointMovementGenerator::Update(Creature&, const uint32 &); void AssistanceMovementGenerator::Finalize(Unit &unit) { @@ -107,3 +106,24 @@ void AssistanceMovementGenerator::Finalize(Unit &unit) unit.GetMotionMaster()->MoveSeekAssistanceDistract(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY)); } +bool EffectMovementGenerator::Update(Unit &unit, const uint32) +{ + return !unit.movespline->Finalized(); +} + +void EffectMovementGenerator::Finalize(Unit &unit) +{ + if (unit.GetTypeId() != TYPEID_UNIT) + return; + + if (((Creature&)unit).AI() && unit.movespline->Finalized()) + ((Creature&)unit).AI()->MovementInform(EFFECT_MOTION_TYPE, m_Id); + // Need restore previous movement since we have no proper states system + //if (unit.isAlive() && !unit.HasUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_FLEEING)) + //{ + // if (Unit * victim = unit.getVictim()) + // unit.GetMotionMaster()->MoveChase(victim); + // else + // unit.GetMotionMaster()->Initialize(); + //} +} diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h index 2504f1a38e3..e47f3d93450 100755 --- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h @@ -20,8 +20,6 @@ #define TRINITY_POINTMOVEMENTGENERATOR_H #include "MovementGenerator.h" -#include "DestinationHolder.h" -#include "Traveller.h" #include "FollowerReference.h" template @@ -29,13 +27,13 @@ class PointMovementGenerator : public MovementGeneratorMedium< T, PointMovementGenerator > { public: - PointMovementGenerator(uint32 _id, float _x, float _y, float _z) : id(_id), - i_x(_x), i_y(_y), i_z(_z), i_nextMoveTime(0), arrived(false) {} + PointMovementGenerator(uint32 _id, float _x, float _y, float _z, float _speed = 0.0f) : id(_id), + i_x(_x), i_y(_y), i_z(_z), speed(_speed) {} void Initialize(T &); - void Finalize(T &unit); - void Reset(T &unit){unit.StopMoving();} - bool Update(T &, const uint32 diff); + void Finalize(T &); + void Reset(T &); + bool Update(T &, const uint32 &); void MovementInform(T &); @@ -45,9 +43,7 @@ class PointMovementGenerator private: uint32 id; float i_x, i_y, i_z; - TimeTracker i_nextMoveTime; - DestinationHolder< Traveller > i_destinationHolder; - bool arrived; + float speed; }; class AssistanceMovementGenerator @@ -61,5 +57,19 @@ class AssistanceMovementGenerator void Finalize(Unit &); }; +// Does almost nothing - just doesn't allows previous movegen interrupt current effect. +class EffectMovementGenerator : public MovementGenerator +{ + public: + explicit EffectMovementGenerator(uint32 Id) : m_Id(Id) {} + void Initialize(Unit &) {} + void Finalize(Unit &unit); + void Reset(Unit &) {} + bool Update(Unit &u, const uint32); + MovementGeneratorType GetMovementGeneratorType() { return EFFECT_MOTION_TYPE; } + private: + uint32 m_Id; +}; + #endif diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp index 981ec031cf9..0205b734058 100755 --- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp @@ -19,123 +19,103 @@ #include "Creature.h" #include "MapManager.h" #include "RandomMovementGenerator.h" -#include "Traveller.h" #include "ObjectAccessor.h" -#include "DestinationHolderImp.h" #include "Map.h" #include "Util.h" #include "CreatureGroups.h" +#include "MoveSplineInit.h" +#include "MoveSpline.h" #define RUNNING_CHANCE_RANDOMMV 20 //will be "1 / RUNNING_CHANCE_RANDOMMV" -template<> -bool -RandomMovementGenerator::GetDestination(float &x, float &y, float &z) const -{ - if (i_destinationHolder.HasArrived()) - return false; - - i_destinationHolder.GetDestination(x, y, z); - return true; -} - #ifdef MAP_BASED_RAND_GEN #define rand_norm() creature.rand_norm() #endif template<> -void -RandomMovementGenerator::_setRandomLocation(Creature &creature) +void RandomMovementGenerator::_setRandomLocation(Creature &creature) { - float X, Y, Z, nx, ny, nz, ori, dist; - - creature.GetHomePosition(X, Y, Z, ori); - + float respX, respY, respZ, respO, currZ, destX, destY, destZ, travelDistZ; + creature.GetHomePosition(respX, respY, respZ, respO); + currZ = creature.GetPositionZ(); Map const* map = creature.GetBaseMap(); // For 2D/3D system selection - //bool is_land_ok = creature.canWalk(); - //bool is_water_ok = creature.canSwim(); - bool is_air_ok = creature.canFly(); + //bool is_land_ok = creature.CanWalk(); // not used? + //bool is_water_ok = creature.CanSwim(); // not used? + bool is_air_ok = creature.canFly(); - for (uint32 i = 0; ; ++i) - { - const float angle = (float)rand_norm()*static_cast(M_PI*2); - const float range = (float)rand_norm()*wander_distance; - const float distanceX = range * cos(angle); - const float distanceY = range * sin(angle); + const float angle = float(rand_norm()) * static_cast(M_PI*2.0f); + const float range = float(rand_norm()) * wander_distance; + const float distanceX = range * cos(angle); + const float distanceY = range * sin(angle); - nx = X + distanceX; - ny = Y + distanceY; + destX = respX + distanceX; + destY = respY + distanceY; - // prevent invalid coordinates generation - Trinity::NormalizeMapCoord(nx); - Trinity::NormalizeMapCoord(ny); + // prevent invalid coordinates generation + Trinity::NormalizeMapCoord(destX); + Trinity::NormalizeMapCoord(destY); - dist = (nx - X)*(nx - X) + (ny - Y)*(ny - Y); + travelDistZ = distanceX*distanceX + distanceY*distanceY; - if (i == 5) - { - nz = Z; - break; - } + if (is_air_ok) // 3D system above ground and above water (flying mode) + { + // Limit height change + const float distanceZ = float(rand_norm()) * sqrtf(travelDistZ)/2.0f; + destZ = respZ + distanceZ; + float levelZ = map->GetWaterOrGroundLevel(destX, destY, destZ-2.0f); + + // Problem here, we must fly above the ground and water, not under. Let's try on next tick + if (levelZ >= destZ) + return; + } + //else if (is_water_ok) // 3D system under water and above ground (swimming mode) + else // 2D only + { + // 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE) + travelDistZ = travelDistZ >= 100.0f ? 10.0f : sqrtf(travelDistZ); - if (is_air_ok) // 3D system above ground and above water (flying mode) - { - const float distanceZ = (float)(rand_norm()) * sqrtf(dist)/2; // Limit height change - nz = Z + distanceZ; - float tz = map->GetHeight(nx, ny, nz-2.0f, false); // Map check only, vmap needed here but need to alter vmaps checks for height. - float wz = map->GetWaterLevel(nx, ny); - if (tz >= nz || wz >= nz) - continue; // Problem here, we must fly above the ground and water, not under. Let's try on next tick - } - //else if (is_water_ok) // 3D system under water and above ground (swimming mode) - else // 2D only + // The fastest way to get an accurate result 90% of the time. + // Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long. + destZ = map->GetHeight(destX, destY, respZ+travelDistZ-2.0f, false); + + if (fabs(destZ - respZ) > travelDistZ) // Map check { - dist = dist >= 100.0f ? 10.0f : sqrtf(dist); // 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE) + // Vmap Horizontal or above + destZ = map->GetHeight(destX, destY, respZ - 2.0f, true); - // The fastest way to get an accurate result 90% of the time. - // Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long. - nz = map->GetHeight(nx, ny, Z+dist-2.0f, false); // Map check - if (fabs(nz-Z)>dist) + if (fabs(destZ - respZ) > travelDistZ) { - nz = map->GetHeight(nx, ny, Z-2.0f, true); // Vmap Horizontal or above - if (fabs(nz-Z)>dist) - { - nz = map->GetHeight(nx, ny, Z+dist-2.0f, true); // Vmap Higher - if (fabs(nz-Z)>dist) - continue; // let's forget this bad coords where a z cannot be find and retry at next tick - } + // Vmap Higher + destZ = map->GetHeight(destX, destY, respZ+travelDistZ-2.0f, true); + + // let's forget this bad coords where a z cannot be find and retry at next tick + if (fabs(destZ - respZ) > travelDistZ) + return; } } - break; } - Traveller traveller(creature); - creature.SetOrientation(creature.GetAngle(nx, ny)); - i_destinationHolder.SetDestination(traveller, nx, ny, nz); - creature.AddUnitState(UNIT_STAT_ROAMING); if (is_air_ok) - { - i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); - } - //else if (is_water_ok) // Swimming mode to be done with more than this check + i_nextMoveTime.Reset(0); else - { - i_nextMoveTime.Reset(urand(500+i_destinationHolder.GetTotalTravelTime(), 5000+i_destinationHolder.GetTotalTravelTime())); - creature.AddUnitMovementFlag(MOVEMENTFLAG_WALKING); - } + i_nextMoveTime.Reset(urand(500, 10000)); + + creature.AddUnitState(UNIT_STAT_ROAMING_MOVE); + + Movement::MoveSplineInit init(creature); + init.MoveTo(destX, destY, destZ); + init.SetWalk(true); + init.Launch(); //Call for creature group update if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature) - { - creature.GetFormation()->LeaderMoveTo(nx, ny, nz); - } + creature.GetFormation()->LeaderMoveTo(destX, destY, destZ); } template<> -void -RandomMovementGenerator::Initialize(Creature &creature) +void RandomMovementGenerator::Initialize(Creature &creature) { if (!creature.isAlive()) return; @@ -143,8 +123,7 @@ RandomMovementGenerator::Initialize(Creature &creature) if (!wander_distance) wander_distance = creature.GetRespawnRadius(); - if (irand(0, RUNNING_CHANCE_RANDOMMV) > 0) - creature.AddUnitMovementFlag(MOVEMENTFLAG_WALKING); + creature.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE); _setRandomLocation(creature); } @@ -156,8 +135,11 @@ RandomMovementGenerator::Reset(Creature &creature) } template<> -void -RandomMovementGenerator::Finalize(Creature & /*creature*/){} +void RandomMovementGenerator::Finalize(Creature &creature) +{ + creature.ClearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE); + creature.SetWalk(false); +} template<> bool @@ -165,35 +147,29 @@ RandomMovementGenerator::Update(Creature &creature, const uint32 diff) { if (creature.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED)) { - i_nextMoveTime.Update(i_nextMoveTime.GetExpiry()); // Expire the timer - creature.ClearUnitState(UNIT_STAT_ROAMING); + i_nextMoveTime.Reset(0); // Expire the timer + creature.ClearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } - i_nextMoveTime.Update(diff); - - if (i_destinationHolder.HasArrived() && !creature.IsStopped() && !creature.canFly()) - creature.ClearUnitState(UNIT_STAT_ROAMING | UNIT_STAT_MOVE); - - if (!i_destinationHolder.HasArrived() && creature.IsStopped()) - creature.AddUnitState(UNIT_STAT_ROAMING); - - CreatureTraveller traveller(creature); - - if (i_destinationHolder.UpdateTraveller(traveller, diff, true)) + if (creature.movespline->Finalized()) { + i_nextMoveTime.Update(diff); if (i_nextMoveTime.Passed()) - { - if (irand(0, RUNNING_CHANCE_RANDOMMV) > 0) - creature.AddUnitMovementFlag(MOVEMENTFLAG_WALKING); _setRandomLocation(creature); - } - else if (creature.isPet() && creature.GetOwner() && !creature.IsWithinDist(creature.GetOwner(), PET_FOLLOW_DIST+2.5f)) - { - creature.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); - _setRandomLocation(creature); - } } return true; } +template<> +bool RandomMovementGenerator::GetResetPosition(Creature &creature, float& x, float& y, float& z) +{ + float radius; + creature.GetRespawnPosition(x, y, z, NULL, &radius); + + // use current if in range + if (creature.IsWithinDist2d(x,y,radius)) + creature.GetPosition(x,y,z); + + return true; +} diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h index 816e325f3b1..67161b6fc29 100755 --- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h @@ -20,15 +20,12 @@ #define TRINITY_RANDOMMOTIONGENERATOR_H #include "MovementGenerator.h" -#include "DestinationHolder.h" -#include "Traveller.h" template class RandomMovementGenerator : public MovementGeneratorMedium< T, RandomMovementGenerator > { public: - // Wander dist is related on db spawn dist. So what if we wanna set eandom movement on summoned creature?! RandomMovementGenerator(float spawn_dist = 0.0f) : i_nextMoveTime(0), wander_distance(spawn_dist) {} void _setRandomLocation(T &); @@ -36,18 +33,13 @@ class RandomMovementGenerator void Finalize(T &); void Reset(T &); bool Update(T &, const uint32); - bool GetDestination(float &x, float &y, float &z) const; - void UpdateMapPosition(uint32 mapid, float &x, float &y, float &z) - { - i_destinationHolder.GetLocationNow(mapid, x, y, z); - } + bool GetResetPosition(T&, float& x, float& y, float& z); MovementGeneratorType GetMovementGeneratorType() { return RANDOM_MOTION_TYPE; } private: TimeTrackerSmall i_nextMoveTime; - DestinationHolder< Traveller > i_destinationHolder; - float wander_distance; uint32 i_nextMove; + float wander_distance; }; #endif diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp index e0ca5231000..bded2fd512c 100755 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp @@ -21,106 +21,42 @@ #include "Errors.h" #include "Creature.h" #include "CreatureAI.h" -#include "DestinationHolderImp.h" #include "World.h" - -#define SMALL_ALPHA 0.05f +#include "MoveSplineInit.h" +#include "MoveSpline.h" #include -/* -struct StackCleaner -{ - Creature &i_creature; - StackCleaner(Creature &creature) : i_creature(creature) {} - void Done(void) { i_creature.StopMoving(); } - ~StackCleaner() - { - i_creature->Clear(); - } -}; -*/ -template -TargetedMovementGenerator::TargetedMovementGenerator(Unit &target, float offset, float angle) -: TargetedMovementGeneratorBase(target) -, i_offset(offset), i_angle(angle), i_recalculateTravel(false) -{ - target.GetPosition(i_targetX, i_targetY, i_targetZ); -} - -template -bool -TargetedMovementGenerator::_setTargetLocation(T &owner) +template +void TargetedMovementGeneratorMedium::_setTargetLocation(T &owner) { if (!i_target.isValid() || !i_target->IsInWorld()) - return false; + return; - if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED)) - return false; + if (owner.HasUnitState(UNIT_STAT_NOT_MOVE)) + return; float x, y, z; - Traveller traveller(owner); - if (i_destinationHolder.HasDestination()) + + if (i_offset && i_target->IsWithinDistInMap(&owner,2*i_offset)) { - if (i_destinationHolder.HasArrived()) - { - // prevent redundant micro-movement - if (!i_offset) - { - if (i_target->IsWithinMeleeRange(&owner)) - return false; - } - else if (!i_angle && !owner.HasUnitState(UNIT_STAT_FOLLOW)) - { - if (i_target->IsWithinDistInMap(&owner, i_offset)) - return false; - } - else - { - if (i_target->IsWithinDistInMap(&owner, i_offset + 1.0f)) - return false; - } - } - else - { - bool stop = false; - if (!i_offset) - { - if (i_target->IsWithinMeleeRange(&owner, 0)) - stop = true; - } - else if (!i_angle && !owner.HasUnitState(UNIT_STAT_FOLLOW)) - { - if (i_target->IsWithinDist(&owner, i_offset * 0.8f)) - stop = true; - } - - if (stop) - { - owner.GetPosition(x, y, z); - i_destinationHolder.SetDestination(traveller, x, y, z); - i_destinationHolder.StartTravel(traveller, false); - owner.StopMoving(); - return false; - } - } + if (!owner.movespline->Finalized()) + return; - if (i_target->GetExactDistSq(i_targetX, i_targetY, i_targetZ) < 0.01f) - return false; + owner.GetPosition(x, y, z); } - - if (!i_offset) + else if (!i_offset) { + if (i_target->IsWithinMeleeRange(&owner)) + return; + // to nearest random contact position i_target->GetRandomContactPoint(&owner, x, y, z, 0, MELEE_RANGE - 0.5f); } - else if (!i_angle && !owner.HasUnitState(UNIT_STAT_FOLLOW)) - { - // caster chase - i_target->GetContactPoint(&owner, x, y, z, i_offset * urand(80, 95) * 0.01f); - } else { + if (i_target->IsWithinDistInMap(&owner, i_offset + 1.0f)) + return; // to at i_offset distance from target and i_angle from target facing i_target->GetClosePoint(x, y, z, owner.GetObjectSize(), i_offset, i_angle); } @@ -137,55 +73,65 @@ TargetedMovementGenerator::_setTargetLocation(T &owner) ralf //We don't update Mob Movement, if the difference between New destination and last destination is < BothObjectSize - float bothObjectSize = i_target->GetObjectSize() + owner.GetObjectSize() + CONTACT_DISTANCE; - if (i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x, y, z) < bothObjectSize) + float bothObjectSize = i_target->GetObjectBoundingRadius() + owner.GetObjectBoundingRadius() + CONTACT_DISTANCE; + if( i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x,y,z) < bothObjectSize ) return; */ - i_destinationHolder.SetDestination(traveller, x, y, z); - owner.AddUnitState(UNIT_STAT_CHASE); - i_destinationHolder.StartTravel(traveller); - return true; + + + D::_addUnitStateMove(owner); + i_targetReached = false; + i_recalculateTravel = false; + + Movement::MoveSplineInit init(owner); + init.MoveTo(x,y,z); + init.SetWalk(((D*)this)->EnableWalking()); + init.Launch(); } -template -void -TargetedMovementGenerator::Initialize(T &owner) +template<> +void TargetedMovementGeneratorMedium >::UpdateFinalDistance(float /*fDistance*/) { - if (owner.isInCombat()) - owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); + // nothing to do for Player +} - _setTargetLocation(owner); +template<> +void TargetedMovementGeneratorMedium >::UpdateFinalDistance(float /*fDistance*/) +{ + // nothing to do for Player } -template -void -TargetedMovementGenerator::Finalize(T &owner) +template<> +void TargetedMovementGeneratorMedium >::UpdateFinalDistance(float fDistance) { - owner.ClearUnitState(UNIT_STAT_CHASE); + i_offset = fDistance; + i_recalculateTravel = true; } -template -void -TargetedMovementGenerator::Reset(T &owner) +template<> +void TargetedMovementGeneratorMedium >::UpdateFinalDistance(float fDistance) { - Initialize(owner); + i_offset = fDistance; + i_recalculateTravel = true; } -template -bool -TargetedMovementGenerator::Update(T &owner, const uint32 time_diff) +template +bool TargetedMovementGeneratorMedium::Update(T &owner, const uint32 & time_diff) { if (!i_target.isValid() || !i_target->IsInWorld()) return false; - if (!&owner || !owner.isAlive()) + if (!owner.isAlive()) return true; - if (owner.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_DISTRACTED)) + if (owner.HasUnitState(UNIT_STAT_NOT_MOVE)) + { + D::_clearUnitStateMove(owner); return true; + } // prevent movement while casting spells with cast time or channel time - if (owner.HasUnitState(UNIT_STAT_CASTING)) + if (owner.IsNonMeleeSpellCasted(false, false, true)) { if (!owner.IsStopped()) owner.StopMoving(); @@ -193,85 +139,170 @@ TargetedMovementGenerator::Update(T &owner, const uint32 time_diff) } // prevent crash after creature killed pet - if (!owner.HasUnitState(UNIT_STAT_FOLLOW) && owner.getVictim() != i_target.getTarget()) + if (static_cast(this)->_lostTarget(owner)) + { + D::_clearUnitStateMove(owner); return true; + } - Traveller traveller(owner); - - if (!i_destinationHolder.HasDestination()) - _setTargetLocation(owner); - else if (owner.IsStopped() && !i_destinationHolder.HasArrived()) + i_recheckDistance.Update(time_diff); + if (i_recheckDistance.Passed()) { - owner.AddUnitState(UNIT_STAT_CHASE); - i_destinationHolder.StartTravel(traveller); - return true; + i_recheckDistance.Reset(50); + //More distance let have better performance, less distance let have more sensitive reaction at target move. + float allowed_dist = i_target->GetObjectSize() + owner.GetObjectSize() + MELEE_RANGE - 0.5f; + float dist = (owner.movespline->FinalDestination() - G3D::Vector3(i_target->GetPositionX(),i_target->GetPositionY(),i_target->GetPositionZ())).squaredLength(); + if (dist >= allowed_dist * allowed_dist) + _setTargetLocation(owner); } - if (i_destinationHolder.UpdateTraveller(traveller, time_diff)) + if (owner.movespline->Finalized()) { - // put targeted movement generators on a higher priority - //if (owner.GetObjectSize()) - //i_destinationHolder.ResetUpdate(50); + static_cast(this)->MovementInform(owner); + if (i_angle == 0.f && !owner.HasInArc(0.01f, i_target.getTarget())) + owner.SetInFront(i_target.getTarget()); - // target moved - if (i_targetX != i_target->GetPositionX() || i_targetY != i_target->GetPositionY() - || i_targetZ != i_target->GetPositionZ()) + if (!i_targetReached) { - if (_setTargetLocation(owner) || !owner.HasUnitState(UNIT_STAT_FOLLOW)) - owner.SetInFront(i_target.getTarget()); - i_target->GetPosition(i_targetX, i_targetY, i_targetZ); + i_targetReached = true; + static_cast(this)->_reachTarget(owner); } + } + else + { + if (i_recalculateTravel) + _setTargetLocation(owner); + } + return true; +} - if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || i_recalculateTravel) - { - i_recalculateTravel = false; - //Angle update will take place into owner.StopMoving() - owner.SetInFront(i_target.getTarget()); +//-----------------------------------------------// +template +void ChaseMovementGenerator::_reachTarget(T &owner) +{ + if (owner.IsWithinMeleeRange(this->i_target.getTarget())) + owner.Attack(this->i_target.getTarget(),true); +} - owner.StopMoving(); - if (owner.IsWithinMeleeRange(i_target.getTarget()) && !owner.HasUnitState(UNIT_STAT_FOLLOW)) - owner.Attack(i_target.getTarget(), true); - } - } +template<> +void ChaseMovementGenerator::Initialize(Player &owner) +{ + owner.AddUnitState(UNIT_STAT_CHASE|UNIT_STAT_CHASE_MOVE); + _setTargetLocation(owner); +} - // Implemented for PetAI to handle resetting flags when pet owner reached - if (i_destinationHolder.HasArrived()) - MovementInform(owner); +template<> +void ChaseMovementGenerator::Initialize(Creature &owner) +{ + owner.SetWalk(false); + owner.AddUnitState(UNIT_STAT_CHASE|UNIT_STAT_CHASE_MOVE); + _setTargetLocation(owner); +} - return true; +template +void ChaseMovementGenerator::Finalize(T &owner) +{ + owner.ClearUnitState(UNIT_STAT_CHASE|UNIT_STAT_CHASE_MOVE); } template -Unit* -TargetedMovementGenerator::GetTarget() const +void ChaseMovementGenerator::Reset(T &owner) +{ + Initialize(owner); +} + +//-----------------------------------------------// +template<> +bool FollowMovementGenerator::EnableWalking() const +{ + return i_target.isValid() && i_target->IsWalking(); +} + +template<> +bool FollowMovementGenerator::EnableWalking() const { - return i_target.getTarget(); + return false; +} + +template<> +void FollowMovementGenerator::_updateSpeed(Player &/*u*/) +{ + // nothing to do for Player +} + +template<> +void FollowMovementGenerator::_updateSpeed(Creature &u) +{ + // pet only sync speed with owner + if (!((Creature&)u).isPet() || !i_target.isValid() || i_target->GetGUID() != u.GetOwnerGUID()) + return; + + u.UpdateSpeed(MOVE_RUN,true); + u.UpdateSpeed(MOVE_WALK,true); + u.UpdateSpeed(MOVE_SWIM,true); +} + +template<> +void FollowMovementGenerator::Initialize(Player &owner) +{ + owner.AddUnitState(UNIT_STAT_FOLLOW|UNIT_STAT_FOLLOW_MOVE); + _updateSpeed(owner); + _setTargetLocation(owner); +} + +template<> +void FollowMovementGenerator::Initialize(Creature &owner) +{ + owner.AddUnitState(UNIT_STAT_FOLLOW|UNIT_STAT_FOLLOW_MOVE); + _updateSpeed(owner); + _setTargetLocation(owner); } template -void TargetedMovementGenerator::MovementInform(T & /*unit*/) +void FollowMovementGenerator::Finalize(T &owner) { + owner.ClearUnitState(UNIT_STAT_FOLLOW|UNIT_STAT_FOLLOW_MOVE); + _updateSpeed(owner); } -template <> void TargetedMovementGenerator::MovementInform(Creature &unit) +template +void FollowMovementGenerator::Reset(T &owner) +{ + Initialize(owner); +} + +template +void FollowMovementGenerator::MovementInform(T & /*unit*/) { - // Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle - unit.AI()->MovementInform(TARGETED_MOTION_TYPE, i_target.getTarget()->GetGUIDLow()); } -template void TargetedMovementGenerator::MovementInform(Player&); // Not implemented for players -template TargetedMovementGenerator::TargetedMovementGenerator(Unit &target, float offset, float angle); -template TargetedMovementGenerator::TargetedMovementGenerator(Unit &target, float offset, float angle); -template bool TargetedMovementGenerator::_setTargetLocation(Player &); -template bool TargetedMovementGenerator::_setTargetLocation(Creature &); -template void TargetedMovementGenerator::Initialize(Player &); -template void TargetedMovementGenerator::Initialize(Creature &); -template void TargetedMovementGenerator::Finalize(Player &); -template void TargetedMovementGenerator::Finalize(Creature &); -template void TargetedMovementGenerator::Reset(Player &); -template void TargetedMovementGenerator::Reset(Creature &); -template bool TargetedMovementGenerator::Update(Player &, const uint32); -template bool TargetedMovementGenerator::Update(Creature &, const uint32); -template Unit* TargetedMovementGenerator::GetTarget() const; -template Unit* TargetedMovementGenerator::GetTarget() const; +template<> +void FollowMovementGenerator::MovementInform(Creature &unit) +{ + // Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle + if (unit.AI()) + unit.AI()->MovementInform(FOLLOW_MOTION_TYPE, i_target.getTarget()->GetGUIDLow()); +} +//-----------------------------------------------// +template void TargetedMovementGeneratorMedium >::_setTargetLocation(Player &); +template void TargetedMovementGeneratorMedium >::_setTargetLocation(Player &); +template void TargetedMovementGeneratorMedium >::_setTargetLocation(Creature &); +template void TargetedMovementGeneratorMedium >::_setTargetLocation(Creature &); +template bool TargetedMovementGeneratorMedium >::Update(Player &, const uint32 &); +template bool TargetedMovementGeneratorMedium >::Update(Player &, const uint32 &); +template bool TargetedMovementGeneratorMedium >::Update(Creature &, const uint32 &); +template bool TargetedMovementGeneratorMedium >::Update(Creature &, const uint32 &); + +template void ChaseMovementGenerator::_reachTarget(Player &); +template void ChaseMovementGenerator::_reachTarget(Creature &); +template void ChaseMovementGenerator::Finalize(Player &); +template void ChaseMovementGenerator::Finalize(Creature &); +template void ChaseMovementGenerator::Reset(Player &); +template void ChaseMovementGenerator::Reset(Creature &); + +template void FollowMovementGenerator::Finalize(Player &); +template void FollowMovementGenerator::Finalize(Creature &); +template void FollowMovementGenerator::Reset(Player &); +template void FollowMovementGenerator::Reset(Creature &); +template void FollowMovementGenerator::MovementInform(Player &unit); diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h index edb4fca8fce..785d12ba6d2 100755 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h @@ -20,9 +20,8 @@ #define TRINITY_TARGETEDMOVEMENTGENERATOR_H #include "MovementGenerator.h" -#include "DestinationHolder.h" -#include "Traveller.h" #include "FollowerReference.h" +#include "Timer.h" class TargetedMovementGeneratorBase { @@ -33,41 +32,84 @@ class TargetedMovementGeneratorBase FollowerReference i_target; }; +template +class TargetedMovementGeneratorMedium +: public MovementGeneratorMedium< T, D >, public TargetedMovementGeneratorBase +{ + protected: + TargetedMovementGeneratorMedium(Unit &target, float offset, float angle) : + TargetedMovementGeneratorBase(target), i_offset(offset), i_angle(angle), + i_recalculateTravel(false), i_targetReached(false), i_recheckDistance(0) + { + } + ~TargetedMovementGeneratorMedium() {} + + public: + bool Update(T &, const uint32 &); + Unit* GetTarget() const { return i_target.getTarget(); } + + void unitSpeedChanged() { i_recalculateTravel=true; } + void UpdateFinalDistance(float fDistance); + + protected: + void _setTargetLocation(T &); + + TimeTrackerSmall i_recheckDistance; + float i_offset; + float i_angle; + bool i_recalculateTravel : 1; + bool i_targetReached : 1; +}; + template -class TargetedMovementGenerator -: public MovementGeneratorMedium< T, TargetedMovementGenerator >, public TargetedMovementGeneratorBase +class ChaseMovementGenerator : public TargetedMovementGeneratorMedium > { public: - TargetedMovementGenerator(Unit &target, float offset = 0, float angle = 0); - ~TargetedMovementGenerator() {} + ChaseMovementGenerator(Unit &target) + : TargetedMovementGeneratorMedium >(target) {} + ChaseMovementGenerator(Unit &target, float offset, float angle) + : TargetedMovementGeneratorMedium >(target, offset, angle) {} + ~ChaseMovementGenerator() {} + + MovementGeneratorType GetMovementGeneratorType() { return CHASE_MOTION_TYPE; } void Initialize(T &); void Finalize(T &); void Reset(T &); - bool Update(T &, const uint32); - MovementGeneratorType GetMovementGeneratorType() { return TARGETED_MOTION_TYPE; } - - void MovementInform(T &); + void MovementInform(T &){} - Unit* GetTarget() const; + static void _clearUnitStateMove(T &u) { u.ClearUnitState(UNIT_STAT_CHASE_MOVE); } + static void _addUnitStateMove(T &u) { u.AddUnitState(UNIT_STAT_CHASE_MOVE); } + bool EnableWalking() const { return false;} + bool _lostTarget(T &u) const { return u.getVictim() != this->GetTarget(); } + void _reachTarget(T &); +}; - bool GetDestination(float &x, float &y, float &z) const - { - if (i_destinationHolder.HasArrived() || !i_destinationHolder.HasDestination()) return false; - i_destinationHolder.GetDestination(x, y, z); - return true; - } +template +class FollowMovementGenerator : public TargetedMovementGeneratorMedium > +{ + public: + FollowMovementGenerator(Unit &target) + : TargetedMovementGeneratorMedium >(target){} + FollowMovementGenerator(Unit &target, float offset, float angle) + : TargetedMovementGeneratorMedium >(target, offset, angle) {} + ~FollowMovementGenerator() {} - void unitSpeedChanged() { i_recalculateTravel=true; } - private: + MovementGeneratorType GetMovementGeneratorType() { return FOLLOW_MOTION_TYPE; } - bool _setTargetLocation(T &); + void Initialize(T &); + void Finalize(T &); + void Reset(T &); + void MovementInform(T &); - float i_offset; - float i_angle; - DestinationHolder< Traveller > i_destinationHolder; - bool i_recalculateTravel; - float i_targetX, i_targetY, i_targetZ; + static void _clearUnitStateMove(T &u) { u.ClearUnitState(UNIT_STAT_FOLLOW_MOVE); } + static void _addUnitStateMove(T &u) { u.AddUnitState(UNIT_STAT_FOLLOW_MOVE); } + bool EnableWalking() const; + bool _lostTarget(T &) const { return false; } + void _reachTarget(T &) {} + private: + void _updateSpeed(T &u); }; + #endif diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index f88ed249aca..ea858eaba84 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -17,222 +17,165 @@ */ //Basic headers #include "WaypointMovementGenerator.h" -#include "DestinationHolderImp.h" //Extended headers #include "ObjectMgr.h" #include "World.h" -#include "MapManager.h" // for flightmaster grid preloading +//Flightmaster grid preloading +#include "MapManager.h" //Creature-specific headers #include "Creature.h" #include "CreatureAI.h" #include "CreatureGroups.h" //Player-specific #include "Player.h" +#include "MoveSplineInit.h" +#include "MoveSpline.h" -template -void -WaypointMovementGenerator::Initialize(T & /*u*/){} - -template<> -void -WaypointMovementGenerator::Finalize(Creature & /*u*/){} +void WaypointMovementGenerator::LoadPath(Creature &creature) +{ + if (!path_id) + path_id = creature.GetWaypointPath(); -template<> -void -WaypointMovementGenerator::Finalize(Player & /*u*/){} + i_path = sWaypointMgr->GetPath(path_id); -template -void -WaypointMovementGenerator::MovementInform(T & /*unit*/){} + if (!i_path) + { + // No movement found for entry + sLog->outErrorDb("WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %u) doesn't have waypoint path id: %u", creature.GetName(), creature.GetEntry(), creature.GetGUIDLow(), path_id); + return; + } -template<> -void WaypointMovementGenerator::MovementInform(Creature &unit) -{ - unit.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode); + StartMoveNow(creature); } -template<> -bool WaypointMovementGenerator::GetDestination(float &x, float &y, float &z) const +void WaypointMovementGenerator::Initialize(Creature &creature) { - if (i_destinationHolder.HasArrived()) - return false; - - i_destinationHolder.GetDestination(x, y, z); - return true; + LoadPath(creature); + creature.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE); } -template<> -bool WaypointMovementGenerator::GetDestination(float & /*x*/, float & /*y*/, float & /*z*/) const +void WaypointMovementGenerator::Finalize(Creature &creature) { - return false; + creature.ClearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE); + creature.SetWalk(false); } -template<> -void WaypointMovementGenerator::Reset(Creature & /*unit*/) +void WaypointMovementGenerator::Reset(Creature &creature) { - StopedByPlayer = true; - i_nextMoveTime.Reset(0); + creature.AddUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE); + StartMoveNow(creature); } -template<> -void WaypointMovementGenerator::Reset(Player & /*unit*/){} - -template<> -void WaypointMovementGenerator::InitTraveller(Creature &unit, const WaypointData &node) +void WaypointMovementGenerator::OnArrived(Creature& creature) { - node.run ? unit.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING): - unit.AddUnitMovementFlag(MOVEMENTFLAG_WALKING); + if (!i_path || i_path->empty()) + return; + if (m_isArrivalDone) + return; - unit.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); - unit.SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + creature.ClearUnitState(UNIT_STAT_ROAMING_MOVE); + m_isArrivalDone = true; - // TODO: make this part of waypoint node, so that creature can walk when desired? - if (unit.canFly()) - unit.SetByteFlag(UNIT_FIELD_BYTES_1, 3, 0x02); + if (i_path->at(i_currentNode)->event_id && urand(0, 99) < i_path->at(i_currentNode)->event_chance) + { + sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Creature movement start script %u at point %u for %u.", i_path->at(i_currentNode)->event_id, i_currentNode, creature.GetGUID()); + creature.GetMap()->ScriptsStart(sWaypointScripts, i_path->at(i_currentNode)->event_id, &creature, NULL/*, false*/); + } - unit.AddUnitState(UNIT_STAT_ROAMING); + // Inform script + MovementInform(creature); + Stop(i_path->at(i_currentNode)->delay); } -template<> -void -WaypointMovementGenerator::Initialize(Creature &u) +bool WaypointMovementGenerator::StartMove(Creature &creature) { - u.StopMoving(); - //i_currentNode = -1; // uint32, become 0 in the first update - //i_nextMoveTime.Reset(0); - StopedByPlayer = false; - if (!path_id) - path_id = u.GetWaypointPath(); - waypoints = sWaypointMgr->GetPath(path_id); - i_currentNode = 0; - if (waypoints && waypoints->size()) + if (!i_path || i_path->empty()) + return false; + if (Stopped()) + return true; + + const WaypointData *node = i_path->at(i_currentNode); + + if (m_isArrivalDone) { - node = waypoints->front(); - Traveller traveller(u); - InitTraveller(u, *node); - i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z); - i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); - - //Call for creature group update - if (u.GetFormation() && u.GetFormation()->getLeader() == &u) - u.GetFormation()->LeaderMoveTo(node->x, node->y, node->z); + if ((i_currentNode == i_path->size() - 1) && !repeating) // If that's our last waypoint + { + creature.SetHomePosition(node->x, node->y, node->z, creature.GetOrientation()); + creature.GetMotionMaster()->Initialize(); + return false; + } + + i_currentNode = (i_currentNode+1) % i_path->size(); } - else - node = NULL; -} -template<> -void WaypointMovementGenerator::InitTraveller(Player & /*unit*/, const WaypointData & /*node*/){} + m_isArrivalDone = false; -template -bool -WaypointMovementGenerator::Update(T & /*unit*/, const uint32 /*diff*/) -{ - return false; -} + creature.AddUnitState(UNIT_STAT_ROAMING_MOVE); + + Movement::MoveSplineInit init(creature); + init.MoveTo(node->x, node->y, node->z); -template<> -bool -WaypointMovementGenerator::Update(Creature &unit, const uint32 diff) -{ - if (!&unit) - return true; + if (node->orientation != 100 && node->delay != 0) + init.SetFacing(node->orientation); - if (!path_id) - return false; + init.SetWalk(!node->run); + init.Launch(); + + //Call for creature group update + if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature) + creature.GetFormation()->LeaderMoveTo(node->x, node->y, node->z); + + return true; +} +bool WaypointMovementGenerator::Update(Creature &creature, const uint32 &diff) +{ // Waypoint movement can be switched on/off // This is quite handy for escort quests and other stuff - if (unit.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED)) + if (creature.HasUnitState(UNIT_STAT_NOT_MOVE)) + { + creature.ClearUnitState(UNIT_STAT_ROAMING_MOVE); return true; - - // Clear the generator if the path doesn't exist - if (!waypoints || !waypoints->size()) + } + // prevent a crash at empty waypoint path. + if (!i_path || i_path->empty()) return false; - Traveller traveller(unit); - - i_nextMoveTime.Update(diff); - i_destinationHolder.UpdateTraveller(traveller, diff, true); - - if (i_nextMoveTime.GetExpiry() < TIMEDIFF_NEXT_WP) + if (Stopped()) { - if (unit.IsStopped()) - { - if (StopedByPlayer) - { - ASSERT(node); - InitTraveller(unit, *node); - i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z); - i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); - StopedByPlayer = false; - return true; - } - - if (i_currentNode == waypoints->size() - 1) // If that's our last waypoint - { - if (repeating) // If the movement is repeating - i_currentNode = 0; // Start moving all over again - else - { - unit.SetHomePosition(node->x, node->y, node->z, unit.GetOrientation()); - unit.GetMotionMaster()->Initialize(); - return false; // Clear the waypoint movement - } - } - else - ++i_currentNode; - - node = waypoints->at(i_currentNode); - InitTraveller(unit, *node); - i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z); - i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); - - //Call for creature group update - if (unit.GetFormation() && unit.GetFormation()->getLeader() == &unit) - unit.GetFormation()->LeaderMoveTo(node->x, node->y, node->z); - } - else - { - //Determine waittime - if (node->delay) - i_nextMoveTime.Reset(node->delay); - - //note: disable "start" for mtmap - if (node->event_id && urand(0, 99) < node->event_chance) - unit.GetMap()->ScriptsStart(sWaypointScripts, node->event_id, &unit, NULL/*, false*/); - - i_destinationHolder.ResetTravelTime(); - MovementInform(unit); - unit.UpdateWaypointID(i_currentNode); - unit.ClearUnitState(UNIT_STAT_ROAMING); - if (node->orientation) - { - unit.Relocate(node->x, node->y, node->z, node->orientation); - unit.SetFacing(node->orientation, NULL); - } - else - unit.Relocate(node->x, node->y, node->z); - } + if (CanMove(diff)) + return StartMove(creature); } - else + else { - if (unit.IsStopped() && !i_destinationHolder.HasArrived()) + if (creature.IsStopped()) + Stop(STOP_TIME_FOR_PLAYER); + else if (creature.movespline->Finalized()) { - if (!StopedByPlayer) - { - i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER); - i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER); - StopedByPlayer = true; - } - } + OnArrived(creature); + return StartMove(creature); + } } + return true; + } + +void WaypointMovementGenerator::MovementInform(Creature &creature) +{ + if (creature.AI()) + creature.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode); +} + +bool WaypointMovementGenerator::GetResetPosition(Creature&, float& x, float& y, float& z) +{ + // prevent a crash at empty waypoint path. + if (!i_path || i_path->empty()) + return false; + + const WaypointData* node = i_path->at(i_currentNode); + x = node->x; y = node->y; z = node->z; return true; } -template void WaypointMovementGenerator::Initialize(Player &); -template bool WaypointMovementGenerator::Update(Player &, const uint32); -template void WaypointMovementGenerator::MovementInform(Player &); //----------------------------------------------------// @@ -253,71 +196,72 @@ uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const void FlightPathMovementGenerator::Initialize(Player &player) { - player.getHostileRefManager().setOnlineOfflineState(false); - player.AddUnitState(UNIT_STAT_IN_FLIGHT); - player.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); - Traveller traveller(player); - // do not send movement, it was sent already - i_destinationHolder.SetDestination(traveller, (*i_path)[i_currentNode].x, (*i_path)[i_currentNode].y, (*i_path)[i_currentNode].z, false); - // For preloading end grid + Reset(player); InitEndGridInfo(); - player.SendMonsterMoveByPath(GetPath(), GetCurrentNode(), GetPathAtMapEnd()); } void FlightPathMovementGenerator::Finalize(Player & player) { + // remove flag to prevent send object build movement packets for flight state and crash (movement generator already not at top of stack) player.ClearUnitState(UNIT_STAT_IN_FLIGHT); - float x = 0; - float y = 0; - float z = 0; - i_destinationHolder.GetLocationNow(player.GetBaseMap(), x, y, z); - player.UpdatePosition(x, y, z, player.GetOrientation()); + player.Dismount(); + player.RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); + if(player.m_taxi.empty()) + { + player.getHostileRefManager().setOnlineOfflineState(true); + if(player.pvpInfo.inHostileArea) + player.CastSpell(&player, 2479, true); + + // update z position to ground and orientation for landing point + // this prevent cheating with landing point at lags + // when client side flight end early in comparison server side + player.StopMoving(); + } +} + +#define PLAYER_FLIGHT_SPEED 32.0f + +void FlightPathMovementGenerator::Reset(Player & player) +{ + player.getHostileRefManager().setOnlineOfflineState(false); + player.AddUnitState(UNIT_STAT_IN_FLIGHT); + player.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); + + Movement::MoveSplineInit init(player); + uint32 end = GetPathAtMapEnd(); + for (uint32 i = GetCurrentNode(); i != end; ++i) + { + G3D::Vector3 vertice((*i_path)[i].x,(*i_path)[i].y,(*i_path)[i].z); + init.Path().push_back(vertice); + } + init.SetFirstPointId(GetCurrentNode()); + init.SetFly(); + init.SetVelocity(PLAYER_FLIGHT_SPEED); + init.Launch(); } bool FlightPathMovementGenerator::Update(Player &player, const uint32 diff) { - if (MovementInProgress()) + uint32 pointId = (uint32)player.movespline->currentPathIdx(); + if (pointId > i_currentNode) { - Traveller traveller(player); - if (i_destinationHolder.UpdateTraveller(traveller, diff)) + bool departureEvent = true; + do { - i_destinationHolder.ResetUpdate(FLIGHT_TRAVEL_UPDATE); - if (i_destinationHolder.HasArrived()) - { - DoEventIfAny(player, (*i_path)[i_currentNode], false); - - uint32 curMap = (*i_path)[i_currentNode].mapid; - ++i_currentNode; - if (MovementInProgress()) - { - DoEventIfAny(player, (*i_path)[i_currentNode], true); - - sLog->outStaticDebug("loading node %u for player %s", i_currentNode, player.GetName()); - if ((*i_path)[i_currentNode].mapid == curMap) - { - // do not send movement, it was sent already - i_destinationHolder.SetDestination(traveller, (*i_path)[i_currentNode].x, (*i_path)[i_currentNode].y, (*i_path)[i_currentNode].z, false); - } - - // check if it's time to preload the flightmaster grid at path end - if (i_currentNode == m_preloadTargetNode) - PreloadEndGrid(); - - return true; - } - //else HasArrived() - } - else - return true; + DoEventIfAny(player, (*i_path)[i_currentNode], departureEvent); + if (pointId == i_currentNode) + break; + if (i_currentNode == _preloadTargetNode) + PreloadEndGrid(); + i_currentNode += (uint32)departureEvent; + departureEvent = !departureEvent; } - else - return true; + while (true); } - // we have arrived at the end of the path - return false; + return i_currentNode < (i_path->size()-1); } void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport() @@ -336,42 +280,48 @@ void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport() } } +void FlightPathMovementGenerator::DoEventIfAny(Player& player, TaxiPathNodeEntry const& node, bool departure) +{ + if (uint32 eventid = departure ? node.departureEventID : node.arrivalEventID) + { + sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node.index, node.path, player.GetName()); + player.GetMap()->ScriptsStart(sEventScripts, eventid, &player, &player); + } +} + +bool FlightPathMovementGenerator::GetResetPosition(Player&, float& x, float& y, float& z) +{ + const TaxiPathNodeEntry& node = (*i_path)[i_currentNode]; + x = node.x; y = node.y; z = node.z; + return true; +} + void FlightPathMovementGenerator::InitEndGridInfo() { - // Storage to preload flightmaster grid at end of flight. For multi-stop flights, this will - // be reinitialized for each flightmaster at the end of each spline (or stop) in the flight. - - uint32 nodeCount = (*i_path).size(); // Get the number of nodes in the path. - m_endMapId = (*i_path)[nodeCount -1].mapid; // Get the map ID from the last node - m_preloadTargetNode = nodeCount - 3; // 2 nodes before the final node, we pre-load the grid - m_endGridX = (*i_path)[nodeCount -1].x; // Get the X position from the last node - m_endGridY = (*i_path)[nodeCount -1].y; // Get the Y position from the last node + /*! Storage to preload flightmaster grid at end of flight. For multi-stop flights, this will + be reinitialized for each flightmaster at the end of each spline (or stop) in the flight. */ + uint32 nodeCount = (*i_path).size(); //! Number of nodes in path. + _endMapId = (*i_path)[nodeCount - 1].mapid; //! MapId of last node + _preloadTargetNode = nodeCount - 3; + _endGridX = (*i_path)[nodeCount - 1].x; + _endGridY = (*i_path)[nodeCount - 1].y; } void FlightPathMovementGenerator::PreloadEndGrid() { // used to preload the final grid where the flightmaster is - Map* endMap = sMapMgr->FindBaseNonInstanceMap(m_endMapId); + Map* endMap = sMapMgr->FindBaseNonInstanceMap(_endMapId); // Load the grid if (endMap) { - sLog->outDetail("Preloading flightmaster at grid (%f, %f) for map %u", m_endGridX, m_endGridY, m_endMapId); - endMap->LoadGrid(m_endGridX, m_endGridY); + sLog->outDetail("Preloading rid (%f, %f) for map %u at node index %u/%u", _endGridX, _endGridY, _endMapId, _preloadTargetNode, (uint32)(i_path->size()-1)); + endMap->LoadGrid(_endGridX, _endGridY); } else sLog->outDetail("Unable to determine map to preload flightmaster grid"); } -void FlightPathMovementGenerator::DoEventIfAny(Player& player, TaxiPathNodeEntry const& node, bool departure) -{ - if (uint32 eventid = departure ? node.departureEventID : node.arrivalEventID) - { - sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node.index, node.path, player.GetName()); - player.GetMap()->ScriptsStart(sEventScripts, eventid, &player, &player); - } -} - // // Unique1's ASTAR Pathfinding Code... For future use & reference... diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h index 230630936ff..aa6d327db3b 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h @@ -26,10 +26,8 @@ */ #include "MovementGenerator.h" -#include "DestinationHolder.h" #include "WaypointManager.h" #include "Path.h" -#include "Traveller.h" #include "Player.h" @@ -44,49 +42,68 @@ template class PathMovementBase { public: - PathMovementBase() : i_currentNode(0) {} + PathMovementBase() : i_currentNode(0), i_path(NULL) {} virtual ~PathMovementBase() {}; - bool MovementInProgress(void) const { return i_currentNode < i_path->size(); } - + // template pattern, not defined .. override required void LoadPath(T &); - void ReloadPath(T &); uint32 GetCurrentNode() const { return i_currentNode; } - bool GetDestination(float& x, float& y, float& z) const { i_destinationHolder.GetDestination(x, y, z); return true; } - bool GetPosition(float& x, float& y, float& z) const { i_destinationHolder.GetLocationNowNoMicroMovement(x, y, z); return true; } - protected: - uint32 i_currentNode; - DestinationHolder< Traveller > i_destinationHolder; P i_path; + uint32 i_currentNode; }; template +class WaypointMovementGenerator; -class WaypointMovementGenerator - : public MovementGeneratorMedium< T, WaypointMovementGenerator >, public PathMovementBase +template<> +class WaypointMovementGenerator +: public MovementGeneratorMedium< Creature, WaypointMovementGenerator >, +public PathMovementBase { public: - WaypointMovementGenerator(uint32 _path_id = 0, bool _repeating = true) : - node(NULL), path_id(_path_id), i_nextMoveTime(0), repeating(_repeating), StopedByPlayer(false) {} - - void Initialize(T &); - void Finalize(T &); - void MovementInform(T &); - void InitTraveller(T &, const WaypointData &); - void GeneratePathId(T &); - void Reset(T &unit); - bool Update(T &, const uint32); - bool GetDestination(float &x, float &y, float &z) const; + WaypointMovementGenerator(uint32 _path_id = 0, bool _repeating = true) : i_nextMoveTime(0), path_id(_path_id), m_isArrivalDone(false), repeating(_repeating) {} + ~WaypointMovementGenerator() { i_path = NULL; } + void Initialize(Creature &); + void Finalize(Creature &); + void Reset(Creature &); + bool Update(Creature &, const uint32 &diff); + + void MovementInform(Creature &); + MovementGeneratorType GetMovementGeneratorType() { return WAYPOINT_MOTION_TYPE; } + // now path movement implmementation + void LoadPath(Creature &c); + + bool GetResetPosition(Creature&, float& x, float& y, float& z); + private: - WaypointData* node; - uint32 path_id; + + void Stop(int32 time) { i_nextMoveTime.Reset(time);} + + bool Stopped() { return !i_nextMoveTime.Passed();} + + bool CanMove(int32 diff) + { + i_nextMoveTime.Update(diff); + return i_nextMoveTime.Passed(); + } + + void OnArrived(Creature&); + bool StartMove(Creature&); + + void StartMoveNow(Creature& creature) + { + i_nextMoveTime.Reset(0); + StartMove(creature); + } + TimeTrackerSmall i_nextMoveTime; - WaypointPath const* waypoints; - bool repeating, StopedByPlayer; + bool m_isArrivalDone; + uint32 path_id; + bool repeating; }; /** FlightPathMovementGenerator generates movement of the player for the paths @@ -103,7 +120,7 @@ public PathMovementBase i_currentNode = startNode; } void Initialize(Player &); - void Reset(Player & /*u*/){}; + void Reset(Player &); void Finalize(Player &); bool Update(Player &, const uint32); MovementGeneratorType GetMovementGeneratorType() { return FLIGHT_MOTION_TYPE; } @@ -115,17 +132,16 @@ public PathMovementBase void SkipCurrentNode() { ++i_currentNode; } void DoEventIfAny(Player& player, TaxiPathNodeEntry const& node, bool departure); - bool GetDestination(float& x, float& y, float& z) const { return PathMovementBase::GetDestination(x, y, z); } + bool GetResetPosition(Player&, float& x, float& y, float& z); - void PreloadEndGrid(); void InitEndGridInfo(); + void PreloadEndGrid(); + private: - // storage for preloading the flightmaster grid at end - // before reaching final waypoint - uint32 m_endMapId; - uint32 m_preloadTargetNode; - float m_endGridX; - float m_endGridY; + float _endGridX; //! X coord of last node location + float _endGridY; //! Y coord of last node location + uint32 _endMapId; //! map Id of last node location + uint32 _preloadTargetNode; //! node index where preloading starts }; #endif diff --git a/src/server/game/Movement/Spline/MoveSpline.cpp b/src/server/game/Movement/Spline/MoveSpline.cpp new file mode 100644 index 00000000000..4eaa6b57b36 --- /dev/null +++ b/src/server/game/Movement/Spline/MoveSpline.cpp @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2005-2011 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "MoveSpline.h" +#include +#include "Log.h" + +namespace Movement{ + +extern float computeFallTime(float path_length, bool isSafeFall); +extern float computeFallElevation(float time_passed, bool isSafeFall, float start_velocy); +extern float computeFallElevation(float time_passed); + +Location MoveSpline::ComputePosition() const +{ + ASSERT(Initialized()); + + float u = 1.f; + int32 seg_time = spline.length(point_Idx,point_Idx+1); + if (seg_time > 0) + u = (time_passed - spline.length(point_Idx)) / (float)seg_time; + Location c; + c.orientation = initialOrientation; + spline.evaluate_percent(point_Idx, u, c); + + if (splineflags.animation) + ;// MoveSplineFlag::Animation disables falling or parabolic movement + else if (splineflags.parabolic) + computeParabolicElevation(c.z); + else if (splineflags.falling) + computeFallElevation(c.z); + + if (splineflags.done && splineflags.isFacing()) + { + if (splineflags.final_angle) + c.orientation = facing.angle; + else if (splineflags.final_point) + c.orientation = atan2(facing.f.y-c.y, facing.f.x-c.x); + //nothing to do for MoveSplineFlag::Final_Target flag + } + else + { + if (!splineflags.hasFlag(MoveSplineFlag::OrientationFixed|MoveSplineFlag::Falling)) + { + Vector3 hermite; + spline.evaluate_derivative(point_Idx,u,hermite); + c.orientation = atan2(hermite.y, hermite.x); + } + + if (splineflags.orientationInversed) + c.orientation = -c.orientation; + } + return c; +} + +void MoveSpline::computeParabolicElevation(float& el) const +{ + if (time_passed > effect_start_time) + { + float t_passedf = MSToSec(time_passed - effect_start_time); + float t_durationf = MSToSec(Duration() - effect_start_time); //client use not modified duration here + + // -a*x*x + bx + c: + //(dur * v3->z_acceleration * dt)/2 - (v3->z_acceleration * dt * dt)/2 + Z; + el += (t_durationf - t_passedf) * 0.5f * vertical_acceleration * t_passedf; + } +} + +void MoveSpline::computeFallElevation(float& el) const +{ + float z_now = spline.getPoint(spline.first()).z - Movement::computeFallElevation(MSToSec(time_passed)); + float final_z = FinalDestination().z; + if (z_now < final_z) + el = final_z; + else + el = z_now; +} + +inline uint32 computeDuration(float length, float velocity) +{ + return SecToMS(length / velocity); +} + +struct FallInitializer +{ + FallInitializer(float _start_elevation) : start_elevation(_start_elevation) {} + float start_elevation; + inline int32 operator()(Spline& s, int32 i) + { + return Movement::computeFallTime(start_elevation - s.getPoint(i+1).z,false) * 1000.f; + } +}; + +enum{ + minimal_duration = 1, +}; + +struct CommonInitializer +{ + CommonInitializer(float _velocity) : velocityInv(1000.f/_velocity), time(minimal_duration) {} + float velocityInv; + int32 time; + inline int32 operator()(Spline& s, int32 i) + { + time += (s.SegLength(i) * velocityInv); + return time; + } +}; + +void MoveSpline::init_spline(const MoveSplineInitArgs& args) +{ + const SplineBase::EvaluationMode modes[2] = {SplineBase::ModeLinear,SplineBase::ModeCatmullrom}; + if (args.flags.cyclic) + { + uint32 cyclic_point = 0; + // MoveSplineFlag::Enter_Cycle support dropped + //if (splineflags & SPLINEFLAG_ENTER_CYCLE) + //cyclic_point = 1; // shouldn't be modified, came from client + spline.init_cyclic_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], cyclic_point); + } + else + { + spline.init_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()]); + } + + // init spline timestamps + if (splineflags.falling) + { + FallInitializer init(spline.getPoint(spline.first()).z); + spline.initLengths(init); + } + else + { + CommonInitializer init(args.velocity); + spline.initLengths(init); + } + + // TODO: what to do in such cases? problem is in input data (all points are at same coords) + if (spline.length() < minimal_duration) + { + sLog->outError("MoveSpline::init_spline: zero length spline, wrong input data?"); + spline.set_length(spline.last(), spline.isCyclic() ? 1000 : 1); + } + point_Idx = spline.first(); +} + +void MoveSpline::Initialize(const MoveSplineInitArgs& args) +{ + splineflags = args.flags; + facing = args.facing; + m_Id = args.splineId; + point_Idx_offset = args.path_Idx_offset; + initialOrientation = args.initialOrientation; + + time_passed = 0; + vertical_acceleration = 0.f; + effect_start_time = 0; + + init_spline(args); + + // init parabolic / animation + // spline initialized, duration known and i able to compute parabolic acceleration + if (args.flags & (MoveSplineFlag::Parabolic | MoveSplineFlag::Animation)) + { + effect_start_time = Duration() * args.time_perc; + if (args.flags.parabolic && effect_start_time < Duration()) + { + float f_duration = MSToSec(Duration() - effect_start_time); + vertical_acceleration = args.parabolic_amplitude * 8.f / (f_duration * f_duration); + } + } +} + +MoveSpline::MoveSpline() : m_Id(0), time_passed(0), + vertical_acceleration(0.f), effect_start_time(0), point_Idx(0), point_Idx_offset(0), initialOrientation(0.f) +{ + splineflags.done = true; +} + +/// ============================================================================================ + +bool MoveSplineInitArgs::Validate() const +{ +#define CHECK(exp) \ + if (!(exp))\ + {\ + sLog->outError("MoveSplineInitArgs::Validate: expression '%s' failed", #exp);\ + return false;\ + } + CHECK(path.size() > 1); + CHECK(velocity > 0.f); + CHECK(time_perc >= 0.f && time_perc <= 1.f); + //CHECK(_checkPathBounds()); + return true; +#undef CHECK +} + +// MONSTER_MOVE packet format limitation for not CatmullRom movement: +// each vertex offset packed into 11 bytes +bool MoveSplineInitArgs::_checkPathBounds() const +{ + if (!(flags & MoveSplineFlag::Mask_CatmullRom) && path.size() > 2) + { + enum{ + MAX_OFFSET = (1 << 11) / 2, + }; + Vector3 middle = (path.front()+path.back()) / 2; + Vector3 offset; + for (uint32 i = 1; i < path.size()-1; ++i) + { + offset = path[i] - middle; + if (fabs(offset.x) >= MAX_OFFSET || fabs(offset.y) >= MAX_OFFSET || fabs(offset.z) >= MAX_OFFSET) + { + sLog->outError("MoveSplineInitArgs::_checkPathBounds check failed"); + return false; + } + } + } + return true; +} + +/// ============================================================================================ + +MoveSpline::UpdateResult MoveSpline::_updateState(int32& ms_time_diff) +{ + if (Finalized()) + { + ms_time_diff = 0; + return Result_Arrived; + } + + UpdateResult result = Result_None; + + int32 minimal_diff = std::min(ms_time_diff, segment_time_elapsed()); + ASSERT(minimal_diff >= 0); + time_passed += minimal_diff; + ms_time_diff -= minimal_diff; + + if (time_passed >= next_timestamp()) + { + ++point_Idx; + if (point_Idx < spline.last()) + { + result = Result_NextSegment; + } + else + { + if (spline.isCyclic()) + { + point_Idx = spline.first(); + time_passed = time_passed % Duration(); + result = Result_NextSegment; + } + else + { + _Finalize(); + ms_time_diff = 0; + result = Result_Arrived; + } + } + } + + return result; +} + +std::string MoveSpline::ToString() const +{ + std::stringstream str; + str << "MoveSpline" << std::endl; + str << "spline Id: " << GetId() << std::endl; + str << "flags: " << splineflags.ToString() << std::endl; + if (splineflags.final_angle) + str << "facing angle: " << facing.angle; + else if (splineflags.final_target) + str << "facing target: " << facing.target; + else if(splineflags.final_point) + str << "facing point: " << facing.f.x << " " << facing.f.y << " " << facing.f.z; + str << std::endl; + str << "time passed: " << time_passed << std::endl; + str << "total time: " << Duration() << std::endl; + str << "spline point Id: " << point_Idx << std::endl; + str << "path point Id: " << currentPathIdx() << std::endl; + str << spline.ToString(); + return str.str(); +} + +void MoveSpline::_Finalize() +{ + splineflags.done = true; + point_Idx = spline.last() - 1; + time_passed = Duration(); +} + +int32 MoveSpline::currentPathIdx() const +{ + int32 point = point_Idx_offset + point_Idx - spline.first() + (int)Finalized(); + if (isCyclic()) + point = point % (spline.last()-spline.first()); + return point; +} +} diff --git a/src/server/game/Movement/Spline/MoveSpline.h b/src/server/game/Movement/Spline/MoveSpline.h new file mode 100644 index 00000000000..4b8dbcc8ee3 --- /dev/null +++ b/src/server/game/Movement/Spline/MoveSpline.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2005-2011 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITYSERVER_MOVEPLINE_H +#define TRINITYSERVER_MOVEPLINE_H + +#include "Spline.h" +#include "MoveSplineInitArgs.h" + +namespace Movement +{ + struct Location : public Vector3 + { + Location() : orientation(0) {} + Location(float x, float y, float z, float o) : Vector3(x,y,z), orientation(o) {} + Location(const Vector3& v) : Vector3(v), orientation(0) {} + Location(const Vector3& v, float o) : Vector3(v), orientation(o) {} + + float orientation; + }; + + // MoveSpline represents smooth catmullrom or linear curve and point that moves belong it + // curve can be cyclic - in this case movement will be cyclic + // point can have vertical acceleration motion componemt(used in fall, parabolic movement) + class MoveSpline + { + public: + typedef Spline MySpline; + enum UpdateResult{ + Result_None = 0x01, + Result_Arrived = 0x02, + Result_NextCycle = 0x04, + Result_NextSegment = 0x08, + }; + #pragma region fields + friend class PacketBuilder; + protected: + MySpline spline; + + FacingInfo facing; + + uint32 m_Id; + + MoveSplineFlag splineflags; + + int32 time_passed; + // currently duration mods are unused, but its _currently_ + //float duration_mod; + //float duration_mod_next; + float vertical_acceleration; + float initialOrientation; + int32 effect_start_time; + int32 point_Idx; + int32 point_Idx_offset; + + void init_spline(const MoveSplineInitArgs& args); + protected: + + const MySpline::ControlArray& getPath() const { return spline.getPoints();} + void computeParabolicElevation(float& el) const; + void computeFallElevation(float& el) const; + + UpdateResult _updateState(int32& ms_time_diff); + int32 next_timestamp() const { return spline.length(point_Idx+1);} + int32 segment_time_elapsed() const { return next_timestamp()-time_passed;} + int32 Duration() const { return spline.length();} + int32 timeElapsed() const { return Duration() - time_passed;} + int32 timePassed() const { return time_passed;} + + public: + const MySpline& _Spline() const { return spline;} + int32 _currentSplineIdx() const { return point_Idx;} + void _Finalize(); + void _Interrupt() { splineflags.done = true;} + + #pragma endregion + public: + + void Initialize(const MoveSplineInitArgs&); + bool Initialized() const { return !spline.empty();} + + explicit MoveSpline(); + + template + void updateState(int32 difftime, UpdateHandler& handler) + { + ASSERT(Initialized()); + do + handler(_updateState(difftime)); + while(difftime > 0); + } + + void updateState(int32 difftime) + { + ASSERT(Initialized()); + do _updateState(difftime); + while(difftime > 0); + } + + Location ComputePosition() const; + + uint32 GetId() const { return m_Id;} + bool Finalized() const { return splineflags.done; } + bool isCyclic() const { return splineflags.cyclic;} + const Vector3 FinalDestination() const { return Initialized() ? spline.getPoint(spline.last()) : Vector3();} + const Vector3 CurrentDestination() const { return Initialized() ? spline.getPoint(point_Idx+1) : Vector3();} + int32 currentPathIdx() const; + + std::string ToString() const; + }; +} +#endif // TRINITYSERVER_MOVEPLINE_H diff --git a/src/server/game/Movement/Spline/MoveSplineFlag.h b/src/server/game/Movement/Spline/MoveSplineFlag.h new file mode 100644 index 00000000000..de91f63c30a --- /dev/null +++ b/src/server/game/Movement/Spline/MoveSplineFlag.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2005-2011 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITYSERVER_MOVESPLINEFLAG_H +#define TRINITYSERVER_MOVESPLINEFLAG_H +#include "MovementTypedefs.h" + +#include + +namespace Movement +{ +#if defined( __GNUC__ ) +#pragma pack(1) +#else +#pragma pack(push,1) +#endif + + class MoveSplineFlag + { + public: + enum eFlags{ + None = 0x00000000, + // x00-xFF(first byte) used as animation Ids storage in pair with Animation flag + Done = 0x00000100, + Falling = 0x00000200, // Affects elevation computation, can't be combined with Parabolic flag + No_Spline = 0x00000400, + Parabolic = 0x00000800, // Affects elevation computation, can't be combined with Falling flag + Walkmode = 0x00001000, + Flying = 0x00002000, // Smooth movement(Catmullrom interpolation mode), flying animation + OrientationFixed = 0x00004000, // Model orientation fixed + Final_Point = 0x00008000, + Final_Target = 0x00010000, + Final_Angle = 0x00020000, + Catmullrom = 0x00040000, // Used Catmullrom interpolation mode + Cyclic = 0x00080000, // Movement by cycled spline + Enter_Cycle = 0x00100000, // Everytimes appears with cyclic flag in monster move packet, erases first spline vertex after first cycle done + Animation = 0x00200000, // Plays animation after some time passed + Frozen = 0x00400000, // Will never arrive + Unknown5 = 0x00800000, + Unknown6 = 0x01000000, + Unknown7 = 0x02000000, + Unknown8 = 0x04000000, + OrientationInversed = 0x08000000, + Unknown10 = 0x10000000, + Unknown11 = 0x20000000, + Unknown12 = 0x40000000, + Unknown13 = 0x80000000, + + // Masks + Mask_Final_Facing = Final_Point | Final_Target | Final_Angle, + // animation ids stored here, see AnimType enum, used with Animation flag + Mask_Animations = 0xFF, + // flags that shouldn't be appended into SMSG_MONSTER_MOVE\SMSG_MONSTER_MOVE_TRANSPORT packet, should be more probably + Mask_No_Monster_Move = Mask_Final_Facing | Mask_Animations | Done, + // CatmullRom interpolation mode used + Mask_CatmullRom = Flying | Catmullrom, + // Unused, not suported flags + Mask_Unused = No_Spline|Enter_Cycle|Frozen|Unknown5|Unknown6|Unknown7|Unknown8|Unknown10|Unknown11|Unknown12|Unknown13, + }; + + inline uint32& raw() { return (uint32&)*this;} + inline const uint32& raw() const { return (const uint32&)*this;} + + MoveSplineFlag() { raw() = 0; } + MoveSplineFlag(uint32 f) { raw() = f; } + MoveSplineFlag(const MoveSplineFlag& f) { raw() = f.raw(); } + + // Constant interface + + bool isSmooth() const { return raw() & Mask_CatmullRom;} + bool isLinear() const { return !isSmooth();} + bool isFacing() const { return raw() & Mask_Final_Facing;} + + uint8 getAnimationId() const { return animId;} + bool hasAllFlags(uint32 f) const { return (raw() & f) == f;} + bool hasFlag(uint32 f) const { return (raw() & f) != 0;} + uint32 operator & (uint32 f) const { return (raw() & f);} + uint32 operator | (uint32 f) const { return (raw() | f);} + std::string ToString() const; + + // Not constant interface + + void operator &= (uint32 f) { raw() &= f;} + void operator |= (uint32 f) { raw() |= f;} + + void EnableAnimation(uint8 anim) { raw() = raw() & ~(Mask_Animations|Falling|Parabolic) | Animation|anim;} + void EnableParabolic() { raw() = raw() & ~(Mask_Animations|Falling|Animation) | Parabolic;} + void EnableFalling() { raw() = raw() & ~(Mask_Animations|Parabolic|Animation) | Falling;} + void EnableFlying() { raw() = raw() & ~Catmullrom | Flying; } + void EnableCatmullRom() { raw() = raw() & ~Flying | Catmullrom; } + void EnableFacingPoint() { raw() = raw() & ~Mask_Final_Facing | Final_Point;} + void EnableFacingAngle() { raw() = raw() & ~Mask_Final_Facing | Final_Angle;} + void EnableFacingTarget() { raw() = raw() & ~Mask_Final_Facing | Final_Target;} + + uint8 animId : 8; + bool done : 1; + bool falling : 1; + bool no_spline : 1; + bool parabolic : 1; + bool walkmode : 1; + bool flying : 1; + bool orientationFixed : 1; + bool final_point : 1; + bool final_target : 1; + bool final_angle : 1; + bool catmullrom : 1; + bool cyclic : 1; + bool enter_cycle : 1; + bool animation : 1; + bool frozen : 1; + bool unknown5 : 1; + bool unknown6 : 1; + bool unknown7 : 1; + bool unknown8 : 1; + bool orientationInversed : 1; + bool unknown10 : 1; + bool unknown11 : 1; + bool unknown12 : 1; + bool unknown13 : 1; + }; +#if defined( __GNUC__ ) +#pragma pack() +#else +#pragma pack(pop) +#endif +} + +#endif // TRINITYSERVER_MOVESPLINEFLAG_H diff --git a/src/server/game/Movement/Spline/MoveSplineInit.cpp b/src/server/game/Movement/Spline/MoveSplineInit.cpp new file mode 100644 index 00000000000..885ade57653 --- /dev/null +++ b/src/server/game/Movement/Spline/MoveSplineInit.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2005-2011 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "MoveSplineInit.h" +#include "MoveSpline.h" +#include "MovementPacketBuilder.h" +#include "Unit.h" + +namespace Movement +{ + UnitMoveType SelectSpeedType(uint32 moveFlags) + { + if (moveFlags & MOVEMENTFLAG_FLYING) + { + if ( moveFlags & MOVEMENTFLAG_BACKWARD /*&& speed_obj.flight >= speed_obj.flight_back*/ ) + return MOVE_FLIGHT_BACK; + else + return MOVE_FLIGHT; + } + else if (moveFlags & MOVEMENTFLAG_SWIMMING) + { + if (moveFlags & MOVEMENTFLAG_BACKWARD /*&& speed_obj.swim >= speed_obj.swim_back*/) + return MOVE_SWIM_BACK; + else + return MOVE_SWIM; + } + else if (moveFlags & MOVEMENTFLAG_WALKING) + { + //if ( speed_obj.run > speed_obj.walk ) + return MOVE_WALK; + } + else if (moveFlags & MOVEMENTFLAG_BACKWARD /*&& speed_obj.run >= speed_obj.run_back*/) + return MOVE_RUN_BACK; + + return MOVE_RUN; + } + + void MoveSplineInit::Launch() + { + MoveSpline& move_spline = *unit.movespline; + + Location real_position(unit.GetPositionX(),unit.GetPositionY(),unit.GetPositionZ(),unit.GetOrientation()); + // there is a big chane that current position is unknown if current state is not finalized, need compute it + // this also allows calculate spline position and update map position in much greater intervals + if (!move_spline.Finalized()) + real_position = move_spline.ComputePosition(); + + if (args.path.empty()) + { + // should i do the things that user should do? + MoveTo(real_position); + } + + // corrent first vertex + args.path[0] = real_position; + args.initialOrientation = real_position.orientation; + + uint32 moveFlags = unit.m_movementInfo.GetMovementFlags(); + if (args.flags.walkmode) + moveFlags |= MOVEMENTFLAG_WALKING; + else + moveFlags &= ~MOVEMENTFLAG_WALKING; + + moveFlags |= (MOVEMENTFLAG_SPLINE_ENABLED|MOVEMENTFLAG_FORWARD); + + if (args.velocity == 0.f) + args.velocity = unit.GetSpeed(SelectSpeedType(moveFlags)); + + if (!args.Validate()) + return; + + if (moveFlags & MOVEMENTFLAG_ROOT) + moveFlags &= ~MOVEMENTFLAG_MASK_MOVING; + + unit.m_movementInfo.SetMovementFlags((MovementFlags)moveFlags); + move_spline.Initialize(args); + + WorldPacket data(SMSG_MONSTER_MOVE, 64); + data.append(unit.GetPackGUID()); + PacketBuilder::WriteMonsterMove(move_spline, data); + unit.SendMessageToSet(&data,true); + } + + MoveSplineInit::MoveSplineInit(Unit& m) : unit(m) + { + // mix existing state into new + args.flags.walkmode = unit.m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING); + args.flags.flying = unit.m_movementInfo.HasMovementFlag((MovementFlags)(MOVEMENTFLAG_FLYING|MOVEMENTFLAG_LEVITATING)); + } + + 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); + } + + void MoveSplineInit::SetFacing(float angle) + { + args.facing.angle = G3D::wrap(angle, 0.f, (float)G3D::twoPi()); + args.flags.EnableFacingAngle(); + } +} diff --git a/src/server/game/Movement/Spline/MoveSplineInit.h b/src/server/game/Movement/Spline/MoveSplineInit.h new file mode 100644 index 00000000000..7ef6cd7a120 --- /dev/null +++ b/src/server/game/Movement/Spline/MoveSplineInit.h @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2005-2011 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITYSERVER_MOVESPLINEINIT_H +#define TRINITYSERVER_MOVESPLINEINIT_H + +#include "MoveSplineInitArgs.h" + +class Unit; + +namespace Movement +{ + enum AnimType + { + ToGround = 0, // 460 = ToGround, index of AnimationData.dbc + FlyToFly = 1, // 461 = FlyToFly? + ToFly = 2, // 458 = ToFly + FlyToGround = 3, // 463 = FlyToGround + }; + + /* Initializes and launches spline movement + */ + class MoveSplineInit + { + public: + + explicit MoveSplineInit(Unit& m); + + /* Final pass of initialization that launches spline movement. + */ + void Launch(); + + /* Adds movement by parabolic trajectory + * @param amplitude - the maximum height of parabola, value could be negative and positive + * @param start_time - delay between movement starting time and beginning to move by parabolic trajectory + * can't be combined with final animation + */ + void SetParabolic(float amplitude, float start_time); + /* Plays animation after movement done + * can't be combined with parabolic movement + */ + void SetAnimation(AnimType anim); + + /* Adds final facing animation + * sets unit's facing to specified point/angle after all path done + * you can have only one final facing: previous will be overriden + */ + void SetFacing(float angle); + void SetFacing(Vector3 const& point); + void SetFacing(const Unit * target); + + /* Initializes movement by path + * @param path - array of points, shouldn't be empty + * @param pointId - Id of fisrt point of the path. Example: when third path point will be done it will notify that pointId + 3 done + */ + void MovebyPath(const PointsArray& path, int32 pointId = 0); + + /* Initializes simple A to B mition, A is current unit's position, B is destination + */ + void MoveTo(const Vector3& destination); + void MoveTo(float x, float y, float z); + + /* Sets Id of fisrt point of the path. When N-th path point will be done ILisener will notify that pointId + N done + * Needed for waypoint movement where path splitten into parts + */ + void SetFirstPointId(int32 pointId) { args.path_Idx_offset = pointId; } + + /* Enables CatmullRom spline interpolation mode(makes path smooth) + * if not enabled linear spline mode will be choosen. Disabled by default + */ + void SetSmooth(); + /* Enables CatmullRom spline interpolation mode, enables flying animation. Disabled by default + */ + void SetFly(); + /* Enables walk mode. Disabled by default + */ + void SetWalk(bool enable); + /* Makes movement cyclic. Disabled by default + */ + void SetCyclic(); + /* Enables falling mode. Disabled by default + */ + void SetFall(); + /* Inverses unit model orientation. Disabled by default + */ + void SetOrientationInversed(); + /* Fixes unit's model rotation. Disabled by default + */ + void SetOrientationFixed(bool enable); + + /* Sets the velocity (in case you want to have custom movement velocity) + * if no set, speed will be selected based on unit's speeds and current movement mode + * Has no effect if falling mode enabled + * velocity shouldn't be negative + */ + void SetVelocity(float velocity); + + PointsArray& Path() { return args.path; } + + protected: + + MoveSplineInitArgs args; + Unit& unit; + }; + + inline void MoveSplineInit::SetFly() { args.flags.EnableFlying();} + inline void MoveSplineInit::SetWalk(bool enable) { args.flags.walkmode = enable;} + inline void MoveSplineInit::SetSmooth() { args.flags.EnableCatmullRom();} + inline void MoveSplineInit::SetCyclic() { args.flags.cyclic = true;} + inline void MoveSplineInit::SetFall() { args.flags.EnableFalling();} + inline void MoveSplineInit::SetVelocity(float vel){ args.velocity = vel;} + inline void MoveSplineInit::SetOrientationInversed() { args.flags.orientationInversed = true;} + inline void MoveSplineInit::SetOrientationFixed(bool enable) { args.flags.orientationFixed = enable;} + + inline void MoveSplineInit::MovebyPath(const PointsArray& controls, int32 path_offset) + { + args.path_Idx_offset = path_offset; + args.path.assign(controls.begin(),controls.end()); + } + + inline void MoveSplineInit::MoveTo(float x, float y, float z) + { + Vector3 v(x,y,z); + MoveTo(v); + } + + inline void MoveSplineInit::MoveTo(const Vector3& dest) + { + args.path_Idx_offset = 0; + args.path.resize(2); + args.path[1] = dest; + } + + inline void MoveSplineInit::SetParabolic(float amplitude, float time_shift) + { + args.time_perc = time_shift; + args.parabolic_amplitude = amplitude; + args.flags.EnableParabolic(); + } + + inline void MoveSplineInit::SetAnimation(AnimType anim) + { + args.time_perc = 0.f; + args.flags.EnableAnimation((uint8)anim); + } + + inline void MoveSplineInit::SetFacing(Vector3 const& spot) + { + args.facing.f.x = spot.x; + args.facing.f.y = spot.y; + args.facing.f.z = spot.z; + args.flags.EnableFacingPoint(); + } +} +#endif // TRINITYSERVER_MOVESPLINEINIT_H diff --git a/src/server/game/Movement/Spline/MoveSplineInitArgs.h b/src/server/game/Movement/Spline/MoveSplineInitArgs.h new file mode 100644 index 00000000000..26fbbdd0fcc --- /dev/null +++ b/src/server/game/Movement/Spline/MoveSplineInitArgs.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2005-2011 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITYSERVER_MOVESPLINEINIT_ARGS_H +#define TRINITYSERVER_MOVESPLINEINIT_ARGS_H + +#include "MoveSplineFlag.h" +#include + +namespace Movement +{ + typedef std::vector PointsArray; + + union FacingInfo + { + struct{ + float x,y,z; + }f; + uint64 target; + float angle; + + FacingInfo(float o) : angle(o) {} + FacingInfo(uint64 t) : target(t) {} + FacingInfo() {} + }; + + struct MoveSplineInitArgs + { + MoveSplineInitArgs(size_t path_capacity = 16) : path_Idx_offset(0), + velocity(0.f), parabolic_amplitude(0.f), time_perc(0.f), splineId(0), initialOrientation(0.f) + { + path.reserve(path_capacity); + } + + PointsArray path; + FacingInfo facing; + MoveSplineFlag flags; + int32 path_Idx_offset; + float velocity; + float parabolic_amplitude; + float time_perc; + uint32 splineId; + float initialOrientation; + + /** Returns true to show that the arguments were configured correctly and MoveSpline initialization will succeed. */ + bool Validate() const; + private: + bool _checkPathBounds() const; + }; +} + +#endif // TRINITYSERVER_MOVESPLINEINIT_ARGS_H diff --git a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp new file mode 100644 index 00000000000..73fdbf4c2f6 --- /dev/null +++ b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2005-2011 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "MovementPacketBuilder.h" +#include "MoveSpline.h" +#include "WorldPacket.h" + +namespace Movement +{ + inline void operator << (ByteBuffer& b, const Vector3& v) + { + b << v.x << v.y << v.z; + } + + inline void operator >> (ByteBuffer& b, Vector3& v) + { + b >> v.x >> v.y >> v.z; + } + + enum MonsterMoveType + { + MonsterMoveNormal = 0, + MonsterMoveStop = 1, + MonsterMoveFacingSpot = 2, + MonsterMoveFacingTarget = 3, + MonsterMoveFacingAngle = 4 + }; + + void PacketBuilder::WriteCommonMonsterMovePart(const MoveSpline& move_spline, WorldPacket& data) + { + MoveSplineFlag splineflags = move_spline.splineflags; + /*if (mov.IsBoarded()) + { + data.SetOpcode(SMSG_MONSTER_MOVE_TRANSPORT); + data << mov.GetTransport()->Owner.GetPackGUID(); + data << int8(mov.m_unused.transport_seat); + }*/ + + data << uint8(0); + data << move_spline.spline.getPoint(move_spline.spline.first()); + data << move_spline.GetId(); + + switch(splineflags & MoveSplineFlag::Mask_Final_Facing) + { + default: + data << uint8(MonsterMoveNormal); + break; + case MoveSplineFlag::Final_Target: + data << uint8(MonsterMoveFacingTarget); + data << move_spline.facing.target; + break; + case MoveSplineFlag::Final_Angle: + data << uint8(MonsterMoveFacingAngle); + data << move_spline.facing.angle; + break; + case MoveSplineFlag::Final_Point: + data << uint8(MonsterMoveFacingSpot); + data << move_spline.facing.f.x << move_spline.facing.f.y << move_spline.facing.f.z; + break; + } + + // add fake Enter_Cycle flag - needed for client-side cyclic movement (client will erase first spline vertex after first cycle done) + splineflags.enter_cycle = move_spline.isCyclic(); + data << uint32(splineflags & ~MoveSplineFlag::Mask_No_Monster_Move); + + if (splineflags.animation) + { + data << splineflags.getAnimationId(); + data << move_spline.effect_start_time; + } + + data << move_spline.Duration(); + + if (splineflags.parabolic) + { + data << move_spline.vertical_acceleration; + data << move_spline.effect_start_time; + } + } + + void WriteLinearPath(const Spline& spline, ByteBuffer& data) + { + uint32 last_idx = spline.getPointCount() - 3; + const Vector3 * real_path = &spline.getPoint(1); + + data << last_idx; + data << real_path[last_idx]; // destination + if (last_idx > 1) + { + Vector3 middle = (real_path[0] + real_path[last_idx]) / 2.f; + Vector3 offset; + // first and last points already appended + for(uint32 i = 1; i < last_idx; ++i) + { + offset = middle - real_path[i]; + data.appendPackXYZ(offset.x, offset.y, offset.z); + } + } + } + + void WriteCatmullRomPath(const Spline& spline, ByteBuffer& data) + { + uint32 count = spline.getPointCount() - 3; + data << count; + data.append(&spline.getPoint(2), count); + } + + void WriteCatmullRomCyclicPath(const Spline& spline, ByteBuffer& data) + { + uint32 count = spline.getPointCount() - 3; + data << uint32(count + 1); + data << spline.getPoint(1); // fake point, client will erase it from the spline after first cycle done + data.append(&spline.getPoint(1), count); + } + + void PacketBuilder::WriteMonsterMove(const MoveSpline& move_spline, WorldPacket& data) + { + WriteCommonMonsterMovePart(move_spline, data); + + const Spline& spline = move_spline.spline; + MoveSplineFlag splineflags = move_spline.splineflags; + if (splineflags & MoveSplineFlag::Mask_CatmullRom) + { + if (splineflags.cyclic) + WriteCatmullRomCyclicPath(spline, data); + else + WriteCatmullRomPath(spline, data); + } + else + WriteLinearPath(spline, data); + } + + void PacketBuilder::WriteCreate(const MoveSpline& move_spline, ByteBuffer& data) + { + //WriteClientStatus(mov,data); + //data.append(&mov.m_float_values[SpeedWalk], SpeedMaxCount); + //if (mov.SplineEnabled()) + { + MoveSplineFlag splineFlags = move_spline.splineflags; + + data << splineFlags.raw(); + + if (splineFlags.final_angle) + { + data << move_spline.facing.angle; + } + else if (splineFlags.final_target) + { + data << move_spline.facing.target; + } + else if(splineFlags.final_point) + { + data << move_spline.facing.f.x << move_spline.facing.f.y << move_spline.facing.f.z; + } + + data << move_spline.timePassed(); + data << move_spline.Duration(); + data << move_spline.GetId(); + + data << float(1.f); // splineInfo.duration_mod; added in 3.1 + data << float(1.f); // splineInfo.duration_mod_next; added in 3.1 + + data << move_spline.vertical_acceleration; // added in 3.1 + data << move_spline.effect_start_time; // added in 3.1 + + uint32 nodes = move_spline.getPath().size(); + data << nodes; + data.append(&move_spline.getPath()[0], nodes); + data << uint8(move_spline.spline.mode()); // added in 3.1 + data << (move_spline.isCyclic() ? Vector3::zero() : move_spline.FinalDestination()); + } + } +} diff --git a/src/server/game/Movement/Spline/MovementPacketBuilder.h b/src/server/game/Movement/Spline/MovementPacketBuilder.h new file mode 100644 index 00000000000..92a414e9b3b --- /dev/null +++ b/src/server/game/Movement/Spline/MovementPacketBuilder.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2005-2011 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITYSERVER_PACKET_BUILDER_H +#define TRINITYSERVER_PACKET_BUILDER_H + +class ByteBuffer; +class WorldPacket; + +namespace Movement +{ + class MoveSpline; + class PacketBuilder + { + static void WriteCommonMonsterMovePart(const MoveSpline& mov, WorldPacket& data); + public: + + static void WriteMonsterMove(const MoveSpline& mov, WorldPacket& data); + static void WriteCreate(const MoveSpline& mov, ByteBuffer& data); + }; +} +#endif // TRINITYSERVER_PACKET_BUILDER_H diff --git a/src/server/game/Movement/Spline/MovementTypedefs.h b/src/server/game/Movement/Spline/MovementTypedefs.h new file mode 100644 index 00000000000..01c8a5b7e7b --- /dev/null +++ b/src/server/game/Movement/Spline/MovementTypedefs.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2005-2011 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITYSERVER_TYPEDEFS_H +#define TRINITYSERVER_TYPEDEFS_H + +#include "Common.h" + +namespace G3D +{ + class Vector2; + class Vector3; + class Vector4; +} + +namespace Movement +{ + using G3D::Vector2; + using G3D::Vector3; + using G3D::Vector4; + + inline uint32 SecToMS(float sec) + { + return static_cast(sec * 1000.f); + } + + inline float MSToSec(uint32 ms) + { + return ms / 1000.f; + } + +#ifndef static_assert + #define CONCAT(x, y) CONCAT1 (x, y) + #define CONCAT1(x, y) x##y + #define static_assert(expr, msg) typedef char CONCAT(static_assert_failed_at_line_, __LINE__) [(expr) ? 1 : -1] +#endif + + template + class counter + { + public: + counter() { init();} + + void Increase() + { + if (m_counter == limit) + init(); + else + ++m_counter; + } + + T NewId() { Increase(); return m_counter;} + T getCurrent() const { return m_counter;} + + private: + void init() { m_counter = 0; } + T m_counter; + }; + + typedef counter UInt32Counter; + + extern double gravity; + extern float computeFallElevation(float t_passed, bool isSafeFall, float start_velocity); +} + +#endif // TRINITYSERVER_TYPEDEFS_H diff --git a/src/server/game/Movement/Spline/MovementUtil.cpp b/src/server/game/Movement/Spline/MovementUtil.cpp new file mode 100644 index 00000000000..f0ed01c4676 --- /dev/null +++ b/src/server/game/Movement/Spline/MovementUtil.cpp @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2005-2011 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "MoveSplineFlag.h" +#include +#include + +namespace Movement +{ + double gravity = 19.29110527038574; + + /// Velocity bounds that makes fall speed limited + float terminalVelocity = 60.148003f; + float terminalSavefallVelocity = 7.f; + + const float terminal_length = float(terminalVelocity * terminalVelocity) / (2.f * gravity); + const float terminal_savefall_length = (terminalSavefallVelocity * terminalSavefallVelocity) / (2.f * gravity); + const float terminalFallTime = float(terminalVelocity/gravity); // the time that needed to reach terminalVelocity + + float computeFallTime(float path_length, bool isSafeFall) + { + if (path_length < 0.f) + return 0.f; + + float time; + if ( isSafeFall ) + { + if (path_length >= terminal_savefall_length) + time = (path_length - terminal_savefall_length)/terminalSavefallVelocity + terminalSavefallVelocity/gravity; + else + time = sqrtf(2.f * path_length/gravity); + } + else + { + if (path_length >= terminal_length) + time = (path_length - terminal_length)/terminalVelocity + terminalFallTime; + else + time = sqrtf(2.f * path_length/gravity); + } + + return time; + } + + float computeFallElevation(float t_passed, bool isSafeFall, float start_velocity) + { + float termVel; + float result; + + if ( isSafeFall ) + termVel = terminalSavefallVelocity; + else + termVel = terminalVelocity; + + if ( start_velocity > termVel ) + start_velocity = termVel; + + float terminal_time = terminalFallTime - start_velocity / gravity; // the time that needed to reach terminalVelocity + + if ( t_passed > terminal_time ) + { + result = terminalVelocity*(t_passed - terminal_time) + + start_velocity*terminal_time + gravity*terminal_time*terminal_time*0.5f; + } + else + result = t_passed * (start_velocity + t_passed * gravity * 0.5f); + + return result; + } + + float computeFallElevation(float t_passed) + { + float result; + + if (t_passed > terminalFallTime) + { + //result = terminalVelocity * (t_passed - terminal_time) + gravity*terminal_time*terminal_time*0.5f; + // simplified view: + result = terminalVelocity * (t_passed - terminalFallTime) + terminal_length; + } + else + result = t_passed * t_passed * gravity * 0.5f; + + return result; + } + + #define STR(x) #x + + const char * g_MovementFlag_names[]= + { + STR(Forward ),// 0x00000001, + STR(Backward ),// 0x00000002, + STR(Strafe_Left ),// 0x00000004, + STR(Strafe_Right ),// 0x00000008, + STR(Turn_Left ),// 0x00000010, + STR(Turn_Right ),// 0x00000020, + STR(Pitch_Up ),// 0x00000040, + STR(Pitch_Down ),// 0x00000080, + + STR(Walk ),// 0x00000100, // Walking + STR(Ontransport ),// 0x00000200, + STR(Levitation ),// 0x00000400, + STR(Root ),// 0x00000800, + STR(Falling ),// 0x00001000, + STR(Fallingfar ),// 0x00002000, + STR(Pendingstop ),// 0x00004000, + STR(PendingSTRafestop ),// 0x00008000, + STR(Pendingforward ),// 0x00010000, + STR(Pendingbackward ),// 0x00020000, + STR(PendingSTRafeleft ),// 0x00040000, + STR(PendingSTRaferight ),// 0x00080000, + STR(Pendingroot ),// 0x00100000, + STR(Swimming ),// 0x00200000, // Appears With Fly Flag Also + STR(Ascending ),// 0x00400000, // Swim Up Also + STR(Descending ),// 0x00800000, // Swim Down Also + STR(Can_Fly ),// 0x01000000, // Can Fly In 3.3? + STR(Flying ),// 0x02000000, // Actual Flying Mode + STR(Spline_Elevation ),// 0x04000000, // Used For Flight Paths + STR(Spline_Enabled ),// 0x08000000, // Used For Flight Paths + STR(Waterwalking ),// 0x10000000, // Prevent Unit From Falling Through Water + STR(Safe_Fall ),// 0x20000000, // Active Rogue Safe Fall Spell (Passive) + STR(Hover ),// 0x40000000 + STR(Unknown13 ),// 0x80000000 + STR(Unk1 ), + STR(Unk2 ), + STR(Unk3 ), + STR(Fullspeedturning ), + STR(Fullspeedpitching ), + STR(Allow_Pitching ), + STR(Unk4 ), + STR(Unk5 ), + STR(Unk6 ), + STR(Unk7 ), + STR(Interp_Move ), + STR(Interp_Turning ), + STR(Interp_Pitching ), + STR(Unk8 ), + STR(Unk9 ), + STR(Unk10 ), + }; + + const char * g_SplineFlag_names[32]= + { + STR(AnimBit1 ),// 0x00000001, + STR(AnimBit2 ),// 0x00000002, + STR(AnimBit3 ),// 0x00000004, + STR(AnimBit4 ),// 0x00000008, + STR(AnimBit5 ),// 0x00000010, + STR(AnimBit6 ),// 0x00000020, + STR(AnimBit7 ),// 0x00000040, + STR(AnimBit8 ),// 0x00000080, + STR(Done ),// 0x00000100, + STR(Falling ),// 0x00000200, // Not Compartible With Trajectory Movement + STR(No_Spline ),// 0x00000400, + STR(Trajectory ),// 0x00000800, // Not Compartible With Fall Movement + STR(Walkmode ),// 0x00001000, + STR(Flying ),// 0x00002000, // Smooth Movement(Catmullrom Interpolation Mode), Flying Animation + STR(Knockback ),// 0x00004000, // Model Orientation Fixed + STR(Final_Point ),// 0x00008000, + STR(Final_Target ),// 0x00010000, + STR(Final_Angle ),// 0x00020000, + STR(Catmullrom ),// 0x00040000, // Used Catmullrom Interpolation Mode + STR(Cyclic ),// 0x00080000, // Movement By Cycled Spline + STR(Enter_Cycle ),// 0x00100000, // Everytime Appears With Cyclic Flag In Monster Move Packet + STR(Animation ),// 0x00200000, // Animationid (0...3), Uint32 Time, Not Compartible With Trajectory And Fall Movement + STR(Unknown4 ),// 0x00400000, // Disables Movement By Path + STR(Unknown5 ),// 0x00800000, + STR(Unknown6 ),// 0x01000000, + STR(Unknown7 ),// 0x02000000, + STR(Unknown8 ),// 0x04000000, + STR(OrientationInversed ),// 0x08000000, // Appears With Runmode Flag, Nodes ),// 1, Handles Orientation + STR(Unknown10 ),// 0x10000000, + STR(Unknown11 ),// 0x20000000, + STR(Unknown12 ),// 0x40000000, + STR(Unknown13 ),// 0x80000000, + }; + + template + void print_flags(Flags t, const char* (&names)[N], std::string& str) + { + for (int i = 0; i < N; ++i) + { + if ((t & (Flags)(1 << i)) && names[i] != NULL) + str.append(" ").append(names[i]); + } + } + + std::string MoveSplineFlag::ToString() const + { + std::string str; + print_flags(raw(),g_SplineFlag_names,str); + return str; + } +} diff --git a/src/server/game/Movement/Spline/Spline.cpp b/src/server/game/Movement/Spline/Spline.cpp new file mode 100644 index 00000000000..14c1bd0c117 --- /dev/null +++ b/src/server/game/Movement/Spline/Spline.cpp @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2005-2011 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Spline.h" +#include +#include + +namespace Movement{ + +SplineBase::EvaluationMethtod SplineBase::evaluators[SplineBase::ModesEnd] = +{ + &SplineBase::EvaluateLinear, + &SplineBase::EvaluateCatmullRom, + &SplineBase::EvaluateBezier3, + (EvaluationMethtod)&SplineBase::UninitializedSpline, +}; + +SplineBase::EvaluationMethtod SplineBase::derivative_evaluators[SplineBase::ModesEnd] = +{ + &SplineBase::EvaluateDerivativeLinear, + &SplineBase::EvaluateDerivativeCatmullRom, + &SplineBase::EvaluateDerivativeBezier3, + (EvaluationMethtod)&SplineBase::UninitializedSpline, +}; + +SplineBase::SegLenghtMethtod SplineBase::seglengths[SplineBase::ModesEnd] = +{ + &SplineBase::SegLengthLinear, + &SplineBase::SegLengthCatmullRom, + &SplineBase::SegLengthBezier3, + (SegLenghtMethtod)&SplineBase::UninitializedSpline, +}; + +SplineBase::InitMethtod SplineBase::initializers[SplineBase::ModesEnd] = +{ + //&SplineBase::InitLinear, + &SplineBase::InitCatmullRom, // we should use catmullrom initializer even for linear mode! (client's internal structure limitation) + &SplineBase::InitCatmullRom, + &SplineBase::InitBezier3, + (InitMethtod)&SplineBase::UninitializedSpline, +}; + +/////////// +#pragma region evaluation methtods + +using G3D::Matrix4; +static const Matrix4 s_catmullRomCoeffs( + -0.5f, 1.5f,-1.5f, 0.5f, + 1.f, -2.5f, 2.f, -0.5f, + -0.5f, 0.f, 0.5f, 0.f, + 0.f, 1.f, 0.f, 0.f); + +static const Matrix4 s_Bezier3Coeffs( + -1.f, 3.f, -3.f, 1.f, + 3.f, -6.f, 3.f, 0.f, + -3.f, 3.f, 0.f, 0.f, + 1.f, 0.f, 0.f, 0.f); + +/* classic view: +inline void C_Evaluate(const Vector3 *vertice, float t, const float (&matrix)[4][4], Vector3 &position) +{ + Vector3 tvec(t*t*t, t*t, t); + int i = 0; + double c; + double x = 0, y = 0, z = 0; + while ( i < 4 ) + { + c = matrix[0][i]*tvec.x + matrix[1][i]*tvec.y + matrix[2][i]*tvec.z + matrix[3][i]; + + x += c * vertice->x; + y += c * vertice->y; + z += c * vertice->z; + + ++i; + ++vertice; + } + + position.x = x; + position.y = y; + position.z = z; +}*/ + +inline void C_Evaluate(const Vector3 *vertice, float t, const Matrix4& matr, Vector3 &result) +{ + Vector4 tvec(t*t*t, t*t, t, 1.f); + Vector4 weights(tvec * matr); + + result = vertice[0] * weights[0] + vertice[1] * weights[1] + + vertice[2] * weights[2] + vertice[3] * weights[3]; +} + +inline void C_Evaluate_Derivative(const Vector3 *vertice, float t, const Matrix4& matr, Vector3 &result) +{ + Vector4 tvec(3.f*t*t, 2.f*t, 1.f, 0.f); + Vector4 weights(tvec * matr); + + result = vertice[0] * weights[0] + vertice[1] * weights[1] + + vertice[2] * weights[2] + vertice[3] * weights[3]; +} + +void SplineBase::EvaluateLinear(index_type index, float u, Vector3& result) const +{ + ASSERT(index >= index_lo && index < index_hi); + result = points[index] + (points[index+1] - points[index]) * u; +} + +void SplineBase::EvaluateCatmullRom( index_type index, float t, Vector3& result) const +{ + ASSERT(index >= index_lo && index < index_hi); + C_Evaluate(&points[index - 1], t, s_catmullRomCoeffs, result); +} + +void SplineBase::EvaluateBezier3(index_type index, float t, Vector3& result) const +{ + index *= 3u; + ASSERT(index >= index_lo && index < index_hi); + C_Evaluate(&points[index], t, s_Bezier3Coeffs, result); +} + +void SplineBase::EvaluateDerivativeLinear(index_type index, float, Vector3& result) const +{ + ASSERT(index >= index_lo && index < index_hi); + result = points[index+1] - points[index]; +} + +void SplineBase::EvaluateDerivativeCatmullRom(index_type index, float t, Vector3& result) const +{ + ASSERT(index >= index_lo && index < index_hi); + C_Evaluate_Derivative(&points[index - 1], t, s_catmullRomCoeffs, result); +} + +void SplineBase::EvaluateDerivativeBezier3(index_type index, float t, Vector3& result) const +{ + index *= 3u; + ASSERT(index >= index_lo && index < index_hi); + C_Evaluate_Derivative(&points[index], t, s_Bezier3Coeffs, result); +} + +float SplineBase::SegLengthLinear(index_type index) const +{ + ASSERT(index >= index_lo && index < index_hi); + return (points[index] - points[index+1]).length(); +} + +float SplineBase::SegLengthCatmullRom( index_type index ) const +{ + ASSERT(index >= index_lo && index < index_hi); + + Vector3 curPos, nextPos; + const Vector3 * p = &points[index - 1]; + curPos = nextPos = p[1]; + + index_type i = 1; + double length = 0; + while (i <= STEPS_PER_SEGMENT) + { + C_Evaluate(p, float(i) / float(STEPS_PER_SEGMENT), s_catmullRomCoeffs, nextPos); + length += (nextPos - curPos).length(); + curPos = nextPos; + ++i; + } + return length; +} + +float SplineBase::SegLengthBezier3(index_type index) const +{ + index *= 3u; + ASSERT(index >= index_lo && index < index_hi); + + Vector3 curPos, nextPos; + const Vector3 * p = &points[index]; + + C_Evaluate(p, 0.f, s_Bezier3Coeffs, nextPos); + curPos = nextPos; + + index_type i = 1; + double length = 0; + while (i <= STEPS_PER_SEGMENT) + { + C_Evaluate(p, float(i) / float(STEPS_PER_SEGMENT), s_Bezier3Coeffs, nextPos); + length += (nextPos - curPos).length(); + curPos = nextPos; + ++i; + } + return length; +} +#pragma endregion + +void SplineBase::init_spline(const Vector3 * controls, index_type count, EvaluationMode m) +{ + m_mode = m; + cyclic = false; + + (this->*initializers[m_mode])(controls, count, cyclic, 0); +} + +void SplineBase::init_cyclic_spline(const Vector3 * controls, index_type count, EvaluationMode m, index_type cyclic_point) +{ + m_mode = m; + cyclic = true; + + (this->*initializers[m_mode])(controls, count, cyclic, cyclic_point); +} + +void SplineBase::InitLinear(const Vector3* controls, index_type count, bool cyclic, index_type cyclic_point) +{ + ASSERT(count >= 2); + const int real_size = count + 1; + + points.resize(real_size); + + memcpy(&points[0],controls, sizeof(Vector3) * count); + + // first and last two indexes are space for special 'virtual points' + // these points are required for proper C_Evaluate and C_Evaluate_Derivative methtod work + if (cyclic) + points[count] = controls[cyclic_point]; + else + points[count] = controls[count-1]; + + index_lo = 0; + index_hi = cyclic ? count : (count - 1); +} + +void SplineBase::InitCatmullRom(const Vector3* controls, index_type count, bool cyclic, index_type cyclic_point) +{ + const int real_size = count + (cyclic ? (1+2) : (1+1)); + + points.resize(real_size); + + int lo_index = 1; + int high_index = lo_index + count - 1; + + memcpy(&points[lo_index],controls, sizeof(Vector3) * count); + + // first and last two indexes are space for special 'virtual points' + // these points are required for proper C_Evaluate and C_Evaluate_Derivative methtod work + if (cyclic) + { + if (cyclic_point == 0) + points[0] = controls[count-1]; + else + points[0] = controls[0].lerp(controls[1], -1); + + points[high_index+1] = controls[cyclic_point]; + points[high_index+2] = controls[cyclic_point+1]; + } + else + { + points[0] = controls[0].lerp(controls[1], -1); + points[high_index+1] = controls[count-1]; + } + + index_lo = lo_index; + index_hi = high_index + (cyclic ? 1 : 0); +} + +void SplineBase::InitBezier3(const Vector3* controls, index_type count, bool /*cyclic*/, index_type /*cyclic_point*/) +{ + index_type c = count / 3u * 3u; + index_type t = c / 3u; + + points.resize(c); + memcpy(&points[0],controls, sizeof(Vector3) * c); + + index_lo = 0; + index_hi = t-1; + //mov_assert(points.size() % 3 == 0); +} + +void SplineBase::clear() +{ + index_lo = 0; + index_hi = 0; + points.clear(); +} + +std::string SplineBase::ToString() const +{ + std::stringstream str; + const char * mode_str[ModesEnd] = {"Linear", "CatmullRom", "Bezier3", "Uninitialized"}; + + index_type count = this->points.size(); + str << "mode: " << mode_str[mode()] << std::endl; + str << "points count: " << count << std::endl; + for (index_type i = 0; i < count; ++i) + str << "point " << i << " : " << points[i].toString() << std::endl; + + return str.str(); +} + +} diff --git a/src/server/game/Movement/Spline/Spline.h b/src/server/game/Movement/Spline/Spline.h new file mode 100644 index 00000000000..28876b220d4 --- /dev/null +++ b/src/server/game/Movement/Spline/Spline.h @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2005-2011 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRINITYSERVER_SPLINE_H +#define TRINITYSERVER_SPLINE_H + +#include "MovementTypedefs.h" +#include + +namespace Movement { + +class SplineBase +{ +public: + typedef int index_type; + typedef std::vector ControlArray; + + enum EvaluationMode + { + ModeLinear, + ModeCatmullrom, + ModeBezier3_Unused, + UninitializedMode, + ModesEnd + }; + + #pragma region fields +protected: + ControlArray points; + + index_type index_lo; + index_type index_hi; + + uint8 m_mode; + bool cyclic; + + enum{ + // could be modified, affects segment length evaluation precision + // lesser value saves more performance in cost of lover precision + // minimal value is 1 + // client's value is 20, blizzs use 2-3 steps to compute length + STEPS_PER_SEGMENT = 3, + }; + static_assert(STEPS_PER_SEGMENT > 0, "shouldn't be lesser than 1"); + +protected: + void EvaluateLinear(index_type, float, Vector3&) const; + void EvaluateCatmullRom(index_type, float, Vector3&) const; + void EvaluateBezier3(index_type, float, Vector3&) const; + typedef void (SplineBase::*EvaluationMethtod)(index_type,float,Vector3&) const; + static EvaluationMethtod evaluators[ModesEnd]; + + void EvaluateDerivativeLinear(index_type, float, Vector3&) const; + void EvaluateDerivativeCatmullRom(index_type, float, Vector3&) const; + void EvaluateDerivativeBezier3(index_type, float, Vector3&) const; + static EvaluationMethtod derivative_evaluators[ModesEnd]; + + float SegLengthLinear(index_type) const; + float SegLengthCatmullRom(index_type) const; + float SegLengthBezier3(index_type) const; + typedef float (SplineBase::*SegLenghtMethtod)(index_type) const; + static SegLenghtMethtod seglengths[ModesEnd]; + + void InitLinear(const Vector3*, index_type, bool, index_type); + void InitCatmullRom(const Vector3*, index_type, bool, index_type); + void InitBezier3(const Vector3*, index_type, bool, index_type); + typedef void (SplineBase::*InitMethtod)(const Vector3*, index_type, bool, index_type); + static InitMethtod initializers[ModesEnd]; + + void UninitializedSpline() const { ASSERT(false);} + + #pragma endregion +public: + + explicit SplineBase() : m_mode(UninitializedMode), index_lo(0), index_hi(0), cyclic(false) {} + + /** Caclulates the position for given segment Idx, and percent of segment length t + @param t - percent of segment length, assumes that t in range [0, 1] + @param Idx - spline segment index, should be in range [first, last) + */ + void evaluate_percent(index_type Idx, float u, Vector3& c) const {(this->*evaluators[m_mode])(Idx,u,c);} + + /** Caclulates derivation in index Idx, and percent of segment length t + @param Idx - spline segment index, should be in range [first, last) + @param t - percent of spline segment length, assumes that t in range [0, 1] + */ + void evaluate_derivative(index_type Idx, float u, Vector3& hermite) const {(this->*derivative_evaluators[m_mode])(Idx,u,hermite);} + + /** Bounds for spline indexes. All indexes should be in range [first, last). */ + index_type first() const { return index_lo;} + index_type last() const { return index_hi;} + + bool empty() const { return index_lo == index_hi;} + EvaluationMode mode() const { return (EvaluationMode)m_mode;} + bool isCyclic() const { return cyclic;} + + const ControlArray& getPoints() const { return points;} + index_type getPointCount() const { return points.size();} + const Vector3& getPoint(index_type i) const { return points[i];} + + /** Initializes spline. Don't call other methods while spline not initialized. */ + void init_spline(const Vector3 * controls, index_type count, EvaluationMode m); + void init_cyclic_spline(const Vector3 * controls, index_type count, EvaluationMode m, index_type cyclic_point); + + /** As i can see there are a lot of ways how spline can be initialized + would be no harm to have some custom initializers. */ + template inline void init_spline(Init& initializer) + { + initializer(m_mode,cyclic,points,index_lo,index_hi); + } + + void clear(); + + /** Calculates distance between [i; i+1] points, assumes that index i is in bounds. */ + float SegLength(index_type i) const { return (this->*seglengths[m_mode])(i);} + + std::string ToString() const; +}; + +template +class Spline : public SplineBase +{ +public: + typedef length_type LengthType; + typedef std::vector LengthArray; + #pragma region fields +protected: + + LengthArray lengths; + + index_type computeIndexInBounds(length_type length) const; + #pragma endregion +public: + + explicit Spline(){} + + /** Calculates the position for given t + @param t - percent of spline's length, assumes that t in range [0, 1]. */ + void evaluate_percent(float t, Vector3 & c) const; + + /** Calculates derivation for given t + @param t - percent of spline's length, assumes that t in range [0, 1]. */ + void evaluate_derivative(float t, Vector3& hermite) const; + + /** Calculates the position for given segment Idx, and percent of segment length t + @param t = partial_segment_length / whole_segment_length + @param Idx - spline segment index, should be in range [first, last). */ + void evaluate_percent(index_type Idx, float u, Vector3& c) const { SplineBase::evaluate_percent(Idx,u,c);} + + /** Caclulates derivation for index Idx, and percent of segment length t + @param Idx - spline segment index, should be in range [first, last) + @param t - percent of spline segment length, assumes that t in range [0, 1]. */ + void evaluate_derivative(index_type Idx, float u, Vector3& c) const { SplineBase::evaluate_derivative(Idx,u,c);} + + // Assumes that t in range [0, 1] + index_type computeIndexInBounds(float t) const; + void computeIndex(float t, index_type& out_idx, float& out_u) const; + + /** Initializes spline. Don't call other methods while spline not initialized. */ + void init_spline(const Vector3 * controls, index_type count, EvaluationMode m) { SplineBase::init_spline(controls,count,m);} + void init_cyclic_spline(const Vector3 * controls, index_type count, EvaluationMode m, index_type cyclic_point) { SplineBase::init_cyclic_spline(controls,count,m,cyclic_point);} + + /** Initializes lengths with SplineBase::SegLength method. */ + void initLengths(); + + /** Initializes lengths in some custom way + Note that value returned by cacher must be greater or equal to previous value. */ + template inline void initLengths(T& cacher) + { + index_type i = index_lo; + lengths.resize(index_hi+1); + length_type prev_length = 0, new_length = 0; + while(i < index_hi) + { + new_length = cacher(*this, i); + lengths[++i] = new_length; + + ASSERT(prev_length <= new_length); + prev_length = new_length; + } + } + + /** Returns length of the whole spline. */ + length_type length() const { return lengths[index_hi];} + /** Returns length between given nodes. */ + length_type length(index_type first, index_type last) const { return lengths[last]-lengths[first];} + length_type length(index_type Idx) const { return lengths[Idx];} + + void set_length(index_type i, length_type length) { lengths[i] = length;} + void clear(); +}; + +} + +#include "SplineImpl.h" + +#endif // TRINITYSERVER_SPLINE_H diff --git a/src/server/game/Movement/Spline/SplineImpl.h b/src/server/game/Movement/Spline/SplineImpl.h new file mode 100644 index 00000000000..eded2d8c903 --- /dev/null +++ b/src/server/game/Movement/Spline/SplineImpl.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2005-2011 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +namespace Movement +{ +template void Spline::evaluate_percent( float t, Vector3 & c ) const +{ + index_type Index; + float u; + computeIndex(t, Index, u); + evaluate_percent(Index, u, c); +} + +template void Spline::evaluate_derivative(float t, Vector3& hermite) const +{ + index_type Index; + float u; + computeIndex(t, Index, u); + evaluate_derivative(Index, u, hermite); +} + +template SplineBase::index_type Spline::computeIndexInBounds(length_type length_) const +{ +// Temporary disabled: causes infinite loop with t = 1.f +/* + index_type hi = index_hi; + index_type lo = index_lo; + + index_type i = lo + (float)(hi - lo) * t; + + while ((lengths[i] > length) || (lengths[i + 1] <= length)) + { + if (lengths[i] > length) + hi = i - 1; // too big + else if (lengths[i + 1] <= length) + lo = i + 1; // too small + + i = (hi + lo) / 2; + }*/ + + index_type i = index_lo; + index_type N = index_hi; + while (i+1 < N && lengths[i+1] < length_) + ++i; + + return i; +} + +template void Spline::computeIndex(float t, index_type& index, float& u) const +{ + ASSERT(t >= 0.f && t <= 1.f); + length_type length_ = t * length(); + index = computeIndexInBounds(length_); + ASSERT(index < index_hi); + u = (length_ - length(index)) / (float)length(index, index+1); +} + +template SplineBase::index_type Spline::computeIndexInBounds( float t ) const +{ + ASSERT(t >= 0.f && t <= 1.f); + return computeIndexInBounds(t * length()); +} + +template void Spline::initLengths() +{ + index_type i = index_lo; + length_type length = 0; + lengths.resize(index_hi+1); + while(i < index_hi ) + { + length += SegLength(i); + lengths[++i] = length; + } +} + +template void Spline::clear() +{ + SplineBase::clear(); + lengths.clear(); +} + +} diff --git a/src/server/game/Movement/Traveller.h b/src/server/game/Movement/Traveller.h deleted file mode 100755 index 641278ee37a..00000000000 --- a/src/server/game/Movement/Traveller.h +++ /dev/null @@ -1,152 +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 TRINITY_TRAVELLER_H -#define TRINITY_TRAVELLER_H - -#include "Creature.h" -#include "Player.h" -#include - -/** Traveller is a wrapper for units (creatures or players) that - * travel from point A to point B using the destination holder. - */ -#define PLAYER_FLIGHT_SPEED 32.0f - -template -struct Traveller -{ - T &i_traveller; - Traveller(T &t) : i_traveller(t) {} - Traveller(const Traveller &obj) : i_traveller(obj) {} - Traveller& operator=(const Traveller &obj) - { - this.i_traveller = obj.i_traveller; - return *this; - } - - operator T&(void) { return i_traveller; } - operator const T&(void) { return i_traveller; } - float GetPositionX() const { return i_traveller.GetPositionX(); } - float GetPositionY() const { return i_traveller.GetPositionY(); } - float GetPositionZ() const { return i_traveller.GetPositionZ(); } - T& GetTraveller(void) { return i_traveller; } - - float Speed(void) { ASSERT(false); return 0.0f; } - float GetMoveDestinationTo(float x, float y, float z); - uint32 GetTotalTrevelTimeTo(float x, float y, float z); - - void Relocation(float x, float y, float z, float orientation) {} - void Relocation(float x, float y, float z) { Relocation(x, y, z, i_traveller.GetOrientation()); } - void MoveTo(float x, float y, float z, uint32 t) {} -}; - -template -inline uint32 Traveller::GetTotalTrevelTimeTo(float x, float y, float z) -{ - float dist = GetMoveDestinationTo(x, y, z); - float speed = Speed(); - if (speed < 0.0f) - return 0xfffffffe; // almost infinity-unit should stop - else - speed *= 0.001f; // speed is in seconds so convert from second to millisecond - return static_cast(dist/speed); -} - -// specialization for creatures -template<> -inline float Traveller::Speed() -{ - if (i_traveller.HasUnitState(UNIT_STAT_CHARGING)) - return i_traveller.m_TempSpeed; - else if (i_traveller.HasUnitMovementFlag(MOVEMENTFLAG_WALKING)) - return i_traveller.GetSpeed(MOVE_WALK); - else if (i_traveller.HasUnitMovementFlag(MOVEMENTFLAG_FLYING)) - return i_traveller.GetSpeed(MOVE_FLIGHT); - else - return i_traveller.GetSpeed(MOVE_RUN); -} - -template<> -inline void Traveller::Relocation(float x, float y, float z, float orientation) -{ - i_traveller.UpdatePosition(x, y, z, orientation); -} - -template<> -inline float Traveller::GetMoveDestinationTo(float x, float y, float z) -{ - float dx = x - GetPositionX(); - float dy = y - GetPositionY(); - float dz = z - GetPositionZ(); - - //if (i_traveller.HasUnitMovementFlag(MOVEMENTFLAG_FLYING)) - return sqrt((dx*dx) + (dy*dy) + (dz*dz)); - //else //Walking on the ground - // return sqrt((dx*dx) + (dy*dy)); -} - -template<> -inline void Traveller::MoveTo(float x, float y, float z, uint32 t) -{ - //i_traveller.AI_SendMoveToPacket(x, y, z, t, i_traveller.GetUnitMovementFlags(), 0); - i_traveller.SendMonsterMove(x, y, z, t); -} - -// specialization for players -template<> -inline float Traveller::Speed() -{ - if (i_traveller.HasUnitState(UNIT_STAT_CHARGING)) - return i_traveller.m_TempSpeed; - else if (i_traveller.isInFlight()) - return PLAYER_FLIGHT_SPEED; - else - return i_traveller.GetSpeed(i_traveller.m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING) ? MOVE_WALK : MOVE_RUN); -} - -template<> -inline float Traveller::GetMoveDestinationTo(float x, float y, float z) -{ - float dx = x - GetPositionX(); - float dy = y - GetPositionY(); - float dz = z - GetPositionZ(); - - //if (i_traveller.isInFlight()) - return sqrt((dx*dx) + (dy*dy) + (dz*dz)); - //else //Walking on the ground - // return sqrt((dx*dx) + (dy*dy)); -} - -template<> -inline void Traveller::Relocation(float x, float y, float z, float orientation) -{ - i_traveller.UpdatePosition(x, y, z, orientation); -} - -template<> -inline void Traveller::MoveTo(float x, float y, float z, uint32 t) -{ - //Only send MOVEMENTFLAG_WALKING, client has strange issues with other move flags - i_traveller.SendMonsterMove(x, y, z, t); -} - -typedef Traveller CreatureTraveller; -typedef Traveller PlayerTraveller; -#endif - diff --git a/src/server/game/Scripting/MapScripts.cpp b/src/server/game/Scripting/MapScripts.cpp index 71195538256..7757e1a1a35 100755 --- a/src/server/game/Scripting/MapScripts.cpp +++ b/src/server/game/Scripting/MapScripts.cpp @@ -475,8 +475,14 @@ void Map::ScriptsProcess() // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { - cSource->SendMonsterMoveWithSpeed(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, step.script->MoveTo.TravelTime); - cSource->GetMap()->CreatureRelocation(cSource, step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, 0); + Unit * unit = (Unit*)cSource; + if (step.script->MoveTo.TravelTime != 0) + { + float speed = unit->GetDistance(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ) / ((float)step.script->MoveTo.TravelTime * 0.001f); + unit->MonsterMoveWithSpeed(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, speed); + } + else + unit->NearTeleportTo(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, unit->GetOrientation()); } break; diff --git a/src/server/game/Server/Protocol/Handlers/TaxiHandler.cpp b/src/server/game/Server/Protocol/Handlers/TaxiHandler.cpp index 81481bdef31..3533b153bd8 100755 --- a/src/server/game/Server/Protocol/Handlers/TaxiHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/TaxiHandler.cpp @@ -27,7 +27,6 @@ #include "UpdateMask.h" #include "Path.h" #include "WaypointMovementGenerator.h" -#include "DestinationHolderImp.h" void WorldSession::HandleTaxiNodeStatusQueryOpcode(WorldPacket & recv_data) { diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 1d3c657f50a..535253f4e13 100755 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -4761,11 +4761,7 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool break; case 46361: // Reinforced Net if (caster) - { - float currentGroundLevel = target->GetBaseMap()->GetHeight(target->GetPositionX(), target->GetPositionY(), MAX_HEIGHT); - if (target->GetPositionZ() > currentGroundLevel) - target->GetMotionMaster()->MoveFall(currentGroundLevel); - } + target->GetMotionMaster()->MoveFall(); break; case 46699: // Requires No Ammo if (target->GetTypeId() == TYPEID_PLAYER) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 2c33488f76c..eaf5f4e1d31 100755 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -3363,22 +3363,11 @@ void Spell::EffectDistract(SpellEffIndex /*effIndex*/) if (unitTarget->HasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING)) return; - float angle = unitTarget->GetAngle(m_targets.GetDst()); + unitTarget->SetFacingTo(unitTarget->GetAngle(m_targets.GetDst())); + unitTarget->ClearUnitState(UNIT_STAT_MOVING); - if (unitTarget->GetTypeId() == TYPEID_PLAYER) - { - // For players just turn them - unitTarget->ToPlayer()->UpdatePosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false); - unitTarget->ToPlayer()->SendTeleportAckPacket(); - } - else - { - // Set creature Distracted, Stop it, And turn it - unitTarget->SetOrientation(angle); - unitTarget->StopMoving(); + if (unitTarget->GetTypeId() == TYPEID_UNIT) unitTarget->GetMotionMaster()->MoveDistract(damage * IN_MILLISECONDS); - unitTarget->SendMovementFlagUpdate(); - } } void Spell::EffectPickPocket(SpellEffIndex /*effIndex*/) diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 54dac404f03..1b6a6c6fdcf 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -1036,15 +1036,14 @@ public: } if (/*creature->GetMotionMaster()->empty() ||*/ - creature->GetMotionMaster()->GetCurrentMovementGeneratorType () != TARGETED_MOTION_TYPE) + creature->GetMotionMaster()->GetCurrentMovementGeneratorType () != FOLLOW_MOTION_TYPE) { handler->PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU, creature->GetName()); handler->SetSentErrorMessage(true); return false; } - TargetedMovementGenerator const* mgen - = static_cast const*>((creature->GetMotionMaster()->top())); + FollowMovementGenerator const* mgen = static_cast const*>((creature->GetMotionMaster()->top())); if (mgen->GetTarget() != player) { diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp index 999f3fda2e4..a7d1c3ad8ba 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp @@ -1009,7 +1009,7 @@ public: me->SetInFront(car); me->SendMovementFlagUpdate(); car->Relocate(car->GetPositionX(), car->GetPositionY(), me->GetPositionZ() + 1); - car->SendMonsterStop(); + car->StopMoving(); car->RemoveAura(SPELL_CART_DRAG); } me->MonsterSay(SAY_SCARLET_MINER2, LANG_UNIVERSAL, 0); diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp index d04d7af5c80..eee6b08d834 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp @@ -325,7 +325,7 @@ class boss_akilzon : public CreatureScript if (target) { target->SetUnitMovementFlags(MOVEMENTFLAG_LEVITATING); - target->SendMonsterMove(x, y, me->GetPositionZ()+15, 0); + target->MonsterMoveWithSpeed(x, y, me->GetPositionZ()+15, 0); } Unit* Cloud = me->SummonTrigger(x, y, me->GetPositionZ()+16, 0, 15000); if (Cloud) diff --git a/src/server/scripts/EasternKingdoms/undercity.cpp b/src/server/scripts/EasternKingdoms/undercity.cpp index f1c0fba2e29..fe9c40e6dbd 100644 --- a/src/server/scripts/EasternKingdoms/undercity.cpp +++ b/src/server/scripts/EasternKingdoms/undercity.cpp @@ -109,7 +109,7 @@ public: { if (Creature* target = Unit::GetCreature(*summoned, targetGUID)) { - target->SendMonsterMove(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ()+15.0f, 0); + target->MonsterMoveWithSpeed(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ()+15.0f, 0); target->SetPosition(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ()+15.0f, 0.0f); summoned->CastSpell(target, SPELL_RIBBON_OF_SOULS, false); } @@ -186,7 +186,7 @@ public: if (EventMove_Timer <= diff) { me->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); - me->SendMonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), HIGHBORNE_LOC_Y_NEW, 5000); + me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), HIGHBORNE_LOC_Y_NEW, me->GetDistance(me->GetPositionX(), me->GetPositionY(), HIGHBORNE_LOC_Y_NEW) / (5000 * 0.001f)); me->SetPosition(me->GetPositionX(), me->GetPositionY(), HIGHBORNE_LOC_Y_NEW, me->GetOrientation()); EventMove = false; } else EventMove_Timer -= diff; diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp index bc6145252d2..8e34a318d6c 100755 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp @@ -592,11 +592,8 @@ public: me->GetMotionMaster()->MoveIdle(); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); //At hit the ground - me->GetPosition(x, y, z); - z = me->GetMap()->GetHeight(x, y, z, true, 50); me->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH); - me->GetMotionMaster()->MoveFall(z, 0); - //me->FallGround(); //need correct vmap use (i believe it isn't working properly right now) + me->GetMotionMaster()->MoveFall(); } } } @@ -610,7 +607,6 @@ public: case 0: me->RemoveAurasDueToSpell(SPELL_FROST_SPHERE); me->SetDisplayId(11686); - me->Relocate(x, y, z, me->GetOrientation()); DoCast(SPELL_PERMAFROST_VISUAL); DoCast(SPELL_PERMAFROST); me->SetFloatValue(OBJECT_FIELD_SCALE_X, 2.0f); diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp index bc06a92ef07..d444160b8f2 100644 --- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp @@ -201,7 +201,7 @@ class mob_corrupted_soul_fragment : public CreatureScript void MovementInform(uint32 type, uint32 id) { - if (type != TARGETED_MOTION_TYPE) + if (type != CHASE_MOTION_TYPE) return; if (instance) diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp index 3b15bba5c5d..94a3da2672b 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp @@ -1159,7 +1159,7 @@ class npc_ball_of_flame : public CreatureScript void MovementInform(uint32 type, uint32 id) { - if (type == TARGETED_MOTION_TYPE && id == GUID_LOPART(_chaseGUID) && _chaseGUID) + if (type == CHASE_MOTION_TYPE && id == GUID_LOPART(_chaseGUID) && _chaseGUID) { me->RemoveAurasDueToSpell(SPELL_BALL_OF_FLAMES_PERIODIC); DoCast(me, SPELL_FLAMES); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp index 8396b6e6c85..31b3786a360 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp @@ -608,7 +608,7 @@ class npc_high_overlord_saurfang_icc : public CreatureScript me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); me->SendMovementFlagUpdate(); me->Relocate(me->GetPositionX(), me->GetPositionY(), 539.2917f); - me->SendMonsterMove(me->GetPositionX(), me->GetPositionY(), 539.2917f, SPLINEFLAG_FALLING, 0, 0.0f); + me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), 539.2917f, 0.0f); for (std::list::iterator itr = _guardList.begin(); itr != _guardList.end(); ++itr) (*itr)->AI()->DoAction(ACTION_DESPAWN); break; @@ -815,7 +815,7 @@ class npc_muradin_bronzebeard_icc : public CreatureScript me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); me->SendMovementFlagUpdate(); me->Relocate(me->GetPositionX(), me->GetPositionY(), 539.2917f); - me->SendMonsterMove(me->GetPositionX(), me->GetPositionY(), 539.2917f, SPLINEFLAG_FALLING, 0, 0.0f); + me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), 539.2917f, 0.0f); for (std::list::iterator itr = _guardList.begin(); itr != _guardList.end(); ++itr) (*itr)->AI()->DoAction(ACTION_DESPAWN); break; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp index f2657e5b2ef..5029dbcceee 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -508,7 +508,7 @@ class boss_the_lich_king : public CreatureScript if (fabs(ground_Z - z) < 0.1f) return; - me->GetMotionMaster()->MoveFall(ground_Z); + me->GetMotionMaster()->MoveFall(); } void EnterCombat(Unit* target) @@ -801,7 +801,7 @@ class boss_the_lich_king : public CreatureScript events.ScheduleEvent(EVENT_INTRO_TALK_1, 9000, 0, PHASE_INTRO); break; case POINT_CENTER_1: - me->SetFacing(0.0f); + me->SetFacingTo(0.0f); Talk(SAY_LK_REMORSELESS_WINTER); SendMusicToPlayers(MUSIC_SPECIAL); me->SetReactState(REACT_PASSIVE); @@ -818,7 +818,7 @@ class boss_the_lich_king : public CreatureScript events.ScheduleEvent(EVENT_SOUL_REAPER, 94000, 0, PHASE_TWO); break; case POINT_CENTER_2: - me->SetFacing(0.0f); + me->SetFacingTo(0.0f); Talk(SAY_LK_REMORSELESS_WINTER); SendMusicToPlayers(MUSIC_SPECIAL); me->SetReactState(REACT_PASSIVE); @@ -1047,14 +1047,14 @@ class boss_the_lich_king : public CreatureScript break; case EVENT_OUTRO_TALK_3: if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING))) - me->SetFacing(0.0f, tirion); + me->SetFacingToObject(tirion); Talk(SAY_LK_OUTRO_3); break; case EVENT_OUTRO_MOVE_CENTER: me->GetMotionMaster()->MovePoint(POINT_LK_OUTRO_1, CenterPosition); break; case EVENT_OUTRO_TALK_4: - me->SetFacing(0.01745329f); + me->SetFacingTo(0.01745329f); Talk(SAY_LK_OUTRO_4); break; case EVENT_OUTRO_RAISE_DEAD: @@ -1070,7 +1070,7 @@ class boss_the_lich_king : public CreatureScript case EVENT_OUTRO_TALK_6: Talk(SAY_LK_OUTRO_6); if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HIGHLORD_TIRION_FORDRING))) - tirion->SetFacing(0.0f, me); + tirion->SetFacingToObject(me); me->ClearUnitState(UNIT_STAT_CASTING); DoCastAOE(SPELL_SUMMON_BROKEN_FROSTMOURNE_3); SetEquipmentSlots(false, EQUIP_UNEQUIP); @@ -1222,7 +1222,7 @@ class npc_tirion_fordring_tft : public CreatureScript void SpellHit(Unit* /*caster*/, SpellInfo const* spell) { if (spell->Id == SPELL_ICE_LOCK) - me->SetFacing(3.085098f); + me->SetFacingTo(3.085098f); else if (spell->Id == SPELL_BROKEN_FROSTMOURNE_KNOCK) SetEquipmentSlots(true); // remove glow on ashbringer } @@ -1285,7 +1285,7 @@ class npc_tirion_fordring_tft : public CreatureScript SetEquipmentSlots(false, EQUIP_ASHBRINGER_GLOWING); if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) { - me->SetFacing(0.0f, lichKing); + me->SetFacingToObject(lichKing); lichKing->AI()->DoAction(ACTION_PLAY_MUSIC); } break; @@ -1621,7 +1621,7 @@ class npc_strangulate_vehicle : public CreatureScript void IsSummonedBy(Unit* summoner) { - me->SetFacing(0.0f, summoner); + me->SetFacingToObject(summoner); DoCast(summoner, SPELL_HARVEST_SOUL_VEHICLE); _events.Reset(); _events.ScheduleEvent(EVENT_MOVE_TO_LICH_KING, 2000); @@ -1789,7 +1789,7 @@ class npc_terenas_menethil : public CreatureScript _events.Reset(); _events.SetPhase(PHASE_OUTRO); if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_THE_LICH_KING))) - me->SetFacing(0.0f, lichKing); + me->SetFacingToObject(lichKing); _events.ScheduleEvent(EVENT_OUTRO_TERENAS_TALK_1, 2000, 0, PHASE_OUTRO); _events.ScheduleEvent(EVENT_OUTRO_TERENAS_TALK_2, 14000, 0, PHASE_OUTRO); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index ab3046806db..6bd8f3cba7d 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -1264,7 +1264,7 @@ struct npc_argent_captainAI : public ScriptedAI void EnterEvadeMode() { // not yet following - if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_IDLE) != TARGETED_MOTION_TYPE || IsUndead) + if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_IDLE) != CHASE_MOTION_TYPE || IsUndead) { ScriptedAI::EnterEvadeMode(); return; diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp index 8e995a9b260..052fa3ba4a5 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp @@ -838,7 +838,7 @@ public: return; } - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE) + if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE) me->GetMotionMaster()->MoveFollow(malygos, 0.0f, 0.0f); } } diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp index 194c2a36862..1fc724c8b6c 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp @@ -243,7 +243,7 @@ public: { if (m_uiPause_Timer <= uiDiff) { - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE) + if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE) if (me->getVictim()) me->GetMotionMaster()->MoveChase(me->getVictim()); @@ -421,7 +421,7 @@ public: // me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); //Set in DB if (me->IsNonMeleeSpellCasted(false)) me->InterruptNonMeleeSpells(false); - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE) + if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) me->GetMotionMaster()->MovementExpired(); m_bIsFrozen = true; } diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_krystallus.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_krystallus.cpp index 4ee71367b55..d1aba800094 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_krystallus.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_krystallus.cpp @@ -174,7 +174,7 @@ public: bIsSlam = false; //and correct movement, if not already - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE) + if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE) { if (me->getVictim()) me->GetMotionMaster()->MoveChase(me->getVictim()); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp index 68435fffb1b..2c7532fcf70 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp @@ -634,7 +634,7 @@ class boss_stormcaller_brundir : public CreatureScript // Prevent to have Brundir somewhere in the air when he die in Air phase if (me->GetPositionZ() > FLOOR_Z) - me->GetMotionMaster()->MoveFall(FLOOR_Z); + me->GetMotionMaster()->MoveFall(); } void KilledUnit(Unit* /*who*/) diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp index 1bedd7e19e9..d5cd79b25f1 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp @@ -288,7 +288,7 @@ public: me->Dismount(); if (Creature* pGrauf = me->SummonCreature(CREATURE_GRAUF, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3*IN_MILLISECONDS)) { - pGrauf->GetMotionMaster()->MoveFall(0); + pGrauf->GetMotionMaster()->MoveFall(); pGrauf->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH); } me->GetMotionMaster()->MoveJump(Location[4].GetPositionX(), Location[4].GetPositionY(), Location[4].GetPositionZ(), 5.0f, 10.0f); diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp index 9cab1de197c..436336ec5b8 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp @@ -249,22 +249,16 @@ public: if (Phase == SACRIFICING) SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); - me->GetPosition(x, y, z); - z = me->GetMap()->GetHeight(x, y, z, true, 50); + damage = 0; + Phase = SVALADEAD; + me->InterruptNonMeleeSpells(true); + me->RemoveAllAuras(); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->SetHealth(1); - if (me->GetPositionZ() > z) - { - damage = 0; - Phase = SVALADEAD; - me->InterruptNonMeleeSpells(true); - me->RemoveAllAuras(); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - me->SetHealth(1); - - SetCombatMovement(false); - me->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH); - me->GetMotionMaster()->MoveFall(z, 1); - } + SetCombatMovement(false); + me->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH); + me->GetMotionMaster()->MoveFall(); } } @@ -274,10 +268,7 @@ public: return; if (pointId == 1) - { - me->Relocate(x, y, z, me->GetOrientation()); me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } } void JustDied(Unit* killer) diff --git a/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_nexusprince_shaffar.cpp b/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_nexusprince_shaffar.cpp index 81211b6e3d9..aa63f1adf18 100644 --- a/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_nexusprince_shaffar.cpp +++ b/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_nexusprince_shaffar.cpp @@ -187,7 +187,7 @@ public: //expire movement, will prevent from running right back to victim after cast //(but should MoveChase be used again at a certain time or should he not move?) - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE) + if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) me->GetMotionMaster()->MovementExpired(); DoCast(me, SPELL_BLINK); diff --git a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp index b23b7bcd1ac..c17b6d5baf3 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp @@ -1982,7 +1982,7 @@ void boss_illidan_stormrage::boss_illidan_stormrageAI::HandleTalkSequence() Akama->GetMotionMaster()->Clear(false); // Akama->GetMotionMaster()->MoveIdle(); Akama->SetPosition(x, y, z, 0.0f); - Akama->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_NONE, 0); // Illidan must not die until Akama arrives. + Akama->MonsterMoveWithSpeed(x, y, z, 0); // Illidan must not die until Akama arrives. Akama->GetMotionMaster()->MoveChase(me); } diff --git a/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp b/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp index 33196b1213a..b7604c41794 100644 --- a/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp +++ b/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp @@ -151,7 +151,7 @@ public: m_bPerformingGroundSlam = false; //and correct movement, if not already - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE) + if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE) { if (me->getVictim()) me->GetMotionMaster()->MoveChase(me->getVictim()); diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp index 974d81ef914..a45576f8884 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp @@ -820,7 +820,7 @@ class boss_kaelthas : public CreatureScript me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveIdle(); me->SetPosition(afGravityPos[0], afGravityPos[1], afGravityPos[2], 0); - me->SendMonsterMove(afGravityPos[0], afGravityPos[1], afGravityPos[2], 0, 0, 0); + me->MonsterMoveWithSpeed(afGravityPos[0], afGravityPos[1], afGravityPos[2], 1); me->InterruptNonMeleeSpells(false); DoCast(me, SPELL_FULLPOWER); @@ -887,7 +887,7 @@ class boss_kaelthas : public CreatureScript me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveIdle(); me->SetPosition(afGravityPos[0], afGravityPos[1], afGravityPos[2], 0); - me->SendMonsterMove(afGravityPos[0], afGravityPos[1], afGravityPos[2], 0, MOVEMENTFLAG_NONE, 0); + me->MonsterMoveWithSpeed(afGravityPos[0], afGravityPos[1], afGravityPos[2], 0); // 1) Kael'thas will portal the whole raid right into his body for (i = me->getThreatManager().getThreatList().begin(); i!= me->getThreatManager().getThreatList().end(); ++i) diff --git a/src/server/scripts/World/guards.cpp b/src/server/scripts/World/guards.cpp index d562542a7d7..9bc511931b9 100644 --- a/src/server/scripts/World/guards.cpp +++ b/src/server/scripts/World/guards.cpp @@ -179,7 +179,7 @@ public: globalCooldown = GENERIC_CREATURE_COOLDOWN; } //If no spells available and we arn't moving run to target - else if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE) + else if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE) { //Cancel our current spell and then mutate new movement generator me->InterruptNonMeleeSpells(false); diff --git a/src/server/shared/Utilities/Timer.h b/src/server/shared/Utilities/Timer.h index 4dae8ac30d2..4d3f02f6688 100755 --- a/src/server/shared/Utilities/Timer.h +++ b/src/server/shared/Utilities/Timer.h @@ -133,7 +133,7 @@ struct TimeTrackerSmall { public: - TimeTrackerSmall(uint32 expiry) + TimeTrackerSmall(uint32 expiry = 0) : i_expiryTime(expiry) { } -- cgit v1.2.3 From f4075f0f945c842fe2b1a08ea4a7fa253e8e2e53 Mon Sep 17 00:00:00 2001 From: Subv2112 Date: Sat, 14 Jan 2012 17:37:28 +0100 Subject: Core/LFG: Fix priority of the player when its added to the lfg group Better implementation of the Dungeon Deserter debuff Rewrite the NeedBeforeGreed loot Fixed players being shown as Unknown Entity when entering the lfg group Some incremental optimizations after original patch Thanks to Retriman and Paecman for base implementation Signed-off-by: Machiavelli --- .../2012_01_14_00_characters_lfg_data.sql | 8 ++ src/server/game/DungeonFinding/LFGMgr.cpp | 115 +++++++++++++++++++- src/server/game/DungeonFinding/LFGMgr.h | 8 +- src/server/game/Entities/Player/Player.cpp | 96 +++++++++++++++- src/server/game/Entities/Player/Player.h | 1 + src/server/game/Groups/Group.cpp | 121 +++++++++++++++------ src/server/game/Groups/Group.h | 3 +- src/server/game/Groups/GroupMgr.cpp | 8 +- src/server/game/Groups/GroupReference.cpp | 4 +- .../Server/Protocol/Handlers/CharacterHandler.cpp | 14 ++- .../game/Server/Protocol/Handlers/LFGHandler.cpp | 3 +- src/server/scripts/Spells/spell_generic.cpp | 12 +- .../Database/Implementation/CharacterDatabase.cpp | 4 + .../Database/Implementation/CharacterDatabase.h | 3 + 14 files changed, 347 insertions(+), 53 deletions(-) create mode 100644 sql/updates/characters/2012_01_14_00_characters_lfg_data.sql (limited to 'src/server/scripts') diff --git a/sql/updates/characters/2012_01_14_00_characters_lfg_data.sql b/sql/updates/characters/2012_01_14_00_characters_lfg_data.sql new file mode 100644 index 00000000000..3c6671a3914 --- /dev/null +++ b/sql/updates/characters/2012_01_14_00_characters_lfg_data.sql @@ -0,0 +1,8 @@ +DROP TABLE IF EXISTS `lfg_data`; + +CREATE TABLE `lfg_data` ( + `guid` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier', + `dungeon` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `state` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`guid`) +) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='LFG Data'; diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index e0a16d4868b..0f146598a6e 100755 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -72,6 +72,54 @@ LFGMgr::~LFGMgr() delete it->second; } +void LFGMgr::_LoadFromDB(Field* fields, uint64 guid) +{ + if (!fields) + return; + + if (!IS_GROUP(guid)) + return; + + uint32 dungeon = fields[16].GetUInt32(); + + uint8 state = fields[17].GetUInt8(); + + if (!dungeon || !state) + return; + + SetDungeon(guid, dungeon); + + switch (state) + { + case LFG_STATE_DUNGEON: + case LFG_STATE_FINISHED_DUNGEON: + SetState(guid, (LfgState)state); + break; + default: + break; + } +} + +void LFGMgr::_SaveToDB(uint64 guid, uint32 db_guid) +{ + if (!IS_GROUP(guid)) + return; + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_LFG_DATA); + + stmt->setUInt32(0, db_guid); + + CharacterDatabase.Execute(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_LFG_DATA); + stmt->setUInt32(0, db_guid); + + stmt->setUInt32(1, GetDungeon(guid)); + stmt->setUInt32(2, GetState(guid)); + + CharacterDatabase.Execute(stmt); +} + /// Load rewards for completing dungeons void LFGMgr::LoadRewards() { @@ -245,7 +293,8 @@ void LFGMgr::Update(uint32 diff) UpdateProposal(m_lfgProposalId, guid, true); } else - currentQueue.push_back(frontguid); // Lfg group not found, add this group to the queue. + if (std::find(currentQueue.begin(), currentQueue.end(), frontguid) == currentQueue.end()) //already in queue? + currentQueue.push_back(frontguid); // Lfg group not found, add this group to the queue. firstNew.clear(); } } @@ -382,7 +431,10 @@ void LFGMgr::InitializeLockedDungeons(Player* player) else if (DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, dungeon->map, player)) locktype = LFG_LOCKSTATUS_RAID_LOCKED; else if (dungeon->difficulty > DUNGEON_DIFFICULTY_NORMAL && player->GetBoundInstance(dungeon->map, Difficulty(dungeon->difficulty))) - locktype = LFG_LOCKSTATUS_RAID_LOCKED; + { + if (!player->GetGroup() || !player->GetGroup()->isLFGGroup() || GetDungeon(player->GetGroup()->GetGUID(), true) != dungeon->ID || GetState(player->GetGroup()->GetGUID()) != LFG_STATE_DUNGEON) + locktype = LFG_LOCKSTATUS_RAID_LOCKED; + } else if (dungeon->minlevel > level) locktype = LFG_LOCKSTATUS_TOO_LOW_LEVEL; else if (dungeon->maxlevel < level) @@ -808,7 +860,7 @@ bool LFGMgr::CheckCompatibility(LfgGuidList check, LfgProposal*& pProposal) { uint64 guid = (*it); LfgQueueInfoMap::iterator itQueue = m_QueueInfoMap.find(guid); - if (itQueue == m_QueueInfoMap.end()) + if (itQueue == m_QueueInfoMap.end() || GetState(guid) != LFG_STATE_QUEUED) { sLog->outError("LFGMgr::CheckCompatibility: [" UI64FMTD "] is not queued but listed as queued!", (*it)); RemoveFromQueue(guid); @@ -923,6 +975,42 @@ bool LFGMgr::CheckCompatibility(LfgGuidList check, LfgProposal*& pProposal) if (numPlayers != MAXGROUPSIZE) { sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) Compatibles but not match. Players(%u)", strGuids.c_str(), numPlayers); + uint8 Tanks_Needed = LFG_TANKS_NEEDED; + uint8 Healers_Needed = LFG_HEALERS_NEEDED; + uint8 Dps_Needed = LFG_DPS_NEEDED; + for (LfgQueueInfoMap::const_iterator itQueue = pqInfoMap.begin(); itQueue != pqInfoMap.end(); ++itQueue) + { + LfgQueueInfo* queue = itQueue->second; + for (LfgRolesMap::const_iterator itPlayer = queue->roles.begin(); itPlayer != queue->roles.end(); ++itPlayer) + { + uint8 roles = itPlayer->second; + if ((roles & ROLE_TANK) && Tanks_Needed > 0) + --Tanks_Needed; + else if ((roles & ROLE_HEALER) && Healers_Needed > 0) + --Healers_Needed; + else if ((roles & ROLE_DAMAGE) && Dps_Needed > 0) + --Dps_Needed; + } + } + for (PlayerSet::const_iterator itPlayers = players.begin(); itPlayers != players.end(); ++itPlayers) + { + for (LfgQueueInfoMap::const_iterator itQueue = pqInfoMap.begin(); itQueue != pqInfoMap.end(); ++itQueue) + { + LfgQueueInfo* queue = itQueue->second; + if (!queue) + continue; + + for (LfgRolesMap::const_iterator itPlayer = queue->roles.begin(); itPlayer != queue->roles.end(); ++itPlayer) + { + if (*itPlayers == ObjectAccessor::FindPlayer(itPlayer->first)) + { + queue->tanks = Tanks_Needed; + queue->healers = Healers_Needed; + queue->dps = Dps_Needed; + } + } + } + } return true; } sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) MATCH! Group formed", strGuids.c_str()); @@ -1078,6 +1166,11 @@ void LFGMgr::UpdateRoleCheck(uint64 gguid, uint64 guid /* = 0 */, uint8 roles /* } m_QueueInfoMap[gguid] = pqInfo; + if(GetState(gguid) != LFG_STATE_NONE) + { + LfgGuidList& currentQueue = m_currentQueue[team]; + currentQueue.push_front(gguid); + } AddToQueue(gguid, team); } @@ -1384,6 +1477,7 @@ void LFGMgr::UpdateProposal(uint32 proposalId, uint64 guid, bool accept) break; } } + m_teleport.push_back(pguid); grp->SetLfgRoles(pguid, pProposal->players[pguid]->role); SetState(pguid, LFG_STATE_DUNGEON); } @@ -1395,6 +1489,7 @@ void LFGMgr::UpdateProposal(uint32 proposalId, uint64 guid, bool accept) uint64 gguid = grp->GetGUID(); SetDungeon(gguid, dungeon->Entry()); SetState(gguid, LFG_STATE_DUNGEON); + _SaveToDB(gguid, grp->GetDbStoreId()); // Remove players/groups from Queue for (LfgGuidList::const_iterator it = pProposal->queues.begin(); it != pProposal->queues.end(); ++it) @@ -1509,7 +1604,9 @@ void LFGMgr::RemoveProposal(LfgProposalMap::iterator itProposal, LfgUpdateType t for (LfgGuidList::const_iterator it = pProposal->queues.begin(); it != pProposal->queues.end(); ++it) { uint64 guid = *it; - AddToQueue(guid, team); + LfgGuidList& currentQueue = m_currentQueue[team]; + currentQueue.push_front(guid); //Add GUID for high priority + AddToQueue(guid, team); //We have to add each GUID in newQueue to check for a new groups } delete pProposal; @@ -1921,6 +2018,16 @@ const std::string& LFGMgr::GetComment(uint64 guid) return m_Players[guid].GetComment(); } +bool LFGMgr::IsTeleported(uint64 pguid) +{ + if (std::find(m_teleport.begin(), m_teleport.end(), pguid) != m_teleport.end()) + { + m_teleport.remove(pguid); + return true; + } + return false; +} + const LfgDungeonSet& LFGMgr::GetSelectedDungeons(uint64 guid) { sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetSelectedDungeons: [" UI64FMTD "]", guid); diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h index 3e324f4b5f4..d10902b9553 100755 --- a/src/server/game/DungeonFinding/LFGMgr.h +++ b/src/server/game/DungeonFinding/LFGMgr.h @@ -287,6 +287,9 @@ class LFGMgr void InitializeLockedDungeons(Player* player); + void _LoadFromDB(Field* fields, uint64 guid); + void _SaveToDB(uint64 guid, uint32 db_guid); + void SetComment(uint64 guid, const std::string& comment); const LfgLockMap& GetLockedDungeons(uint64 guid); LfgState GetState(uint64 guid); @@ -298,7 +301,9 @@ class LFGMgr void RemoveGroupData(uint64 guid); uint8 GetKicksLeft(uint64 gguid); uint8 GetVotesNeeded(uint64 gguid); + bool IsTeleported(uint64 pguid); void SetRoles(uint64 guid, uint8 roles); + void SetSelectedDungeons(uint64 guid, const LfgDungeonSet& dungeons); private: @@ -306,10 +311,8 @@ class LFGMgr const std::string& GetComment(uint64 gguid); void RestoreState(uint64 guid); void SetDungeon(uint64 guid, uint32 dungeon); - void SetSelectedDungeons(uint64 guid, const LfgDungeonSet& dungeons); void SetLockedDungeons(uint64 guid, const LfgLockMap& lock); void DecreaseKicksLeft(uint64 guid); - void NoExiste(uint8 lala); // Queue void AddToQueue(uint64 guid, uint8 queueId); @@ -352,6 +355,7 @@ class LFGMgr LfgGuidListMap m_currentQueue; ///< Ordered list. Used to find groups LfgGuidListMap m_newToQueue; ///< New groups to add to queue LfgCompatibleMap m_CompatibleMap; ///< Compatible dungeons + LfgGuidList m_teleport; ///< Players being teleported // Rolecheck - Proposal - Vote Kicks LfgRoleCheckMap m_RoleChecks; ///< Current Role checks LfgProposalMap m_Proposals; ///< Current Proposals diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 46f903ee71a..6a4b729e58a 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -2305,9 +2305,14 @@ bool Player::TeleportToBGEntryPoint() if (m_bgData.joinPos.m_mapId == MAPID_INVALID) return false; + Group* group = GetGroup(); + if (group && group->isLFGGroup() && group->GetMembersCount() == 1) + group->Disband(); + else + ScheduleDelayedOperation(DELAYED_BG_GROUP_RESTORE); + ScheduleDelayedOperation(DELAYED_BG_MOUNT_RESTORE); ScheduleDelayedOperation(DELAYED_BG_TAXI_RESTORE); - ScheduleDelayedOperation(DELAYED_BG_GROUP_RESTORE); return TeleportTo(m_bgData.joinPos); } @@ -7371,6 +7376,22 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) SendInitWorldStates(newZone, newArea); // only if really enters to new zone, not just area change, works strange... } + // group update + if (GetGroup()) + { + SetGroupUpdateFlag(GROUP_UPDATE_FULL); + Group* grp = GetGroup(); + if (GetSession() && grp->isLFGGroup() && sLFGMgr->IsTeleported(GetGUID())) + { + for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* tempplr = itr->getSource(); + if (tempplr) + GetSession()->SendNameQueryOpcode(tempplr->GetGUID()); + } + } + } + m_zoneUpdateId = newZone; m_zoneUpdateTimer = ZONE_UPDATE_INTERVAL; @@ -7458,10 +7479,6 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) // recent client version not send leave/join channel packets for built-in local channels UpdateLocalChannels(newZone); - // group update - if (GetGroup()) - SetGroupUpdateFlag(GROUP_UPDATE_FULL); - UpdateZoneDependentAuras(newZone); } @@ -11794,6 +11811,75 @@ InventoryResult Player::CanUseItem(ItemTemplate const* proto) const return EQUIP_ERR_ITEM_NOT_FOUND; } +InventoryResult Player::CanRollForItem(ItemTemplate const* proto) const +{ + if (!proto) + return EQUIP_ERR_ITEM_NOT_FOUND; + // Used by group, function NeedBeforeGreed, to know if a prototype can be used by a player + + const static uint32 item_weapon_skills[MAX_ITEM_SUBCLASS_WEAPON] = + { + SKILL_AXES, SKILL_2H_AXES, SKILL_BOWS, SKILL_GUNS, SKILL_MACES, + SKILL_2H_MACES, SKILL_POLEARMS, SKILL_SWORDS, SKILL_2H_SWORDS, 0, + SKILL_STAVES, 0, 0, SKILL_FIST_WEAPONS, 0, + SKILL_DAGGERS, SKILL_THROWN, SKILL_ASSASSINATION, SKILL_CROSSBOWS, SKILL_WANDS, + SKILL_FISHING + }; //Copy from function Item::GetSkill() + + if ((proto->AllowableClass & getClassMask()) == 0 || (proto->AllowableRace & getRaceMask()) == 0) + return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; + + if (proto->RequiredSpell != 0 && !HasSpell(proto->RequiredSpell)) + return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + + if (proto->RequiredSkill != 0) + { + if (!GetSkillValue(proto->RequiredSkill)) + return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + else if (GetSkillValue(proto->RequiredSkill) < proto->RequiredSkillRank) + return EQUIP_ERR_CANT_EQUIP_SKILL; + } + + uint8 _class = getClass(); + + if (proto->Class == ITEM_CLASS_WEAPON && GetSkillValue(item_weapon_skills[proto->SubClass]) == 0) + return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + + if (proto->Class == ITEM_CLASS_ARMOR && proto->SubClass > ITEM_SUBCLASS_ARMOR_MISC && proto->SubClass < ITEM_SUBCLASS_ARMOR_BUCKLER && proto->InventoryType != INVTYPE_CLOAK) + { + if (_class == CLASS_WARRIOR || _class == CLASS_PALADIN || _class == CLASS_DEATH_KNIGHT) + { + if (getLevel() < 40) + { + if (proto->SubClass != ITEM_SUBCLASS_ARMOR_MAIL) + return EQUIP_ERR_CANT_DO_RIGHT_NOW; + } + else if (proto->SubClass != ITEM_SUBCLASS_ARMOR_PLATE) + return EQUIP_ERR_CANT_DO_RIGHT_NOW; + } + else if (_class == CLASS_HUNTER || _class == CLASS_SHAMAN) + { + if (getLevel() < 40) + { + if (proto->SubClass != ITEM_SUBCLASS_ARMOR_LEATHER) + return EQUIP_ERR_CANT_DO_RIGHT_NOW; + } + else if (proto->SubClass != ITEM_SUBCLASS_ARMOR_MAIL) + return EQUIP_ERR_CANT_DO_RIGHT_NOW; + } + + if (_class == CLASS_ROGUE || _class == CLASS_DRUID) + if (proto->SubClass != ITEM_SUBCLASS_ARMOR_LEATHER) + return EQUIP_ERR_CANT_DO_RIGHT_NOW; + + if (_class == CLASS_MAGE || _class == CLASS_PRIEST || _class == CLASS_WARLOCK) + if (proto->SubClass != ITEM_SUBCLASS_ARMOR_CLOTH) + return EQUIP_ERR_CANT_DO_RIGHT_NOW; + } + + return EQUIP_ERR_OK; +} + InventoryResult Player::CanUseAmmo(uint32 item) const { sLog->outDebug(LOG_FILTER_PLAYER_ITEMS, "STORAGE: CanUseAmmo item = %u", item); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index aa1d4e8185e..2b8ea7bbdc8 100755 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1277,6 +1277,7 @@ class Player : public Unit, public GridObject bool HasItemTotemCategory(uint32 TotemCategory) const; InventoryResult CanUseItem(ItemTemplate const* pItem) const; InventoryResult CanUseAmmo(uint32 item) const; + InventoryResult CanRollForItem(ItemTemplate const* item) const; Item* StoreNewItem(ItemPosCountVec const& pos, uint32 item, bool update, int32 randomPropertyId = 0); Item* StoreNewItem(ItemPosCountVec const& pos, uint32 item, bool update, int32 randomPropertyId, AllowedLooterSet &allowedLooters); Item* StoreItem(ItemPosCountVec const& pos, Item* pItem, bool update); diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 49472880edd..b2fb59ea993 100755 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -190,6 +190,9 @@ void Group::LoadGroupFromDB(Field* fields) m_raidDifficulty = RAID_DIFFICULTY_10MAN_NORMAL; else m_raidDifficulty = Difficulty(r_diff); + + if (m_groupType & GROUPTYPE_LFG) + sLFGMgr->_LoadFromDB(fields, GetGUID()); } void Group::LoadMemberFromDB(uint32 guidLow, uint8 memberFlags, uint8 subgroup, uint8 roles) @@ -211,6 +214,14 @@ void Group::LoadMemberFromDB(uint32 guidLow, uint8 memberFlags, uint8 subgroup, m_memberSlots.push_back(member); SubGroupCounterIncrease(subgroup); + + if (isLFGGroup()) + { + LfgDungeonSet Dungeons; + Dungeons.insert(sLFGMgr->GetDungeon(GetGUID())); + sLFGMgr->SetSelectedDungeons(member.guid, Dungeons); + sLFGMgr->SetState(member.guid, sLFGMgr->GetState(GetGUID())); + } } void Group::ConvertToLFG() @@ -441,7 +452,7 @@ bool Group::RemoveMember(uint64 guid, const RemoveMethod &method /*= GROUP_REMOV return m_memberSlots.size(); // remove member and change leader (if need) only if strong more 2 members _before_ member remove (BG allow 1 member group) - if (GetMembersCount() > (isBGGroup() ? 1u : 2u)) + if (GetMembersCount() > ((isBGGroup() || isLFGGroup()) ? 1u : 2u)) { Player* player = ObjectAccessor::FindPlayer(guid); if (player) @@ -485,6 +496,8 @@ bool Group::RemoveMember(uint64 guid, const RemoveMethod &method /*= GROUP_REMOV CharacterDatabase.Execute(stmt); + DelinkMember(guid); + // Reevaluate group enchanter if the leaving player had enchanting skill or the player is offline if ((player && player->GetSkillValue(SKILL_ENCHANTING)) || !player) ResetMaxEnchantingLevel(); @@ -534,6 +547,20 @@ bool Group::RemoveMember(uint64 guid, const RemoveMethod &method /*= GROUP_REMOV } SendUpdate(); + + if (isLFGGroup() && GetMembersCount() == 1) + { + Player* Leader = ObjectAccessor::FindPlayer(GetLeaderGUID()); + LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(sLFGMgr->GetDungeon(GetGUID())); + if ((Leader && dungeon && Leader->isAlive() && Leader->GetMapId() != dungeon->map) || !dungeon) + { + Disband(); + return false; + } + } + + if (m_memberMgr.getSize() < ((isLFGGroup() || isBGGroup()) ? 1u : 2u)) + Disband(); return true; } @@ -673,6 +700,10 @@ void Group::Disband(bool hideDestroy /* = false */) CharacterDatabase.CommitTransaction(trans); ResetInstances(INSTANCE_RESET_GROUP_DISBAND, false, NULL); ResetInstances(INSTANCE_RESET_GROUP_DISBAND, true, NULL); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_LFG_DATA); + stmt->setUInt32(0, m_dbStoreId); + CharacterDatabase.Execute(stmt); sGroupMgr->FreeGroupDbStoreId(this); } @@ -709,6 +740,28 @@ void Group::SendLootStartRoll(uint32 CountDown, uint32 mapid, const Roll &r) } } +void Group::SendLootStartRollToPlayer(uint32 CountDown, uint32 mapid, Player* p, bool NeedBlocked, const Roll &r) +{ + if (!p || !p->GetSession()) + return; + + WorldPacket data(SMSG_LOOT_START_ROLL, (8 + 4 + 4 + 4 + 4 + 4 + 4 + 1 )); + data << uint64(r.itemGUID); // guid of rolled item + data << uint32(mapid); // 3.3.3 mapid + data << uint32(r.totalPlayersRolling); // maybe the number of players rolling for it??? + data << uint32(r.itemid); // the itemEntryId for the item that shall be rolled for + data << uint32(r.itemRandomSuffix); // randomSuffix + data << uint32(r.itemRandomPropId); // item random property ID + data << uint32(r.itemCount); // items in stack + data << uint32(CountDown); // the countdown time to choose "need" or "greed" + uint8 VoteMask = r.rollVoteMask; + if (NeedBlocked) + VoteMask &= ~ROLL_FLAG_TYPE_NEED; + data << uint8(VoteMask); // roll type mask + + p->GetSession()->SendPacket(&data); +} + void Group::SendLootRoll(uint64 SourceGuid, uint64 TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r) { WorldPacket data(SMSG_LOOT_ROLL, (8+4+8+4+4+4+1+1+1)); @@ -887,7 +940,7 @@ void Group::GroupLoot(Loot* loot, WorldObject* pLootedObject) } } -void Group::NeedBeforeGreed(Loot* loot, WorldObject* pLootedObject) +void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject) { ItemTemplate const* item; uint8 itemSlot = 0; @@ -902,7 +955,7 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* pLootedObject) if (item->Quality >= uint32(m_lootThreshold)) { uint64 newitemGUID = MAKE_NEW_GUID(sObjectMgr->GenerateLowGuid(HIGHGUID_ITEM), 0, HIGHGUID_ITEM); - Roll* r=new Roll(newitemGUID, *i); + Roll* r = new Roll(newitemGUID, *i); for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) { @@ -911,21 +964,17 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* pLootedObject) continue; bool allowedForPlayer = i->AllowedForPlayer(playerToRoll); - if (playerToRoll->CanUseItem(item) == EQUIP_ERR_OK && allowedForPlayer) + if (allowedForPlayer && playerToRoll->IsWithinDistInMap(lootedObject, sWorld->getFloatConfig(CONFIG_GROUP_XP_DISTANCE), false)) { - if (playerToRoll->IsWithinDistInMap(pLootedObject, sWorld->getFloatConfig(CONFIG_GROUP_XP_DISTANCE), false)) + r->totalPlayersRolling++; + if (playerToRoll->GetPassOnGroupLoot()) { - r->totalPlayersRolling++; - - if (playerToRoll->GetPassOnGroupLoot()) - { - r->playerVote[playerToRoll->GetGUID()] = PASS; - r->totalPass++; - // can't broadcast the pass now. need to wait until all rolling players are known. - } - else - r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET; + r->playerVote[playerToRoll->GetGUID()] = PASS; + r->totalPass++; + // can't broadcast the pass now. need to wait until all rolling players are known. } + else + r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET; } } @@ -941,25 +990,24 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* pLootedObject) loot->items[itemSlot].is_blocked = true; - // If there is any "auto pass", broadcast the pass now. - if (r->totalPass) + //Broadcast Pass and Send Rollstart + for (Roll::PlayerVote::const_iterator itr=r->playerVote.begin(); itr != r->playerVote.end(); ++itr) { - for (Roll::PlayerVote::const_iterator itr=r->playerVote.begin(); itr != r->playerVote.end(); ++itr) - { - Player* p = ObjectAccessor::FindPlayer(itr->first); - if (!p || !p->GetSession()) - continue; - - if (itr->second == PASS) - SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r); - } + Player* p = ObjectAccessor::FindPlayer(itr->first); + if (!p || !p->GetSession()) + continue; + + if (itr->second == PASS) + SendLootRoll(newitemGUID, p->GetGUID(), 128, ROLL_PASS, *r); + if (p->CanRollForItem(item) == EQUIP_ERR_OK) + SendLootStartRollToPlayer(60000, lootedObject->GetMapId(), p, false, *r); + else + SendLootStartRollToPlayer(60000, lootedObject->GetMapId(), p, true, *r); } - SendLootStartRoll(60000, pLootedObject->GetMapId(), *r); - RollId.push_back(r); - if (Creature* creature = pLootedObject->ToCreature()) + if (Creature* creature = lootedObject->ToCreature()) { creature->m_groupLootTimer = 60000; creature->lootingGroupLowGUID = GetLowGUID(); @@ -1242,9 +1290,7 @@ void Group::SendTargetIconList(WorldSession* session) void Group::SendUpdate() { for (member_witerator witr = m_memberSlots.begin(); witr != m_memberSlots.end(); ++witr) - { SendUpdateToPlayer(witr->guid, &(*witr)); - } } void Group::SendUpdateToPlayer(uint64 playerGUID, MemberSlot* slot) @@ -2118,8 +2164,19 @@ void Group::LinkMember(GroupReference* pRef) m_memberMgr.insertFirst(pRef); } -void Group::DelinkMember(GroupReference* /*pRef*/) const +void Group::DelinkMember(uint64 guid) { + GroupReference* ref = m_memberMgr.getFirst(); + while (ref) + { + GroupReference* nextRef = ref->next(); + if (ref->getSource()->GetGUID() == guid) + { + ref->unlink(); + break; + } + ref = nextRef; + } } Group::BoundInstancesMap& Group::GetBoundInstances(Difficulty difficulty) diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index bed112d5511..caa49125100 100755 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -273,6 +273,7 @@ class Group bool isRollLootActive() const; void SendLootStartRoll(uint32 CountDown, uint32 mapid, const Roll &r); + void SendLootStartRollToPlayer(uint32 CountDown, uint32 mapid, Player* p, bool NeedBlocked, const Roll &r); void SendLootRoll(uint64 SourceGuid, uint64 TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r); void SendLootRollWon(uint64 SourceGuid, uint64 TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r); void SendLootAllPassed(uint32 NumberOfPlayers, const Roll &r); @@ -289,7 +290,7 @@ class Group void ResetMaxEnchantingLevel(); void LinkMember(GroupReference* pRef); - void DelinkMember(GroupReference* /*pRef*/) const; + void DelinkMember(uint64 guid); InstanceGroupBind* BindToInstance(InstanceSave* save, bool permanent, bool load = false); void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload = false); diff --git a/src/server/game/Groups/GroupMgr.cpp b/src/server/game/Groups/GroupMgr.cpp index 412814a60d2..ae400852c73 100644 --- a/src/server/game/Groups/GroupMgr.cpp +++ b/src/server/game/Groups/GroupMgr.cpp @@ -119,10 +119,10 @@ void GroupMgr::LoadGroups() // Delete all groups with less than 2 members CharacterDatabase.DirectExecute("DELETE FROM groups WHERE guid NOT IN (SELECT guid FROM group_member GROUP BY guid HAVING COUNT(guid) > 1)"); - // 0 1 2 3 4 5 6 7 8 9 - QueryResult result = CharacterDatabase.PQuery("SELECT leaderGuid, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6" - // 10 11 12 13 14 15 - ", icon7, icon8, groupType, difficulty, raiddifficulty, guid FROM groups ORDER BY guid ASC"); + // 0 1 2 3 4 5 6 7 8 9 + QueryResult result = CharacterDatabase.PQuery("SELECT g.leaderGuid, g.lootMethod, g.looterGuid, g.lootThreshold, g.icon1, g.icon2, g.icon3, g.icon4, g.icon5, g.icon6" + // 10 11 12 13 14 15 16 17 + ", g.icon7, g.icon8, g.groupType, g.difficulty, g.raiddifficulty, g.guid, lfg.dungeon, lfg.state FROM groups g LEFT JOIN lfg_data lfg ON lfg.guid = g.guid ORDER BY g.guid ASC"); if (!result) { sLog->outString(">> Loaded 0 group definitions. DB table `groups` is empty!"); diff --git a/src/server/game/Groups/GroupReference.cpp b/src/server/game/Groups/GroupReference.cpp index 4d5890aa4e6..68d85c5bce9 100755 --- a/src/server/game/Groups/GroupReference.cpp +++ b/src/server/game/Groups/GroupReference.cpp @@ -28,12 +28,12 @@ void GroupReference::targetObjectBuildLink() void GroupReference::targetObjectDestroyLink() { // called from unlink() - getTarget()->DelinkMember(this); + //getTarget()->DelinkMember(this); } void GroupReference::sourceObjectDestroyLink() { // called from invalidate() - getTarget()->DelinkMember(this); + //getTarget()->DelinkMember(this); } diff --git a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp index 35276bb1d0a..bd9668ce5b8 100644 --- a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp @@ -43,6 +43,7 @@ #include "ScriptMgr.h" #include "Battleground.h" #include "AccountMgr.h" +#include "LFGMgr.h" class LoginQueryHolder : public SQLQueryHolder { @@ -196,7 +197,7 @@ bool LoginQueryHolder::Initialize() stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES); stmt->setUInt32(0, m_accountId); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADINSTANCELOCKTIMES, stmt); - + return res; } @@ -892,6 +893,17 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) } } + 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()); diff --git a/src/server/game/Server/Protocol/Handlers/LFGHandler.cpp b/src/server/game/Server/Protocol/Handlers/LFGHandler.cpp index 52b4d4abbed..3c6bd28b5cb 100755 --- a/src/server/game/Server/Protocol/Handlers/LFGHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/LFGHandler.cpp @@ -48,7 +48,8 @@ void BuildPartyLockDungeonBlock(WorldPacket& data, const LfgLockPartyMap& lockMa void WorldSession::HandleLfgJoinOpcode(WorldPacket& recv_data) { if (!sWorld->getBoolConfig(CONFIG_DUNGEON_FINDER_ENABLE) || - (GetPlayer()->GetGroup() && GetPlayer()->GetGroup()->GetLeaderGUID() != GetPlayer()->GetGUID())) + (GetPlayer()->GetGroup() && GetPlayer()->GetGroup()->GetLeaderGUID() != GetPlayer()->GetGUID() && + (GetPlayer()->GetGroup()->GetMembersCount() == MAXGROUPSIZE || !GetPlayer()->GetGroup()->isLFGGroup()))) { recv_data.rfinish(); return; diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 38e5771ccca..3fb2c4f3319 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -1445,7 +1445,17 @@ class spell_gen_luck_of_the_draw : public SpellScriptLoader if (GetUnitOwner()->GetTypeId() != TYPEID_PLAYER) return; - LFGDungeonEntry const* randomDungeon = sLFGDungeonStore.LookupEntry(*(sLFGMgr->GetSelectedDungeons(GetUnitOwner()->GetGUID()).begin())); + const LfgDungeonSet dungeons = sLFGMgr->GetSelectedDungeons(GetUnitOwner()->GetGUID()); + LfgDungeonSet::const_iterator itr = dungeons.begin(); + + if (itr == dungeons.end()) + { + Remove(AURA_REMOVE_BY_DEFAULT); + return; + } + + + LFGDungeonEntry const* randomDungeon = sLFGDungeonStore.LookupEntry(*itr); Group* group = GetUnitOwner()->ToPlayer()->GetGroup(); Map const* map = GetUnitOwner()->GetMap(); if (group && group->isLFGGroup()) diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index a24f17a8b76..24b99219f46 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -325,6 +325,10 @@ void CharacterDatabaseConnection::DoPrepareStatements() // For loading and deleting expired auctions at startup PREPARE_STATEMENT(CHAR_SEL_EXPIRED_AUCTIONS, "SELECT id, auctioneerguid, itemguid, itemEntry, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit FROM auctionhouse ah INNER JOIN item_instance ii ON ii.guid = ah.itemguid WHERE ah.time <= ?", CONNECTION_SYNCH) + + // LFG Data + PREPARE_STATEMENT(CHAR_INS_LFG_DATA, "INSERT INTO lfg_data (guid, dungeon, state) VALUES (?, ?, ?)", CONNECTION_ASYNC) + PREPARE_STATEMENT(CHAR_DEL_LFG_DATA, "DELETE FROM lfg_data WHERE guid = ?", CONNECTION_ASYNC) // Player saving PREPARE_STATEMENT(CHAR_INS_CHARACTER, "INSERT INTO characters (guid, account, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, " diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index a239e274a54..18b488e055a 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -351,6 +351,9 @@ enum CharacterDatabaseStatements CHAR_DEL_CHARACTER_SOCIAL, CHAR_UPD_CHARACTER_SOCIAL_NOTE, CHAR_UPD_CHARACTER_POSITION, + + CHAR_INS_LFG_DATA, + CHAR_DEL_LFG_DATA, MAX_CHARACTERDATABASE_STATEMENTS, }; -- cgit v1.2.3 From b02666213c4c69bb0ea1a237e746f994284184ec Mon Sep 17 00:00:00 2001 From: Machiavelli Date: Sun, 15 Jan 2012 15:26:00 +0100 Subject: Scripts/Misc: Fix some MovementInform handler filters after recent motionmaster changes Also correct year of SQL in dbbac0bdaae --- .../world/2011_01_14_03_world_trinity_string.sql | 6 ------ .../world/2012_01_14_03_world_trinity_string.sql | 6 ++++++ src/server/game/Movement/MotionMaster.cpp | 4 ++-- src/server/game/Movement/MotionMaster.h | 2 +- .../Northrend/IcecrownCitadel/boss_sindragosa.cpp | 2 +- .../UtgardeKeep/UtgardePinnacle/boss_svala.cpp | 18 ++++++++++++------ 6 files changed, 22 insertions(+), 16 deletions(-) delete mode 100644 sql/updates/world/2011_01_14_03_world_trinity_string.sql create mode 100644 sql/updates/world/2012_01_14_03_world_trinity_string.sql (limited to 'src/server/scripts') diff --git a/sql/updates/world/2011_01_14_03_world_trinity_string.sql b/sql/updates/world/2011_01_14_03_world_trinity_string.sql deleted file mode 100644 index 7dab007f774..00000000000 --- a/sql/updates/world/2011_01_14_03_world_trinity_string.sql +++ /dev/null @@ -1,6 +0,0 @@ -DELETE FROM `trinity_string` WHERE `entry` IN(1139,1140,1141,1142); -INSERT INTO `trinity_string` (`entry`,`content_default`) VALUES -(1139,' Follow player %s (lowguid %u)'), -(1140,' Follow creature %s (lowguid %u)'), -(1141,' Follow '), -(1142,' Effect movement'); diff --git a/sql/updates/world/2012_01_14_03_world_trinity_string.sql b/sql/updates/world/2012_01_14_03_world_trinity_string.sql new file mode 100644 index 00000000000..7dab007f774 --- /dev/null +++ b/sql/updates/world/2012_01_14_03_world_trinity_string.sql @@ -0,0 +1,6 @@ +DELETE FROM `trinity_string` WHERE `entry` IN(1139,1140,1141,1142); +INSERT INTO `trinity_string` (`entry`,`content_default`) VALUES +(1139,' Follow player %s (lowguid %u)'), +(1140,' Follow creature %s (lowguid %u)'), +(1141,' Follow '), +(1142,' Effect movement'); diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index 2656d882009..c17f5096748 100755 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -368,7 +368,7 @@ void MotionMaster::MoveJump(float x, float y, float z, float speedXY, float spee Mutate(new EffectMovementGenerator(id), MOTION_SLOT_CONTROLLED); } -void MotionMaster::MoveFall() +void MotionMaster::MoveFall(uint32 id/*=0*/) { // use larger distance for vmap height search than in most other cases float tz = i_owner->GetMap()->GetHeight(i_owner->GetPositionX(), i_owner->GetPositionY(), i_owner->GetPositionZ(), true, MAX_FALL_DISTANCE); @@ -387,7 +387,7 @@ void MotionMaster::MoveFall() init.MoveTo(i_owner->GetPositionX(),i_owner->GetPositionY(),tz); init.SetFall(); init.Launch(); - Mutate(new EffectMovementGenerator(0), MOTION_SLOT_CONTROLLED); + Mutate(new EffectMovementGenerator(id), MOTION_SLOT_CONTROLLED); } void MotionMaster::MoveCharge(float x, float y, float z, float speed, uint32 id) diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h index 00f1701e591..a5bd0861b04 100755 --- a/src/server/game/Movement/MotionMaster.h +++ b/src/server/game/Movement/MotionMaster.h @@ -163,7 +163,7 @@ class MotionMaster //: private std::stack void MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ); void MoveJumpTo(float angle, float speedXY, float speedZ); void MoveJump(float x, float y, float z, float speedXY, float speedZ, uint32 id = 0); - void MoveFall(); + void MoveFall(uint32 id = 0); void MoveSeekAssistance(float x, float y, float z); void MoveSeekAssistanceDistract(uint32 timer); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp index 46c1cf425ed..11100e6297e 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -268,7 +268,7 @@ class boss_sindragosa : public CreatureScript void MovementInform(uint32 type, uint32 point) { - if (type != POINT_MOTION_TYPE) + if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE) return; switch (point) diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp index 436336ec5b8..542243293de 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp @@ -94,6 +94,11 @@ enum SvalaPhase SVALADEAD }; +enum SvalaPoint +{ + POINT_FALL_GROUND = 1, +}; + #define DATA_INCREDIBLE_HULK 2043 static const float spectatorWP[2][3] = @@ -258,16 +263,16 @@ public: SetCombatMovement(false); me->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH); - me->GetMotionMaster()->MoveFall(); + me->GetMotionMaster()->MoveFall(POINT_FALL_GROUND); } } void MovementInform(uint32 motionType, uint32 pointId) { - if (motionType != POINT_MOTION_TYPE) + if (motionType != EFFECT_MOTION_TYPE) return; - if (pointId == 1) + if (pointId == POINT_FALL_GROUND) me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); } @@ -288,7 +293,7 @@ public: Phase = NORMAL; SetCombatMovement(true); - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 300, true)) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 300.0f, true)) me->GetMotionMaster()->MoveChase(target); } } @@ -330,7 +335,7 @@ public: { std::list lspectatorList; GetCreatureListWithEntryInGrid(lspectatorList, me, CREATURE_SPECTATOR, 100.0f); - for(std::list::iterator itr = lspectatorList.begin(); itr != lspectatorList.end(); ++itr) + for (std::list::iterator itr = lspectatorList.begin(); itr != lspectatorList.end(); ++itr) { if ((*itr)->isAlive()) { @@ -397,7 +402,8 @@ public: Phase = NORMAL; break; } - } else introTimer -= diff; + } + else introTimer -= diff; return; } -- cgit v1.2.3 From f10e41ee416d723cfae0b8791307a87e029708a6 Mon Sep 17 00:00:00 2001 From: kaelima Date: Sun, 15 Jan 2012 20:37:25 +0100 Subject: Scripts/Trial of the Crusader: Fix crash in MovementInform for Frost Sphere in Anub'arak encounter. Thanks Vincent-Michael! Fixes #4834 --- .../EasternKingdoms/Karazhan/boss_nightbane.cpp | 2 +- .../TrialOfTheCrusader/boss_anubarak_trial.cpp | 105 +++++++++++---------- 2 files changed, 56 insertions(+), 51 deletions(-) (limited to 'src/server/scripts') diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp index ecb909480c5..728446aa833 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp @@ -186,7 +186,7 @@ public: void MovementInform(uint32 type, uint32 id) { if (type != POINT_MOTION_TYPE) - return; + return; if (Intro) { diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp index 8e34a318d6c..d3d92375d39 100755 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp @@ -122,6 +122,11 @@ const Position SphereSpawn[6] = { 706.6383f, 161.5266f, 155.6701f, 0 }, }; +enum MovementPoints +{ + POINT_FALL_GROUND = 1 +}; + class boss_anubarak_trial : public CreatureScript { public: @@ -553,68 +558,68 @@ public: class mob_frost_sphere : public CreatureScript { -public: - mob_frost_sphere() : CreatureScript("mob_frost_sphere") { } + public: + mob_frost_sphere() : CreatureScript("mob_frost_sphere") { } - CreatureAI* GetAI(Creature* creature) const - { - return new mob_frost_sphereAI(creature); - }; - - struct mob_frost_sphereAI : public ScriptedAI - { - mob_frost_sphereAI(Creature* creature) : ScriptedAI(creature) + struct mob_frost_sphereAI : public ScriptedAI { - } - - bool m_bFall; - float x, y, z; + mob_frost_sphereAI(Creature* creature) : ScriptedAI(creature) + { + } - void Reset() - { - m_bFall = false; - me->SetReactState(REACT_PASSIVE); - me->SetFlying(true); - me->SetDisplayId(25144); - me->SetSpeed(MOVE_RUN, 0.5f, false); - me->GetMotionMaster()->MoveRandom(20.0f); - DoCast(SPELL_FROST_SPHERE); - } + void Reset() + { + _isFalling = false; + me->SetReactState(REACT_PASSIVE); + me->SetFlying(true); + me->SetDisplayId(me->GetCreatureInfo()->Modelid2); + me->SetSpeed(MOVE_RUN, 0.5f, false); + me->GetMotionMaster()->MoveRandom(20.0f); + DoCast(SPELL_FROST_SPHERE); + } - void DamageTaken(Unit* /*who*/, uint32& uiDamage) - { - if (me->GetHealth() < uiDamage) + void DamageTaken(Unit* /*who*/, uint32& damage) { - uiDamage = 0; - if (!m_bFall) + if (me->GetHealth() <= damage) { - m_bFall = true; - me->GetMotionMaster()->MoveIdle(); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - //At hit the ground - me->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH); - me->GetMotionMaster()->MoveFall(); + damage = 0; + if (!_isFalling) + { + _isFalling = true; + me->GetMotionMaster()->MoveIdle(); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + //At hit the ground + me->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH); + me->GetMotionMaster()->MoveFall(POINT_FALL_GROUND); + } } } - } - - void MovementInform(uint32 uiType, uint32 uiId) - { - if (uiType != POINT_MOTION_TYPE) return; - switch (uiId) + void MovementInform(uint32 type, uint32 pointId) { - case 0: - me->RemoveAurasDueToSpell(SPELL_FROST_SPHERE); - me->SetDisplayId(11686); - DoCast(SPELL_PERMAFROST_VISUAL); - DoCast(SPELL_PERMAFROST); - me->SetFloatValue(OBJECT_FIELD_SCALE_X, 2.0f); - break; + if (type != EFFECT_MOTION_TYPE) + return; + + switch (pointId) + { + case POINT_FALL_GROUND: + me->RemoveAurasDueToSpell(SPELL_FROST_SPHERE); + me->SetDisplayId(me->GetCreatureInfo()->Modelid1); + DoCast(SPELL_PERMAFROST_VISUAL); + DoCast(SPELL_PERMAFROST); + me->SetFloatValue(OBJECT_FIELD_SCALE_X, 2.0f); + break; + } } - } - }; + private: + bool _isFalling; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new mob_frost_sphereAI(creature); + }; }; class mob_anubarak_spike : public CreatureScript -- cgit v1.2.3 From c1cf2db17f69663078de5ece6136a6a9e434bf09 Mon Sep 17 00:00:00 2001 From: Discover Date: Mon, 16 Jan 2012 12:36:52 +0100 Subject: DB/SAI: The Missing Diplomat closes #3700 --- sql/updates/world/2012_01_16_07_world_sai.sql | 33 ++++++++++ .../scripts/EasternKingdoms/stormwind_city.cpp | 74 ---------------------- 2 files changed, 33 insertions(+), 74 deletions(-) create mode 100644 sql/updates/world/2012_01_16_07_world_sai.sql (limited to 'src/server/scripts') diff --git a/sql/updates/world/2012_01_16_07_world_sai.sql b/sql/updates/world/2012_01_16_07_world_sai.sql new file mode 100644 index 00000000000..33028d542e6 --- /dev/null +++ b/sql/updates/world/2012_01_16_07_world_sai.sql @@ -0,0 +1,33 @@ +-- [Q] [A] The Missing Diplomat +-- Dashel Stonefist SAI +SET @ENTRY := 4961; +SET @QUEST := 1447; +SET @SPELL_PUMMEL := 12555; +UPDATE `creature_template` SET `AIName`='SmartAI',`ScriptName`='' WHERE `entry`=@ENTRY; +UPDATE `quest_template` SET `StartScript`=0,`CompleteScript`=0,`EmoteOnComplete`=11 WHERE `id`=@QUEST; -- ONESHOT_LAUGH +UPDATE `quest_template` SET `CompleteEmote`=14 WHERE `entry`=1246; -- Previous version should make him rude against player +DELETE FROM `quest_start_scripts` WHERE `id`=@QUEST; +DELETE FROM `smart_scripts` WHERE `entryorguid` IN (@ENTRY,@ENTRY*100,@ENTRY*100+1); +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 +(@ENTRY,0,0,0,13,0,100,0,6000,21000,0,0,11,@SPELL_PUMMEL,0,0,0,0,0,1,0,0,0,0,0,0,0,"Dashel Stonefist - Player Casting - Cast Pummel"), + +(@ENTRY,0,1,0,19,0,100,0,@QUEST,0,0,0,80,@ENTRY*100,0,2,0,0,0,1,0,0,0,0,0,0,0,"Dashel Stonefist - On Quest Accept - Run Script"), +(@ENTRY*100,9,0,0,0,0,100,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Dashel Stonefist - On Script - Say Line 0"), +(@ENTRY*100,9,1,0,0,0,100,0,0,0,0,0,2,168,0,0,0,0,0,1,0,0,0,0,0,0,0,"Dashel Stonefist - On Script - Set Faction Hostile"), +(@ENTRY*100,9,2,0,0,0,100,0,0,0,0,0,49,0,0,0,0,0,0,7,0,0,0,0,0,0,0,"Dashel Stonefist - On Script - Attack Player"), +(@ENTRY*100,9,3,0,0,0,100,0,2000,2000,0,0,12,4969,1,300000,0,0,0,8,0,0,0,-8678.246094,440.952606,99.620926,4.364815,"Dashel Stonefist - On Script - Summon Old Town Thug"), +(@ENTRY*100,9,4,0,0,0,100,0,0,0,0,0,12,4969,1,300000,0,0,0,8,0,0,0,-8682.465820,441.471161,99.531319,4.871392,"Dashel Stonefist - On Script - Summon Old Town Thug"), + +(@ENTRY,0,2,0,2,0,100,0,0,15,0,0,80,@ENTRY*100+1,0,2,0,0,0,1,0,0,0,0,0,0,0,"Dashel Stonefist - On 15% HP - Run Script"), +(@ENTRY*100+1,9,0,0,0,0,100,0,0,0,0,0,15,@QUEST,0,0,0,0,0,7,0,0,0,0,0,0,0,"Dashel Stonefist - On Script - Quest Credit"), -- We are putting this before evade else we lose our target +(@ENTRY*100+1,9,1,0,0,0,100,0,0,0,0,0,20,9,0,0,0,0,0,1,0,0,0,0,0,0,0,"Dashel Stonefist - On Script - Stop Attacking"), +(@ENTRY*100+1,9,2,0,0,0,100,0,0,0,0,0,24,0,0,0,0,0,0,1,0,0,0,0,0,0,0,"Dashel Stonefist - On Script - Evade"), +(@ENTRY*100+1,9,3,0,0,0,100,0,0,0,0,0,2,84,0,0,0,0,0,1,0,0,0,0,0,0,0,"Dashel Stonefist - On Script - Set Faction Back"), +(@ENTRY*100+1,9,4,0,0,0,100,0,0,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,"Dashel Stonefist - On Script - Say Line 1"), +(@ENTRY*100+1,9,5,0,0,0,100,0,6000,6000,0,0,1,2,0,0,0,0,0,1,0,0,0,0,0,0,0,"Dashel Stonefist - On Script - Say Line 2"); +-- Texts +DELETE FROM `creature_text` WHERE `entry`=@ENTRY; +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +(@ENTRY,0,0,"Now you're going to get it good!",12,0,100,0,0,0,"Dashel Stonefist"), +(@ENTRY,1,0,"Okay, okay! Enough fighting. No one else needs to get hurt.",12,0,100,0,0,0,"Dashel Stonefist"), +(@ENTRY,2,0,"It's okay, boys. Back off. You've done enough. I'll meet up with you later.",12,0,100,0,0,0,"Dashel Stonefist"); diff --git a/src/server/scripts/EasternKingdoms/stormwind_city.cpp b/src/server/scripts/EasternKingdoms/stormwind_city.cpp index 4d43e4adefe..a4eca1950f8 100644 --- a/src/server/scripts/EasternKingdoms/stormwind_city.cpp +++ b/src/server/scripts/EasternKingdoms/stormwind_city.cpp @@ -26,7 +26,6 @@ EndScriptData */ /* ContentData npc_archmage_malin npc_bartleby -npc_dashel_stonefist npc_lady_katrana_prestor npc_tyrion npc_tyrion_spybot @@ -147,78 +146,6 @@ public: }; -/*###### -## npc_dashel_stonefist -######*/ - -enum eDashel -{ - QUEST_MISSING_DIPLO_PT8 = 1447, - FACTION_HOSTILE = 168 -}; - -class npc_dashel_stonefist : public CreatureScript -{ -public: - npc_dashel_stonefist() : CreatureScript("npc_dashel_stonefist") { } - - bool OnQuestAccept(Player* player, Creature* creature, Quest const* quest) - { - if (quest->GetQuestId() == QUEST_MISSING_DIPLO_PT8) - { - creature->setFaction(FACTION_HOSTILE); - CAST_AI(npc_dashel_stonefist::npc_dashel_stonefistAI, creature->AI())->AttackStart(player); - } - return true; - } - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_dashel_stonefistAI(creature); - } - - struct npc_dashel_stonefistAI : public ScriptedAI - { - npc_dashel_stonefistAI(Creature* c) : ScriptedAI(c) - { - m_uiNormalFaction = c->getFaction(); - } - - uint32 m_uiNormalFaction; - - void Reset() - { - if (me->getFaction() != m_uiNormalFaction) - me->setFaction(m_uiNormalFaction); - } - - void AttackedBy(Unit* pAttacker) - { - if (me->getVictim()) - return; - - if (me->IsFriendlyTo(pAttacker)) - return; - - AttackStart(pAttacker); - } - - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) - { - if (uiDamage > me->GetHealth() || me->HealthBelowPctDamaged(15, uiDamage)) - { - uiDamage = 0; - - if (pDoneBy->GetTypeId() == TYPEID_PLAYER) - CAST_PLR(pDoneBy)->AreaExploredOrEventHappens(QUEST_MISSING_DIPLO_PT8); - - EnterEvadeMode(); - } - } - }; - -}; - /*###### ## npc_lady_katrana_prestor ######*/ @@ -716,7 +643,6 @@ void AddSC_stormwind_city() { new npc_archmage_malin(); new npc_bartleby(); - new npc_dashel_stonefist(); new npc_lady_katrana_prestor(); new npc_tyrion(); new npc_tyrion_spybot(); -- cgit v1.2.3 From 688ddb17d428a2ea93861226775d522c3999c5b3 Mon Sep 17 00:00:00 2001 From: Fredi Date: Tue, 17 Jan 2012 09:25:46 -0200 Subject: Core/Commands: Implement reload multiple creature templates Example: .reload creature_template 34797 34799 35144 34796 Closes #2700 --- src/server/scripts/Commands/cs_reload.cpp | 209 +++++++++++++++--------------- 1 file changed, 106 insertions(+), 103 deletions(-) (limited to 'src/server/scripts') diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index 4d8ce4ef4ed..35b590fe404 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -404,113 +404,116 @@ public: if (!*args) return false; - uint32 entry = (uint32) atoi((char*)args); - QueryResult result = WorldDatabase.PQuery("SELECT difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction_A, faction_H, npcflag, speed_walk, speed_run, scale, rank, mindmg, maxdmg, dmgschool, attackpower, dmg_multiplier, baseattacktime, rangeattacktime, unit_class, unit_flags, dynamicflags, family, trainer_type, trainer_spell, trainer_class, trainer_race, minrangedmg, maxrangedmg, rangedattackpower, type, type_flags, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, Health_mod, Mana_mod, Armor_mod, RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, questItem6, movementId, RegenHealth, equipment_id, mechanic_immune_mask, flags_extra, ScriptName FROM creature_template WHERE entry = %u", entry); - if (!result) - { - handler->PSendSysMessage(LANG_COMMAND_CREATURETEMPLATE_NOTFOUND, entry); - handler->SetSentErrorMessage(true); - return false; - } - - CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(entry); - if (!cInfo) - { - handler->PSendSysMessage(LANG_COMMAND_CREATURESTORAGE_NOTFOUND, entry); - handler->SetSentErrorMessage(true); - return false; - } + Tokens entries(std::string(args), ' '); - sLog->outString("Reloading creature template entry %u", entry); - - Field* fields = result->Fetch(); - - const_cast(cInfo)->DifficultyEntry[0] = fields[0].GetUInt32(); - const_cast(cInfo)->DifficultyEntry[1] = fields[1].GetUInt32(); - const_cast(cInfo)->DifficultyEntry[2] = fields[2].GetUInt32(); - const_cast(cInfo)->KillCredit[0] = fields[3].GetUInt32(); - const_cast(cInfo)->KillCredit[1] = fields[4].GetUInt32(); - const_cast(cInfo)->Modelid1 = fields[5].GetUInt32(); - const_cast(cInfo)->Modelid2 = fields[6].GetUInt32(); - const_cast(cInfo)->Modelid3 = fields[7].GetUInt32(); - const_cast(cInfo)->Modelid4 = fields[8].GetUInt32(); - const_cast(cInfo)->Name = fields[9].GetString(); - const_cast(cInfo)->SubName = fields[10].GetString(); - const_cast(cInfo)->IconName = fields[11].GetString(); - const_cast(cInfo)->GossipMenuId = fields[12].GetUInt32(); - const_cast(cInfo)->minlevel = fields[13].GetUInt32(); - const_cast(cInfo)->maxlevel = fields[14].GetUInt32(); - const_cast(cInfo)->expansion = fields[15].GetUInt32(); - const_cast(cInfo)->faction_A = fields[16].GetUInt32(); - const_cast(cInfo)->faction_H = fields[17].GetUInt32(); - const_cast(cInfo)->npcflag = fields[18].GetUInt32(); - const_cast(cInfo)->speed_walk = fields[19].GetFloat(); - const_cast(cInfo)->speed_run = fields[20].GetFloat(); - const_cast(cInfo)->scale = fields[21].GetFloat(); - const_cast(cInfo)->rank = fields[22].GetUInt32(); - const_cast(cInfo)->mindmg = fields[23].GetFloat(); - const_cast(cInfo)->maxdmg = fields[24].GetFloat(); - const_cast(cInfo)->dmgschool = fields[25].GetUInt32(); - const_cast(cInfo)->attackpower = fields[26].GetUInt32(); - const_cast(cInfo)->dmg_multiplier = fields[27].GetFloat(); - const_cast(cInfo)->baseattacktime = fields[28].GetUInt32(); - const_cast(cInfo)->rangeattacktime = fields[29].GetUInt32(); - const_cast(cInfo)->unit_class = fields[30].GetUInt32(); - const_cast(cInfo)->unit_flags = fields[31].GetUInt32(); - const_cast(cInfo)->dynamicflags = fields[32].GetUInt32(); - const_cast(cInfo)->family = fields[33].GetUInt32(); - const_cast(cInfo)->trainer_type = fields[34].GetUInt32(); - const_cast(cInfo)->trainer_spell = fields[35].GetUInt32(); - const_cast(cInfo)->trainer_class = fields[36].GetUInt32(); - const_cast(cInfo)->trainer_race = fields[37].GetUInt32(); - const_cast(cInfo)->minrangedmg = fields[38].GetFloat(); - const_cast(cInfo)->maxrangedmg = fields[39].GetFloat(); - const_cast(cInfo)->rangedattackpower = fields[40].GetUInt32(); - const_cast(cInfo)->type = fields[41].GetUInt32(); - const_cast(cInfo)->type_flags = fields[42].GetUInt32(); - const_cast(cInfo)->lootid = fields[43].GetUInt32(); - const_cast(cInfo)->pickpocketLootId = fields[44].GetUInt32(); - const_cast(cInfo)->SkinLootId = fields[45].GetUInt32(); - - for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) + for (Tokens::const_iterator itr = entries.begin(); itr != entries.end(); ++itr) { - const_cast(cInfo)->resistance[i] = fields[46 + i -1].GetUInt32(); + uint32 entry = uint32(atoi(*itr)); + QueryResult result = WorldDatabase.PQuery("SELECT difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction_A, faction_H, npcflag, speed_walk, speed_run, scale, rank, mindmg, maxdmg, dmgschool, attackpower, dmg_multiplier, baseattacktime, rangeattacktime, unit_class, unit_flags, dynamicflags, family, trainer_type, trainer_spell, trainer_class, trainer_race, minrangedmg, maxrangedmg, rangedattackpower, type, type_flags, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, Health_mod, Mana_mod, Armor_mod, RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, questItem6, movementId, RegenHealth, equipment_id, mechanic_immune_mask, flags_extra, ScriptName FROM creature_template WHERE entry = %u", entry); + if (!result) + { + handler->PSendSysMessage(LANG_COMMAND_CREATURETEMPLATE_NOTFOUND, entry); + continue; + } + + CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(entry); + if (!cInfo) + { + handler->PSendSysMessage(LANG_COMMAND_CREATURESTORAGE_NOTFOUND, entry); + continue; + } + + sLog->outString("Reloading creature template entry %u", entry); + + Field* fields = result->Fetch(); + + const_cast(cInfo)->DifficultyEntry[0] = fields[0].GetUInt32(); + const_cast(cInfo)->DifficultyEntry[1] = fields[1].GetUInt32(); + const_cast(cInfo)->DifficultyEntry[2] = fields[2].GetUInt32(); + const_cast(cInfo)->KillCredit[0] = fields[3].GetUInt32(); + const_cast(cInfo)->KillCredit[1] = fields[4].GetUInt32(); + const_cast(cInfo)->Modelid1 = fields[5].GetUInt32(); + const_cast(cInfo)->Modelid2 = fields[6].GetUInt32(); + const_cast(cInfo)->Modelid3 = fields[7].GetUInt32(); + const_cast(cInfo)->Modelid4 = fields[8].GetUInt32(); + const_cast(cInfo)->Name = fields[9].GetString(); + const_cast(cInfo)->SubName = fields[10].GetString(); + const_cast(cInfo)->IconName = fields[11].GetString(); + const_cast(cInfo)->GossipMenuId = fields[12].GetUInt32(); + const_cast(cInfo)->minlevel = fields[13].GetUInt32(); + const_cast(cInfo)->maxlevel = fields[14].GetUInt32(); + const_cast(cInfo)->expansion = fields[15].GetUInt32(); + const_cast(cInfo)->faction_A = fields[16].GetUInt32(); + const_cast(cInfo)->faction_H = fields[17].GetUInt32(); + const_cast(cInfo)->npcflag = fields[18].GetUInt32(); + const_cast(cInfo)->speed_walk = fields[19].GetFloat(); + const_cast(cInfo)->speed_run = fields[20].GetFloat(); + const_cast(cInfo)->scale = fields[21].GetFloat(); + const_cast(cInfo)->rank = fields[22].GetUInt32(); + const_cast(cInfo)->mindmg = fields[23].GetFloat(); + const_cast(cInfo)->maxdmg = fields[24].GetFloat(); + const_cast(cInfo)->dmgschool = fields[25].GetUInt32(); + const_cast(cInfo)->attackpower = fields[26].GetUInt32(); + const_cast(cInfo)->dmg_multiplier = fields[27].GetFloat(); + const_cast(cInfo)->baseattacktime = fields[28].GetUInt32(); + const_cast(cInfo)->rangeattacktime = fields[29].GetUInt32(); + const_cast(cInfo)->unit_class = fields[30].GetUInt32(); + const_cast(cInfo)->unit_flags = fields[31].GetUInt32(); + const_cast(cInfo)->dynamicflags = fields[32].GetUInt32(); + const_cast(cInfo)->family = fields[33].GetUInt32(); + const_cast(cInfo)->trainer_type = fields[34].GetUInt32(); + const_cast(cInfo)->trainer_spell = fields[35].GetUInt32(); + const_cast(cInfo)->trainer_class = fields[36].GetUInt32(); + const_cast(cInfo)->trainer_race = fields[37].GetUInt32(); + const_cast(cInfo)->minrangedmg = fields[38].GetFloat(); + const_cast(cInfo)->maxrangedmg = fields[39].GetFloat(); + const_cast(cInfo)->rangedattackpower = fields[40].GetUInt32(); + const_cast(cInfo)->type = fields[41].GetUInt32(); + const_cast(cInfo)->type_flags = fields[42].GetUInt32(); + const_cast(cInfo)->lootid = fields[43].GetUInt32(); + const_cast(cInfo)->pickpocketLootId = fields[44].GetUInt32(); + const_cast(cInfo)->SkinLootId = fields[45].GetUInt32(); + + for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) + { + const_cast(cInfo)->resistance[i] = fields[46 + i -1].GetUInt32(); + } + + const_cast(cInfo)->spells[0] = fields[52].GetUInt32(); + const_cast(cInfo)->spells[1] = fields[53].GetUInt32(); + const_cast(cInfo)->spells[2] = fields[54].GetUInt32(); + const_cast(cInfo)->spells[3] = fields[55].GetUInt32(); + const_cast(cInfo)->spells[4] = fields[56].GetUInt32(); + const_cast(cInfo)->spells[5] = fields[57].GetUInt32(); + const_cast(cInfo)->spells[6] = fields[58].GetUInt32(); + const_cast(cInfo)->spells[7] = fields[59].GetUInt32(); + const_cast(cInfo)->PetSpellDataId = fields[60].GetUInt32(); + const_cast(cInfo)->VehicleId = fields[61].GetUInt32(); + const_cast(cInfo)->mingold = fields[62].GetUInt32(); + const_cast(cInfo)->maxgold = fields[63].GetUInt32(); + const_cast(cInfo)->AIName = fields[64].GetString(); + const_cast(cInfo)->MovementType = fields[65].GetUInt32(); + const_cast(cInfo)->InhabitType = fields[66].GetUInt32(); + const_cast(cInfo)->ModHealth = fields[67].GetFloat(); + const_cast(cInfo)->ModMana = fields[68].GetFloat(); + const_cast(cInfo)->ModArmor = fields[69].GetFloat(); + const_cast(cInfo)->RacialLeader = fields[70].GetBool(); + const_cast(cInfo)->questItems[0] = fields[71].GetUInt32(); + const_cast(cInfo)->questItems[1] = fields[72].GetUInt32(); + const_cast(cInfo)->questItems[2] = fields[73].GetUInt32(); + const_cast(cInfo)->questItems[3] = fields[74].GetUInt32(); + const_cast(cInfo)->questItems[4] = fields[75].GetUInt32(); + const_cast(cInfo)->questItems[5] = fields[76].GetUInt32(); + const_cast(cInfo)->movementId = fields[77].GetUInt32(); + const_cast(cInfo)->RegenHealth = fields[78].GetBool(); + const_cast(cInfo)->equipmentId = fields[79].GetUInt32(); + const_cast(cInfo)->MechanicImmuneMask = fields[80].GetUInt32(); + const_cast(cInfo)->flags_extra = fields[81].GetUInt32(); + const_cast(cInfo)->ScriptID = sObjectMgr->GetScriptId(fields[82].GetCString()); + + sObjectMgr->CheckCreatureTemplate(cInfo); } - const_cast(cInfo)->spells[0] = fields[52].GetUInt32(); - const_cast(cInfo)->spells[1] = fields[53].GetUInt32(); - const_cast(cInfo)->spells[2] = fields[54].GetUInt32(); - const_cast(cInfo)->spells[3] = fields[55].GetUInt32(); - const_cast(cInfo)->spells[4] = fields[56].GetUInt32(); - const_cast(cInfo)->spells[5] = fields[57].GetUInt32(); - const_cast(cInfo)->spells[6] = fields[58].GetUInt32(); - const_cast(cInfo)->spells[7] = fields[59].GetUInt32(); - const_cast(cInfo)->PetSpellDataId = fields[60].GetUInt32(); - const_cast(cInfo)->VehicleId = fields[61].GetUInt32(); - const_cast(cInfo)->mingold = fields[62].GetUInt32(); - const_cast(cInfo)->maxgold = fields[63].GetUInt32(); - const_cast(cInfo)->AIName = fields[64].GetString(); - const_cast(cInfo)->MovementType = fields[65].GetUInt32(); - const_cast(cInfo)->InhabitType = fields[66].GetUInt32(); - const_cast(cInfo)->ModHealth = fields[67].GetFloat(); - const_cast(cInfo)->ModMana = fields[68].GetFloat(); - const_cast(cInfo)->ModArmor = fields[69].GetFloat(); - const_cast(cInfo)->RacialLeader = fields[70].GetBool(); - const_cast(cInfo)->questItems[0] = fields[71].GetUInt32(); - const_cast(cInfo)->questItems[1] = fields[72].GetUInt32(); - const_cast(cInfo)->questItems[2] = fields[73].GetUInt32(); - const_cast(cInfo)->questItems[3] = fields[74].GetUInt32(); - const_cast(cInfo)->questItems[4] = fields[75].GetUInt32(); - const_cast(cInfo)->questItems[5] = fields[76].GetUInt32(); - const_cast(cInfo)->movementId = fields[77].GetUInt32(); - const_cast(cInfo)->RegenHealth = fields[78].GetBool(); - const_cast(cInfo)->equipmentId = fields[79].GetUInt32(); - const_cast(cInfo)->MechanicImmuneMask = fields[80].GetUInt32(); - const_cast(cInfo)->flags_extra = fields[81].GetUInt32(); - const_cast(cInfo)->ScriptID = sObjectMgr->GetScriptId(fields[82].GetCString()); - - sObjectMgr->CheckCreatureTemplate(cInfo); - handler->SendGlobalGMSysMessage("Creature template reloaded."); return true; } -- cgit v1.2.3 From 4bdc5353735a7ec73c23e11f824adb378eea3adf Mon Sep 17 00:00:00 2001 From: Souler Date: Tue, 17 Jan 2012 12:55:54 +0100 Subject: Script/Quest: Solve some related problems with "An Audience With The Arcanist" and "A Meeting With The Magister" --- sql/updates/world/2012_01_17_00_world_misc.sql | 27 +++++++++ src/server/scripts/Northrend/dalaran.cpp | 13 ++++- src/server/scripts/Spells/spell_generic.cpp | 80 +++++++++++++++++++++++++- 3 files changed, 116 insertions(+), 4 deletions(-) create mode 100644 sql/updates/world/2012_01_17_00_world_misc.sql (limited to 'src/server/scripts') diff --git a/sql/updates/world/2012_01_17_00_world_misc.sql b/sql/updates/world/2012_01_17_00_world_misc.sql new file mode 100644 index 00000000000..300d239bd43 --- /dev/null +++ b/sql/updates/world/2012_01_17_00_world_misc.sql @@ -0,0 +1,27 @@ +DELETE FROM `spell_script_names` WHERE `spell_id` IN (69672,69673); +INSERT INTO `spell_script_names`(`spell_id`,`ScriptName`) VALUES +(69672,'spell_gen_sunreaver_disguise'), +(69673,'spell_gen_silver_covenant_disguise'); + +-- Update spells used on script. Now they are always casting the female spell, +-- since the spell script is fixed we should cast now the correct spell. +UPDATE `smart_scripts` SET `action_param1`=69672 WHERE `entryorguid`=36669 AND `action_type`=11 AND `action_param1`=70973; +UPDATE `smart_scripts` SET `action_param1`=69673 WHERE `entryorguid`=36670 AND `action_type`=11 AND `action_param1`=70971; +-- Set correct gossip menus ids for renewing the disguise +UPDATE `smart_scripts` SET `event_param1`=10858 WHERE `entryorguid`=36669 AND `event_param1`=10857; +UPDATE `smart_scripts` SET `event_param1`=10857 WHERE `entryorguid`=36670 AND `event_param1`=10858; + +-- Gossip options were crossed. They should offer to cast the oposing faction disguise,instead of his own faction disguise. +UPDATE `gossip_menu_option` SET `option_text`="Would you renew my Covenant disguise?" WHERE `menu_id`=10857 AND `id`=1; +UPDATE `gossip_menu_option` SET `option_text`="Would you renew my Sunreaver disguise?" WHERE `menu_id`=10858 AND `id`=1; + +-- Correct quest ids on conditios for showing the renew disguise option. +-- Also add a check for male disguise aura. +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=15 AND `SourceGroup` IN (10857,10858) AND `SourceEntry`=1; +INSERT INTO `conditions`(`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES +(15,10858,1,0,11,70973,0,0,0,'',NULL), +(15,10858,1,0,11,70974,0,0,0,'',NULL), +(15,10858,1,0,9,20439,0,0,0,'',NULL), +(15,10857,1,0,11,70971,0,0,0,'',NULL), +(15,10857,1,0,11,70972,0,0,0,'',NULL), +(15,10857,1,0,9,24451,0,0,0,'',NULL); diff --git a/src/server/scripts/Northrend/dalaran.cpp b/src/server/scripts/Northrend/dalaran.cpp index 57007a93fa7..cd3cbf29d0d 100644 --- a/src/server/scripts/Northrend/dalaran.cpp +++ b/src/server/scripts/Northrend/dalaran.cpp @@ -32,7 +32,12 @@ Script Data End */ enum Spells { SPELL_TRESPASSER_A = 54028, - SPELL_TRESPASSER_H = 54029 + SPELL_TRESPASSER_H = 54029, + + SPELL_SUNREAVER_DISGUISE_FEMALE = 70973, + SPELL_SUNREAVER_DISGUISE_MALE = 70974, + SPELL_SILVER_COVENANT_DISGUISE_FEMALE = 70971, + SPELL_SILVER_COVENANT_DISGUISE_MALE = 70972, }; enum NPCs // All outdoor guards are within 35.0f of these NPCs @@ -71,8 +76,10 @@ public: Player* player = who->GetCharmerOrOwnerPlayerOrPlayerItself(); - // If player has Disguise aura for quest A Meeting With The Magister or An Audience With The Arcanist, do not teleport it away but let it pass - if (!player || player->isGameMaster() || player->IsBeingTeleported() || player->HasAura(70973) || player->HasAura(70971)) + if (!player || player->isGameMaster() || player->IsBeingTeleported() || + // If player has Disguise aura for quest A Meeting With The Magister or An Audience With The Arcanist, do not teleport it away but let it pass + player->HasAura(SPELL_SUNREAVER_DISGUISE_FEMALE) || player->HasAura(SPELL_SUNREAVER_DISGUISE_MALE) || + player->HasAura(SPELL_SILVER_COVENANT_DISGUISE_FEMALE) || player->HasAura(SPELL_SILVER_COVENANT_DISGUISE_MALE)) return; switch (me->GetEntry()) diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 38e5771ccca..bb3e63af8e4 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -1471,6 +1471,82 @@ class spell_gen_luck_of_the_draw : public SpellScriptLoader } }; +enum DalaranDisguiseSpells +{ + SPELL_SUNREAVER_DISGUISE_TRIGGER = 69672, + SPELL_SUNREAVER_DISGUISE_FEMALE = 70973, + SPELL_SUNREAVER_DISGUISE_MALE = 70974, + + SPELL_SILVER_COVENANT_DISGUISE_TRIGGER = 69673, + SPELL_SILVER_COVENANT_DISGUISE_FEMALE = 70971, + SPELL_SILVER_COVENANT_DISGUISE_MALE = 70972, +}; + +class spell_gen_dalaran_disguise : public SpellScriptLoader +{ + public: + spell_gen_dalaran_disguise(const char* name) : SpellScriptLoader(name) {} + + class spell_gen_dalaran_disguise_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gen_dalaran_disguise_SpellScript); + bool Validate(SpellInfo const* spellEntry) + { + switch (spellEntry->Id) + { + case SPELL_SUNREAVER_DISGUISE_TRIGGER: + if (!sSpellMgr->GetSpellInfo(SPELL_SUNREAVER_DISGUISE_FEMALE)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_SUNREAVER_DISGUISE_MALE)) + return false; + break; + case SPELL_SILVER_COVENANT_DISGUISE_TRIGGER: + if (!sSpellMgr->GetSpellInfo(SPELL_SILVER_COVENANT_DISGUISE_FEMALE)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_SILVER_COVENANT_DISGUISE_MALE)) + return false; + break; + } + return true; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + + if (Player* player = GetHitPlayer()) + { + uint8 gender = player->getGender(); + + uint32 spellId = GetSpellInfo()->Id; + + switch (spellId) + { + case SPELL_SUNREAVER_DISGUISE_TRIGGER: + spellId = gender ? SPELL_SUNREAVER_DISGUISE_FEMALE : SPELL_SUNREAVER_DISGUISE_MALE; + break; + case SPELL_SILVER_COVENANT_DISGUISE_TRIGGER: + spellId = gender ? SPELL_SILVER_COVENANT_DISGUISE_FEMALE : SPELL_SILVER_COVENANT_DISGUISE_MALE; + break; + default: + break; + } + + GetCaster()->CastSpell(player, spellId, true); + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_gen_dalaran_disguise_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_gen_dalaran_disguise_SpellScript(); + } +}; + void AddSC_generic_spell_scripts() { new spell_gen_absorb0_hitlimit1(); @@ -1504,4 +1580,6 @@ void AddSC_generic_spell_scripts() new spell_gen_oracle_wolvar_reputation(); new spell_gen_damage_reduction_aura(); new spell_gen_luck_of_the_draw(); -} + new spell_gen_dalaran_disguise("spell_gen_sunreaver_disguise"); + new spell_gen_dalaran_disguise("spell_gen_silver_covenant_disguise"); +} \ No newline at end of file -- cgit v1.2.3 From 2d89b4bfe0db8979c2e530c9afd83f7fbf286394 Mon Sep 17 00:00:00 2001 From: Machiavelli Date: Wed, 18 Jan 2012 21:02:06 +0100 Subject: Core/DBLayer: Change some incorrect uses of PQuery with PExecute or Execute --- src/server/game/Groups/Group.cpp | 4 +++- src/server/scripts/Commands/cs_npc.cpp | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src/server/scripts') diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 19bc1ab7dea..b31b632e963 100755 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -203,7 +203,9 @@ void Group::LoadMemberFromDB(uint32 guidLow, uint8 memberFlags, uint8 subgroup, // skip non-existed member if (!sObjectMgr->GetPlayerNameByGUID(member.guid, member.name)) { - CharacterDatabase.PQuery("DELETE FROM group_member WHERE memberGuid=%u", guidLow); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_MEMBER); + stmt->setUInt32(0, guidLow); + CharacterDatabase.Execute(stmt); return; } diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 1b6a6c6fdcf..57932ef56c6 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -130,7 +130,7 @@ public: { uint32 tguid = chr->GetTransport()->AddNPCPassenger(0, id, chr->GetTransOffsetX(), chr->GetTransOffsetY(), chr->GetTransOffsetZ(), chr->GetTransOffsetO()); if (tguid > 0) - WorldDatabase.PQuery("INSERT INTO creature_transport (guid, npc_entry, transport_entry, TransOffsetX, TransOffsetY, TransOffsetZ, TransOffsetO) values (%u, %u, %f, %f, %f, %f, %u)", tguid, id, chr->GetTransport()->GetEntry(), chr->GetTransOffsetX(), chr->GetTransOffsetY(), chr->GetTransOffsetZ(), chr->GetTransOffsetO()); + WorldDatabase.PExecute("INSERT INTO creature_transport (guid, npc_entry, transport_entry, TransOffsetX, TransOffsetY, TransOffsetZ, TransOffsetO) values (%u, %u, %f, %f, %f, %f, %u)", tguid, id, chr->GetTransport()->GetEntry(), chr->GetTransOffsetX(), chr->GetTransOffsetY(), chr->GetTransOffsetZ(), chr->GetTransOffsetO()); return true; } @@ -679,7 +679,7 @@ public: if (target->GetTransport()) if (target->GetGUIDTransport()) - WorldDatabase.PQuery("UPDATE creature_transport SET emote=%u WHERE transport_entry=%u AND guid=%u", emote, target->GetTransport()->GetEntry(), target->GetGUIDTransport()); + WorldDatabase.PExecute("UPDATE creature_transport SET emote=%u WHERE transport_entry=%u AND guid=%u", emote, target->GetTransport()->GetEntry(), target->GetGUIDTransport()); target->SetUInt32Value(UNIT_NPC_EMOTESTATE, emote); -- cgit v1.2.3 From f02d91309495eb467fbd8ece26ce09e5f0f3cd0f Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Date: Thu, 19 Jan 2012 21:09:13 -0300 Subject: Scripts/FoS: * Fixed Bronjahm teleport. * Soulstorm Channel (Visual) will be correctly cast at wip. * Adjusted Magic Bane timer. --- .../Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src/server/scripts') diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp index d444160b8f2..a0d6f04f44c 100644 --- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp @@ -67,6 +67,7 @@ class boss_bronjahm : public CreatureScript { boss_bronjahmAI(Creature* creature) : BossAI(creature, DATA_BRONJAHM) { + DoCast(me, SPELL_SOULSTORM_CHANNEL, true); } void InitializeAI() @@ -82,14 +83,17 @@ class boss_bronjahm : public CreatureScript events.Reset(); events.SetPhase(PHASE_1); events.ScheduleEvent(EVENT_SHADOW_BOLT, 2000); - events.ScheduleEvent(EVENT_MAGIC_BANE, urand(8000, 15000)); + events.ScheduleEvent(EVENT_MAGIC_BANE, urand(8000, 20000)); events.ScheduleEvent(EVENT_CORRUPT_SOUL, urand(25000, 35000), 0, PHASE_1); - me->CastSpell(me, SPELL_SOULSTORM_CHANNEL, true); - instance->SetBossState(DATA_BRONJAHM, NOT_STARTED); } + void JustReachedHome() + { + DoCast(me, SPELL_SOULSTORM_CHANNEL, true); + } + void EnterCombat(Unit* /*who*/) { DoScriptText(SAY_AGGRO, me); @@ -118,7 +122,7 @@ class boss_bronjahm : public CreatureScript events.SetPhase(PHASE_2); DoCast(me, SPELL_TELEPORT); events.ScheduleEvent(EVENT_FEAR, urand(12000, 16000), 0, PHASE_2); - events.ScheduleEvent(EVENT_SOULSTORM, 700, 0, PHASE_2); + events.ScheduleEvent(EVENT_SOULSTORM, 100, 0, PHASE_2); } } @@ -147,7 +151,7 @@ class boss_bronjahm : public CreatureScript { case EVENT_MAGIC_BANE: DoCastVictim(SPELL_MAGIC_S_BANE); - events.ScheduleEvent(EVENT_MAGIC_BANE, urand(8000, 15000)); + events.ScheduleEvent(EVENT_MAGIC_BANE, urand(8000, 20000)); break; case EVENT_SHADOW_BOLT: if (!me->IsWithinMeleeRange(me->getVictim())) -- cgit v1.2.3 From 53c48c774a007e2a4d60bf8e9a6ba90065645600 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Date: Fri, 20 Jan 2012 01:55:55 -0300 Subject: Scripts/UK: Adjusted Ingvar the Plunderer's spell timers (Shadow Axe is still missing), sniffs have been used as source. --- .../UtgardeKeep/boss_ingvar_the_plunderer.cpp | 135 +++++++++++---------- 1 file changed, 74 insertions(+), 61 deletions(-) (limited to 'src/server/scripts') 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 ea84502c16d..c2b1699bf5b 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 @@ -45,16 +45,32 @@ enum Creatures MOB_INGVAR_UNDEAD = 23980, }; +enum Events +{ + EVENT_CLEAVE = 1, + EVENT_SMASH, + EVENT_STAGGERING_ROAR, + EVENT_ENRAGE, + + EVENT_DARK_SMASH, + EVENT_DREADFUL_ROAR, + EVENT_WOE_STRIKE, + EVENT_SHADOW_AXE +}; + +enum Phases +{ + PHASE_HUMAN = 1, + PHASE_UNDEAD, +}; + enum Spells { //Ingvar Spells human form SPELL_CLEAVE = 42724, SPELL_SMASH = 42669, - H_SPELL_SMASH = 59706, SPELL_STAGGERING_ROAR = 42708, - H_SPELL_STAGGERING_ROAR = 59708, SPELL_ENRAGE = 42705, - H_SPELL_ENRAGE = 59707, SPELL_INGVAR_FEIGN_DEATH = 42795, SPELL_SUMMON_BANSHEE = 42912, @@ -63,9 +79,7 @@ enum Spells //Ingvar Spells undead form SPELL_DARK_SMASH = 42723, SPELL_DREADFUL_ROAR = 42729, - H_SPELL_DREADFUL_ROAR = 59734, SPELL_WOE_STRIKE = 42730, - H_SPELL_WOE_STRIKE = 59735, ENTRY_THROW_TARGET = 23996, SPELL_SHADOW_AXE_SUMMON = 42749 @@ -110,10 +124,18 @@ public: me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); me->SetStandState(UNIT_STAND_STATE_STAND); - uiCleaveTimer = 2000; - uiSmashTimer = 5000; - uiEnrageTimer = 10000; - uiRoarTimer = 15000; + events.Reset(); + events.SetPhase(PHASE_HUMAN); + + events.ScheduleEvent(EVENT_CLEAVE, urand(6,12)*IN_MILLISECONDS, 0, PHASE_HUMAN); + events.ScheduleEvent(EVENT_STAGGERING_ROAR, urand(18,21)*IN_MILLISECONDS, 0, PHASE_HUMAN); + events.ScheduleEvent(EVENT_ENRAGE, urand(7,14)*IN_MILLISECONDS, 0, PHASE_HUMAN); + events.ScheduleEvent(EVENT_SMASH, urand(12,17)*IN_MILLISECONDS, 0, PHASE_HUMAN); + + events.ScheduleEvent(EVENT_DARK_SMASH, urand(14,22)*IN_MILLISECONDS, 0, PHASE_UNDEAD); + events.ScheduleEvent(EVENT_DREADFUL_ROAR, urand(18,21)*IN_MILLISECONDS, 0, PHASE_UNDEAD); + events.ScheduleEvent(EVENT_WOE_STRIKE, urand(10,14)*IN_MILLISECONDS, 0, PHASE_UNDEAD); + events.ScheduleEvent(EVENT_SHADOW_AXE, 30*IN_MILLISECONDS, 0, PHASE_UNDEAD); uiSpawnResTimer = 3000; @@ -138,6 +160,7 @@ public: bEventInProgress = true; bIsUndead = true; + events.SetPhase(PHASE_UNDEAD); DoScriptText(YELL_DEAD_1, me); } @@ -208,70 +231,60 @@ public: return; } - if (uiCleaveTimer <= diff) - { - if (!me->HasUnitState(UNIT_STAT_CASTING)) - { - if (bIsUndead) - DoCast(me->getVictim(), SPELL_WOE_STRIKE); - else - DoCast(me->getVictim(), SPELL_CLEAVE); - uiCleaveTimer = rand()%5000 + 2000; - } - } else uiCleaveTimer -= diff; + events.Update(diff); - if (uiSmashTimer <= diff) - { - if (!me->HasUnitState(UNIT_STAT_CASTING)) - { - if (bIsUndead) - DoCast(me->getVictim(), SPELL_DARK_SMASH); - else - DoCast(me->getVictim(), SPELL_SMASH); - uiSmashTimer = 10000; - } - } else uiSmashTimer -= diff; + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; - if (!bIsUndead) + while (uint32 eventId = events.ExecuteEvent()) { - if (uiEnrageTimer <= diff) + switch (eventId) { - DoCast(me, SPELL_ENRAGE); - uiEnrageTimer = 10000; - } else uiEnrageTimer -= diff; - } else // In Undead form used to summon weapon - { - if (uiEnrageTimer <= diff) - { - if (!me->HasUnitState(UNIT_STAT_CASTING)) - { - // Spawn target for Axe - Unit* target = SelectTarget(SELECT_TARGET_TOPAGGRO, 1); - if (target) + // PHASE ONE + case EVENT_CLEAVE: + DoCastVictim(SPELL_CLEAVE); + events.ScheduleEvent(EVENT_CLEAVE, urand(6,12)*IN_MILLISECONDS, 0, PHASE_HUMAN); + break; + case EVENT_STAGGERING_ROAR: + DoCast(me, SPELL_STAGGERING_ROAR); + events.ScheduleEvent(EVENT_STAGGERING_ROAR, urand(18,21)*IN_MILLISECONDS, 0, PHASE_HUMAN); + break; + case EVENT_ENRAGE: + DoCast(me, SPELL_ENRAGE); + events.ScheduleEvent(EVENT_ENRAGE, urand(7,14)*IN_MILLISECONDS, 0, PHASE_HUMAN); + break; + case EVENT_SMASH: + DoCastVictim(SPELL_SMASH); + events.ScheduleEvent(EVENT_SMASH, urand(12,17)*IN_MILLISECONDS, 0, PHASE_HUMAN); + break; + // PHASE TWO + case EVENT_DARK_SMASH: + DoCastVictim(SPELL_DARK_SMASH); + events.ScheduleEvent(EVENT_DARK_SMASH, urand(14,22)*IN_MILLISECONDS, 0, PHASE_UNDEAD); + break; + case EVENT_DREADFUL_ROAR: + DoCast(me, SPELL_DREADFUL_ROAR); + events.ScheduleEvent(EVENT_DREADFUL_ROAR, urand(18,21)*IN_MILLISECONDS, 0, PHASE_UNDEAD); + break; + case EVENT_WOE_STRIKE: + DoCastVictim(SPELL_WOE_STRIKE); + events.ScheduleEvent(EVENT_WOE_STRIKE, urand(10,14)*IN_MILLISECONDS, 0, PHASE_UNDEAD); + break; + case EVENT_SHADOW_AXE: + if (Unit* target = SelectTarget(SELECT_TARGET_TOPAGGRO, 1)) { me->SummonCreature(ENTRY_THROW_TARGET, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 2000); - DoCast(me, SPELL_SHADOW_AXE_SUMMON); } - uiEnrageTimer = 30000; - } - } else uiEnrageTimer -= diff; - } - - if (uiRoarTimer <= diff) - { - if (!me->HasUnitState(UNIT_STAT_CASTING)) - { - if (bIsUndead) - DoCast(me, SPELL_DREADFUL_ROAR); - else - DoCast(me, SPELL_STAGGERING_ROAR); - uiRoarTimer = 10000; + events.ScheduleEvent(EVENT_SHADOW_AXE, 30*IN_MILLISECONDS, 0, PHASE_UNDEAD); + break; } - } else uiRoarTimer -= diff; + } DoMeleeAttackIfReady(); } + private: + EventMap events; }; }; -- cgit v1.2.3 From e336c6ff57d751d4e395eb6c0bad3c9066765199 Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Date: Fri, 20 Jan 2012 02:28:09 -0300 Subject: Scripts/FoS: Fixed visual bug when Devourer of Souls casts Wailing Souls. fixed #1692 --- .../Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/server/scripts') diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp index 8180a686e0e..fb39019fb84 100644 --- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp @@ -306,6 +306,7 @@ class boss_devourer_of_souls : public CreatureScript if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) { me->SetOrientation(me->GetAngle(target)); + me->SendMovementFlagUpdate(); DoCast(me, SPELL_WAILING_SOULS_BEAM); } @@ -332,6 +333,7 @@ class boss_devourer_of_souls : public CreatureScript case EVENT_WAILING_SOULS_TICK: beamAngle += beamAngleDiff; me->SetOrientation(beamAngle); + me->SendMovementFlagUpdate(); me->StopMoving(); DoCast(me, SPELL_WAILING_SOULS); -- cgit v1.2.3 From 19f8cc26b9cae894469263125fdb5342fe7a264d Mon Sep 17 00:00:00 2001 From: Manuel Carrasco Date: Fri, 20 Jan 2012 13:08:41 -0300 Subject: Scripts/UK: Removed unused variables, thanks to Vincent-Michael. --- .../UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'src/server/scripts') 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 c2b1699bf5b..1ab95c53500 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 @@ -18,7 +18,7 @@ /* ScriptData SDName: Boss_Ingvar_The_Plunderer SD%Complete: 95 -SDComment: Some Problems with Annhylde Movement, Blizzlike Timers +SDComment: Some Problems with Annhylde Movement, Blizzlike Timers (just shadow axe summon needs a new timer) SDCategory: Udgarde Keep EndScriptData */ @@ -97,9 +97,9 @@ public: struct boss_ingvar_the_plundererAI : public ScriptedAI { - boss_ingvar_the_plundererAI(Creature* c) : ScriptedAI(c) + boss_ingvar_the_plundererAI(Creature* creature) : ScriptedAI(creature) { - instance = c->GetInstanceScript(); + instance = creature->GetInstanceScript(); } InstanceScript* instance; @@ -107,10 +107,6 @@ public: bool bIsUndead; bool bEventInProgress; - uint32 uiCleaveTimer; - uint32 uiSmashTimer; - uint32 uiEnrageTimer; - uint32 uiRoarTimer; uint32 uiSpawnResTimer; void Reset() -- cgit v1.2.3 From 3d4f55723c79e828c8fbe7a5c2f1a31a26036e14 Mon Sep 17 00:00:00 2001 From: Subv2112 Date: Sun, 22 Jan 2012 20:36:01 -0500 Subject: Core/SAI: Linked events should be executed after the event that linked them is executed. Core/SAI: Allow SMART_EVENT_GO_STATE_CHANGED to use ActionInvoker target Signed-off-by: Subv2112 --- src/server/game/AI/CoreAI/GameObjectAI.h | 2 +- src/server/game/AI/SmartScripts/SmartAI.cpp | 4 +- src/server/game/AI/SmartScripts/SmartAI.h | 2 +- src/server/game/AI/SmartScripts/SmartScript.cpp | 206 ++++++++++----------- src/server/game/Entities/GameObject/GameObject.cpp | 12 +- src/server/game/Entities/GameObject/GameObject.h | 5 +- src/server/game/Entities/Player/Player.cpp | 2 +- .../game/Server/Protocol/Handlers/LootHandler.cpp | 2 +- src/server/game/Spells/SpellEffects.cpp | 2 +- src/server/scripts/Commands/cs_gobject.cpp | 2 +- 10 files changed, 120 insertions(+), 119 deletions(-) (limited to 'src/server/scripts') diff --git a/src/server/game/AI/CoreAI/GameObjectAI.h b/src/server/game/AI/CoreAI/GameObjectAI.h index 501959d67f9..bfdd887de3e 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) { } + virtual void OnStateChanged(uint32 state, Unit* unit) { } }; class NullGameObjectAI : public GameObjectAI diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 01fb936b847..79fe3df7ff7 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -937,9 +937,9 @@ void SmartGameObjectAI::OnGameEvent(bool start, uint16 eventId) GetScript()->ProcessEventsFor(start ? SMART_EVENT_GAME_EVENT_START : SMART_EVENT_GAME_EVENT_END, NULL, eventId); } -void SmartGameObjectAI::OnStateChanged(uint32 state) +void SmartGameObjectAI::OnStateChanged(uint32 state, Unit* unit) { - GetScript()->ProcessEventsFor(SMART_EVENT_GO_STATE_CHANGED, NULL, state); + GetScript()->ProcessEventsFor(SMART_EVENT_GO_STATE_CHANGED, unit, state); } class SmartTrigger : public AreaTriggerScript diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index 297ac88fbb0..0576612a155 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -253,7 +253,7 @@ public: void SetData(uint32 id, uint32 value); void SetScript9(SmartScriptHolder& e, uint32 entry, Unit* invoker); void OnGameEvent(bool start, uint16 eventId); - void OnStateChanged(uint32 state); + void OnStateChanged(uint32 state, Unit* unit); protected: GameObject* const go; diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 08583406127..84ce57b7a13 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -102,15 +102,6 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (unit) mLastInvoker = unit->GetGUID(); - if (e.link && e.link != e.event_id) - { - SmartScriptHolder linked = FindLinkedEvent(e.link); - if (linked.GetActionType() && linked.GetEventType() == SMART_EVENT_LINK) - ProcessEvent(linked, unit, var0, var1, bvar, spell, gob); - else - sLog->outErrorDb("SmartScript::ProcessAction: Entry %d SourceType %u, Event %u, Link Event %u not found or invalid, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.link); - } - if (Unit* tempInvoker = GetLastInvoker()) sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: Invoker: %s (guidlow: %u)", tempInvoker->GetName(), tempInvoker->GetGUIDLow()); @@ -119,7 +110,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_TALK: { if (!me) - return; + break; ObjectList* targets = GetTargets(e, unit); Creature* talker = me; @@ -257,7 +248,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -300,7 +291,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -319,7 +310,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -340,7 +331,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_SET_REACT_STATE: { if (!me) - return; + break; me->SetReactState(ReactStates(e.action.react.state)); sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_SET_REACT_STATE: Creature guidLow %u set reactstate %u", @@ -351,7 +342,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; uint32 emotes[SMART_ACTION_PARAM_COUNT]; emotes[0] = e.action.randomEmote.emote1; @@ -388,7 +379,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_THREAT_ALL_PCT: { if (!me) - return; + break; std::list const& threatList = me->getThreatManager().getThreatList(); for (std::list::const_iterator i = threatList.begin(); i != threatList.end(); ++i) @@ -405,11 +396,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_THREAT_SINGLE_PCT: { if (!me) - return; + break; ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -428,7 +419,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -446,11 +437,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_SEND_CASTCREATUREORGO: { if (!GetBaseObject()) - return; + break; ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -468,11 +459,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_CAST: { if (!me) - return; + break; ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -494,11 +485,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { Unit* tempLastInvoker = GetLastInvoker(); if (!tempLastInvoker) - return; + break; ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -520,7 +511,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -539,7 +530,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -547,7 +538,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { // Activate (*itr)->ToGameObject()->SetLootState(GO_READY); - (*itr)->ToGameObject()->UseDoorOrButton(); + (*itr)->ToGameObject()->UseDoorOrButton(0, false, unit); sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_ACTIVATE_GOBJECT. Gameobject %u (entry: %u) activated", (*itr)->GetGUIDLow(), (*itr)->GetEntry()); } @@ -560,7 +551,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -579,7 +570,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -598,7 +589,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -617,7 +608,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -635,7 +626,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_AUTO_ATTACK: { if (!IsSmart()) - return; + break; CAST_AI(SmartAI, me->AI())->SetAutoAttack(e.action.autoAttack.attack ? true : false); sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_AUTO_ATTACK: Creature: %u bool on = %u", @@ -645,7 +636,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_ALLOW_COMBAT_MOVEMENT: { if (!IsSmart()) - return; + break; bool move = e.action.combatMove.move ? true : false; CAST_AI(SmartAI, me->AI())->SetCombatMove(move); @@ -656,7 +647,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_SET_EVENT_PHASE: { if (!GetBaseObject()) - return; + break; SetPhase(e.action.setEventPhase.phase); sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_SET_EVENT_PHASE: Creature %u set event phase %u", @@ -666,7 +657,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_INC_EVENT_PHASE: { if (!GetBaseObject()) - return; + break; IncPhase(e.action.incEventPhase.inc); DecPhase(e.action.incEventPhase.dec); @@ -677,7 +668,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_EVADE: { if (!me) - return; + break; me->AI()->EnterEvadeMode(); sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_EVADE: Creature %u EnterEvadeMode", me->GetGUIDLow()); @@ -686,7 +677,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_FLEE_FOR_ASSIST: { if (!me) - return; + break; me->DoFleeToGetAssistance(); if (e.action.flee.withEmote) @@ -707,11 +698,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_CALL_CASTEDCREATUREORGO: { if (!GetBaseObject()) - return; + break; ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -730,7 +721,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -748,11 +739,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_FOLLOW: { if (!IsSmart()) - return; + break; ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -771,7 +762,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_RANDOM_PHASE: { if (!GetBaseObject()) - return; + break; uint32 phases[SMART_ACTION_PARAM_COUNT]; phases[0] = e.action.randomPhase.phase1; @@ -800,7 +791,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_RANDOM_PHASE_RANGE: { if (!GetBaseObject()) - return; + break; uint32 phase = urand(e.action.randomPhaseRange.phaseMin, e.action.randomPhaseRange.phaseMax); SetPhase(phase); @@ -820,7 +811,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -849,13 +840,13 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u obj = unit; if (!obj) - return; + break; InstanceScript* instance = obj->GetInstanceScript(); if (!instance) { sLog->outErrorDb("SmartScript: Event %u attempt to set instance data without instance script. EntryOrGuid %d", e.GetEventType(), e.entryOrGuid); - return; + break; } instance->SetData(e.action.setInstanceData.field, e.action.setInstanceData.data); @@ -870,18 +861,18 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u obj = unit; if (!obj) - return; + break; InstanceScript* instance = obj->GetInstanceScript(); if (!instance) { sLog->outErrorDb("SmartScript: Event %u attempt to set instance data without instance script. EntryOrGuid %d", e.GetEventType(), e.entryOrGuid); - return; + break; } ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; instance->SetData64(e.action.setInstanceData64.field, targets->front()->GetGUID()); sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA64: Field: %u, data: "UI64FMTD, @@ -893,7 +884,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_UPDATE_TEMPLATE: { if (!me || me->GetEntry() == e.action.updateTemplate.creature) - return; + break; me->UpdateEntry(e.action.updateTemplate.creature, e.action.updateTemplate.team ? HORDE : ALLIANCE); sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_UPDATE_TEMPLATE: Creature %u, Template: %u, Team: %u", @@ -940,7 +931,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_FORCE_DESPAWN: { if (!IsSmart()) - return; + break; CAST_AI(SmartAI, me->AI())->SetDespawnTime(e.action.forceDespawn.delay + 1);//next tick CAST_AI(SmartAI, me->AI())->StartDespawn(); @@ -956,7 +947,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -986,7 +977,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_SET_INVINCIBILITY_HP_LEVEL: { if (!me) - return; + break; if (e.action.invincHP.percent) mInvinceabilityHpLevel = me->CountPctFromMaxHealth(e.action.invincHP.percent); @@ -998,7 +989,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -1014,7 +1005,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_MOVE_FORWARD: { if (!me) - return; + break; float x, y, z; me->GetClosePoint(x, y, z, me->GetObjectSize() / 3, (float)e.action.moveRandom.distance); @@ -1036,11 +1027,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_ATTACK_START: { if (!me) - return; + break; ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -1075,7 +1066,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } if (e.GetTargetType() != SMART_TARGET_POSITION) - return; + break; if (Creature* summon = GetBaseObject()->SummonCreature(e.action.summonCreature.creature, e.target.x, e.target.y, e.target.z, e.target.o, (TempSummonType)e.action.summonCreature.type, e.action.summonCreature.duration)) if (unit && e.action.summonCreature.attackInvoker) @@ -1085,7 +1076,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_SUMMON_GO: { if (!GetBaseObject()) - return; + break; float x, y, z, o; ObjectList* targets = GetTargets(e, unit); @@ -1104,7 +1095,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } if (e.GetTargetType() != SMART_TARGET_POSITION) - return; + break; GetBaseObject()->SummonGameObject(e.action.summonGO.entry, e.target.x, e.target.y, e.target.z, e.target.o, 0, 0, 0, 0, e.action.summonGO.despawnTime); break; @@ -1113,7 +1104,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -1135,7 +1126,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -1152,7 +1143,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -1182,7 +1173,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -1198,7 +1189,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_SET_FLY: { if (!IsSmart()) - return; + break; CAST_AI(SmartAI, me->AI())->SetFly(e.action.setFly.fly ? true : false); break; @@ -1206,7 +1197,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_SET_RUN: { if (!IsSmart()) - return; + break; CAST_AI(SmartAI, me->AI())->SetRun(e.action.setRun.run ? true : false); break; @@ -1214,7 +1205,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_SET_SWIM: { if (!IsSmart()) - return; + break; CAST_AI(SmartAI, me->AI())->SetSwim(e.action.setSwim.swim ? true : false); break; @@ -1222,7 +1213,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_WP_START: { if (!IsSmart()) - return; + break; bool run = e.action.wpStart.run ? true : false; uint32 entry = e.action.wpStart.pathID; @@ -1241,7 +1232,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_WP_PAUSE: { if (!IsSmart()) - return; + break; uint32 delay = e.action.wpPause.delay; CAST_AI(SmartAI, me->AI())->PausePath(delay, e.GetEventType() == SMART_EVENT_WAYPOINT_REACHED ? false : true); @@ -1250,7 +1241,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_WP_STOP: { if (!IsSmart()) - return; + break; uint32 DespawnTime = e.action.wpStop.despawnTime; uint32 quest = e.action.wpStop.quest; @@ -1261,7 +1252,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_WP_RESUME: { if (!IsSmart()) - return; + break; CAST_AI(SmartAI, me->AI())->ResumePath(); break; @@ -1269,7 +1260,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_SET_ORIENTATION: { if (!me) - return; + break; ObjectList* targets = GetTargets(e, unit); if (e.GetTargetType() == SMART_TARGET_SELF) @@ -1286,7 +1277,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -1302,7 +1293,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_MOVE_TO_POS: { if (!IsSmart()) - return; + break; WorldObject* target = NULL; @@ -1314,7 +1305,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; target = targets->front(); } @@ -1329,7 +1320,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -1346,7 +1337,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) if (IsPlayer(*itr)) @@ -1359,7 +1350,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -1436,7 +1427,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -1476,7 +1467,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (e.GetTargetType() == SMART_TARGET_NONE) { sLog->outErrorDb("SmartScript: Entry %d SourceType %u Event %u Action %u is using TARGET_NONE(0) for Script9 target. Please correct target_type in database.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType()); - return; + break; } ObjectList* targets = GetTargets(e, unit); @@ -1504,7 +1495,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) if (IsUnit(*itr)) @@ -1517,7 +1508,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) if (IsUnit(*itr)) @@ -1530,7 +1521,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) if (IsUnit(*itr)) @@ -1543,13 +1534,13 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* casters = GetTargets(CreateEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, 0, 0, SMART_ACTION_NONE, 0, 0, 0, 0, 0, 0, (SMARTAI_TARGETS)e.action.cast.targetType, e.action.cast.targetParam1, e.action.cast.targetParam2, e.action.cast.targetParam3, 0), unit); if (!casters) - return; + break; ObjectList* targets = GetTargets(e, unit); if (!targets) { delete casters; // casters already validated, delete now - return; + break; } for (ObjectList::const_iterator itr = casters->begin(); itr != casters->end(); ++itr) @@ -1593,7 +1584,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (e.GetTargetType() == SMART_TARGET_NONE) { sLog->outErrorDb("SmartScript: Entry %d SourceType %u Event %u Action %u is using TARGET_NONE(0) for Script9 target. Please correct target_type in database.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType()); - return; + break; } ObjectList* targets = GetTargets(e, unit); @@ -1623,7 +1614,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (e.GetTargetType() == SMART_TARGET_NONE) { sLog->outErrorDb("SmartScript: Entry %d SourceType %u Event %u Action %u is using TARGET_NONE(0) for Script9 target. Please correct target_type in database.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType()); - return; + break; } ObjectList* targets = GetTargets(e, unit); @@ -1651,7 +1642,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) if (IsPlayer(*itr)) @@ -1664,7 +1655,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -1684,7 +1675,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) if (IsUnit(*itr)) (*itr)->ToUnit()->SetByteFlag(UNIT_FIELD_BYTES_1, 0, e.action.setunitByte.byte1); @@ -1696,7 +1687,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) if (IsUnit(*itr)) @@ -1709,7 +1700,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) if (IsUnit(*itr)) @@ -1722,7 +1713,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) if (IsGameObject(*itr)) @@ -1735,7 +1726,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) if (IsUnit(*itr)) @@ -1748,7 +1739,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) if (IsUnit(*itr)) @@ -1761,7 +1752,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) if (IsUnit(*itr)) @@ -1773,7 +1764,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_JUMP_TO_POS: { if (!me) - return; + break; me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveJump(e.target.x, e.target.y, e.target.z, (float)e.action.jump.speedxy, (float)e.action.jump.speedz); @@ -1785,7 +1776,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) if (IsGameObject(*itr)) @@ -1798,7 +1789,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) { @@ -1824,14 +1815,14 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u case SMART_ACTION_SEND_GOSSIP_MENU: { if (!GetBaseObject()) - return; + break; sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_SEND_GOSSIP_MENU: gossipMenuId %d, gossipNpcTextId %d", e.action.sendGossipMenu.gossipMenuId, e.action.sendGossipMenu.gossipNpcTextId); ObjectList* targets = GetTargets(e, unit); if (!targets) - return; + break; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) if (Player* player = (*itr)->ToPlayer()) @@ -1851,6 +1842,15 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u sLog->outErrorDb("SmartScript::ProcessAction: Unhandled Action type %u", e.GetActionType()); break; } + + if (e.link && e.link != e.event_id) + { + SmartScriptHolder linked = FindLinkedEvent(e.link); + if (linked.GetActionType() && linked.GetEventType() == SMART_EVENT_LINK) + ProcessEvent(linked, unit, var0, var1, bvar, spell, gob); + else + sLog->outErrorDb("SmartScript::ProcessAction: Entry %d SourceType %u, Event %u, Link Event %u not found or invalid, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.link); + } } void SmartScript::InstallTemplate(SmartScriptHolder const& e) diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index fd094938da8..3548ef3bc63 100755 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -974,7 +974,7 @@ void GameObject::ResetDoorOrButton() m_cooldownTime = 0; } -void GameObject::UseDoorOrButton(uint32 time_to_restore, bool alternative /* = false */) +void GameObject::UseDoorOrButton(uint32 time_to_restore, bool alternative /* = false */, Unit* user /*=NULL*/) { if (m_lootState != GO_READY) return; @@ -983,7 +983,7 @@ void GameObject::UseDoorOrButton(uint32 time_to_restore, bool alternative /* = f time_to_restore = GetGOInfo()->GetAutoCloseTime(); SwitchDoorOrButton(true, alternative); - SetLootState(GO_ACTIVATED); + SetLootState(GO_ACTIVATED, user); m_cooldownTime = time(NULL) + time_to_restore; } @@ -1053,7 +1053,7 @@ void GameObject::Use(Unit* user) case GAMEOBJECT_TYPE_DOOR: //0 case GAMEOBJECT_TYPE_BUTTON: //1 //doors/buttons never really despawn, only reset to default state/flags - UseDoorOrButton(); + UseDoorOrButton(0, false, user); // activate script GetMap()->ScriptsStart(sGameObjectScripts, GetDBTableGUIDLow(), spellCaster, this); @@ -1206,7 +1206,7 @@ void GameObject::Use(Unit* user) TriggeringLinkedGameObject(trapEntry, user); SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); - SetLootState(GO_ACTIVATED); + SetLootState(GO_ACTIVATED, user); // this appear to be ok, however others exist in addition to this that should have custom (ex: 190510, 188692, 187389) if (info->goober.customAnim) @@ -1865,8 +1865,8 @@ void GameObject::SetDestructibleState(GameObjectDestructibleState state, Player* } } -void GameObject::SetLootState(LootState s) +void GameObject::SetLootState(LootState s, Unit* unit) { m_lootState = s; - AI()->OnStateChanged(s); + AI()->OnStateChanged(s, unit); } diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 9298c5affee..f677d481c33 100755 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -713,7 +713,8 @@ class GameObject : public WorldObject, public GridObject void Use(Unit* user); LootState getLootState() const { return m_lootState; } - void SetLootState(LootState s); + // Note: unit is only used when s = GO_ACTIVATED + void SetLootState(LootState s, Unit* unit = NULL); uint16 GetLootMode() { return m_LootMode; } bool HasLootMode(uint16 lootMode) { return m_LootMode & lootMode; } @@ -747,7 +748,7 @@ class GameObject : public WorldObject, public GridObject bool hasQuest(uint32 quest_id) const; bool hasInvolvedQuest(uint32 quest_id) const; bool ActivateToQuest(Player* target) const; - void UseDoorOrButton(uint32 time_to_restore = 0, bool alternative = false); + void UseDoorOrButton(uint32 time_to_restore = 0, bool alternative = false, Unit* user = NULL); // 0 = use `gameobject`.`spawntimesecs` void ResetDoorOrButton(); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index ce80d7a7af3..00fbab8ceb3 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -8722,7 +8722,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type) } } - go->SetLootState(GO_ACTIVATED); + go->SetLootState(GO_ACTIVATED, this); } if (go->getLootState() == GO_ACTIVATED) diff --git a/src/server/game/Server/Protocol/Handlers/LootHandler.cpp b/src/server/game/Server/Protocol/Handlers/LootHandler.cpp index b17817e196f..6508f08dc22 100755 --- a/src/server/game/Server/Protocol/Handlers/LootHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/LootHandler.cpp @@ -324,7 +324,7 @@ void WorldSession::DoLootRelease(uint64 lguid) else { // not fully looted object - go->SetLootState(GO_ACTIVATED); + go->SetLootState(GO_ACTIVATED, player); // if the round robin player release, reset it. if (player->GetGUID() == loot->roundRobinPlayer) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index eaf5f4e1d31..c3357b99601 100755 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -2750,7 +2750,7 @@ void Spell::SendLoot(uint64 guid, LootType loottype) { case GAMEOBJECT_TYPE_DOOR: case GAMEOBJECT_TYPE_BUTTON: - gameObjTarget->UseDoorOrButton(); + gameObjTarget->UseDoorOrButton(0, false, player); player->GetMap()->ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget); return; diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp index 2fb6c3f0d10..74b8272201b 100644 --- a/src/server/scripts/Commands/cs_gobject.cpp +++ b/src/server/scripts/Commands/cs_gobject.cpp @@ -97,7 +97,7 @@ public: // Activate object->SetLootState(GO_READY); - object->UseDoorOrButton(10000); + object->UseDoorOrButton(10000, false, handler->GetSession()->GetPlayer()); handler->PSendSysMessage("Object activated!"); -- 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/server/scripts') 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/server/scripts') 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/server/scripts') 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/server/scripts') 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 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/server/scripts') 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/server/scripts') 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/server/scripts') 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/server/scripts') 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/server/scripts') 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/server/scripts') 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/server/scripts') 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/server/scripts') 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/server/scripts') 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/server/scripts') 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 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/server/scripts') 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 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/server/scripts') 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 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/server/scripts') 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/server/scripts') 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/server/scripts') 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 From 50a6ec015eb1cfd7e55129026bd1e3e34d9603a0 Mon Sep 17 00:00:00 2001 From: Souler Date: Sun, 29 Jan 2012 03:49:55 +0100 Subject: Scripts/Spells: Fixed behaviour of Elune's Candle, Rockets and Rocket Clusters. Scripts/NPC: Implemented AI for Omen and his summoning ritual. --- sql/updates/world/2012_01_28_01_world_misc.sql | 102 +++++++++ src/server/scripts/Kalimdor/moonglade.cpp | 146 ++++++++++++- src/server/scripts/Spells/spell_generic.cpp | 70 ++++++ src/server/scripts/World/npcs_special.cpp | 281 +++++++++++++++++++++++++ 4 files changed, 598 insertions(+), 1 deletion(-) create mode 100644 sql/updates/world/2012_01_28_01_world_misc.sql (limited to 'src/server/scripts') diff --git a/sql/updates/world/2012_01_28_01_world_misc.sql b/sql/updates/world/2012_01_28_01_world_misc.sql new file mode 100644 index 00000000000..c6c90dd9e0d --- /dev/null +++ b/sql/updates/world/2012_01_28_01_world_misc.sql @@ -0,0 +1,102 @@ +DELETE FROM `spell_script_names` WHERE `spell_id` IN (26374); +INSERT INTO `spell_script_names`(`spell_id`,`ScriptName`) VALUES +(26374,'spell_gen_elune_candle'); + +-- Set Gigant Spotlight as not selectable +UPDATE `creature_template` SET `unit_flags`=33554432 WHERE `entry`=15902; + +DELETE FROM `creature_template_addon` WHERE (`entry`IN(15902,15466)); +INSERT INTO `creature_template_addon`(`entry`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES +(15466,0,0,0,0,0,17327), -- Add spirit particles to Omen minions +(15902,0,0,0,0,0,50236); -- Add Spotlight aura to Gigant Spotlight (ummoned by 26392 on Omen's death) + +UPDATE `creature_template` SET `ScriptName`='npc_giant_spotlight' WHERE `entry`=15902; +UPDATE `creature_template` SET `RegenHealth`=0,`ScriptName`='npc_omen' WHERE `entry`=15467; +UPDATE `creature_template` SET `ScriptName`='npc_firework',`AIName`='',`faction_A`=35,`faction_H`=35,`unit_flags`=33555200 WHERE `entry` IN (15879,15880,15881,15882,15883,15884,15885,15886,15887,15888,15889,15890,15872,15873,15874,15875,15876,15877,15911,15912,15913,15914,15915,15916,15918); +-- Cleanup EventAI and SmartAI +DELETE FROM `creature_ai_scripts` WHERE `creature_id` IN (15879,15880,15881,15882,15883,15884,15885,15886,15887,15888,15889,15890,15872,15873,15874,15875,15876,15877,15911,15912,15913,15914,15915,15916,15918); +DELETE FROM `smart_scripts` WHERE `source_type`=0 AND `entryorguid` IN (15879,15880,15881,15882,15883,15884,15885,15886,15887,15888,15889,15890,15872,15873,15874,15875,15876,15877,15911,15912,15913,15914,15915,15916,15918); + +-- Update al targeting stuff for Fireworks and Rocket clusters +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry` IN (26294,26295,26333,26334,26336,26337,26338,26488,26490,26517,26521,26344,26347,26345,26348,26349,26351,26352,26354,26355,26356); +INSERT INTO `conditions`(`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES +-- Targeting Firework Launcher +(13,0,26294,0,18,0,180771,0,0,'',"Small White Rocket target Firework Launcher"), +(13,0,26294,0,18,0,180850,0,0,'',"Small White Rocket target Firework Launcher"), +(13,0,26294,0,18,0,180868,0,0,'',"Small White Rocket target Firework Launcher"), +(13,0,26295,0,18,0,180771,0,0,'',"Small Yellow Rocket target Firework Launcher"), +(13,0,26295,0,18,0,180850,0,0,'',"Small Yellow Rocket target Firework Launcher"), +(13,0,26295,0,18,0,180868,0,0,'',"Small Yellow Rocket target Firework Launcher"), +(13,0,26333,0,18,0,180771,0,0,'',"Large Blue Rocket target Firework Launcher"), +(13,0,26333,0,18,0,180850,0,0,'',"Large Blue Rocket target Firework Launcher"), +(13,0,26333,0,18,0,180868,0,0,'',"Large Blue Rocket target Firework Launcher"), +(13,0,26334,0,18,0,180771,0,0,'',"Large Green Rocket target Firework Launcher"), +(13,0,26334,0,18,0,180850,0,0,'',"Large Green Rocket target Firework Launcher"), +(13,0,26334,0,18,0,180868,0,0,'',"Large Green Rocket target Firework Launcher"), +(13,0,26336,0,18,0,180771,0,0,'',"Large Red Rocket target Firework Launcher"), +(13,0,26336,0,18,0,180850,0,0,'',"Large Red Rocket target Firework Launcher"), +(13,0,26336,0,18,0,180868,0,0,'',"Large Red Rocket target Firework Launcher"), +(13,0,26337,0,18,0,180771,0,0,'',"Large White Rocket target Firework Launcher"), +(13,0,26337,0,18,0,180850,0,0,'',"Large White Rocket target Firework Launcher"), +(13,0,26337,0,18,0,180868,0,0,'',"Large White Rocket target Firework Launcher"), +(13,0,26338,0,18,0,180771,0,0,'',"Large Yellow Rocket target Firework Launcher"), +(13,0,26338,0,18,0,180850,0,0,'',"Large Yellow Rocket target Firework Launcher"), +(13,0,26338,0,18,0,180868,0,0,'',"Large Yellow Rocket target Firework Launcher"), +-- Targeting Cluster Launcher +(13,0,26488,0,18,0,180772,0,0,'',"Large Blue Rocket Cluster target Cluster Launcher"), +(13,0,26488,0,18,0,180859,0,0,'',"Large Blue Rocket Cluster target Cluster Launcher"), +(13,0,26488,0,18,0,180869,0,0,'',"Large Blue Rocket Cluster target Cluster Launcher"), +(13,0,26488,0,18,0,180874,0,0,'',"Large Blue Rocket Cluster target Cluster Launcher"), +(13,0,26490,0,18,0,180772,0,0,'',"Large Green Rocket Cluster target Cluster Launcher"), +(13,0,26490,0,18,0,180859,0,0,'',"Large Green Rocket Cluster target Cluster Launcher"), +(13,0,26490,0,18,0,180869,0,0,'',"Large Green Rocket Cluster target Cluster Launcher"), +(13,0,26490,0,18,0,180874,0,0,'',"Large Green Rocket Cluster target Cluster Launcher"), +(13,0,26517,0,18,0,180772,0,0,'',"Large Red Rocket Cluster target Cluster Launcher"), +(13,0,26517,0,18,0,180859,0,0,'',"Large Red Rocket Cluster target Cluster Launcher"), +(13,0,26517,0,18,0,180869,0,0,'',"Large Red Rocket Cluster target Cluster Launcher"), +(13,0,26517,0,18,0,180874,0,0,'',"Large Red Rocket Cluster target Cluster Launcher"), +(13,0,26521,0,18,0,180772,0,0,'',"Lucky Lunar rocket Cluster target Cluster Launcher"), +(13,0,26521,0,18,0,180859,0,0,'',"Lucky Lunar rocket Cluster target Cluster Launcher"), +(13,0,26521,0,18,0,180869,0,0,'',"Lucky Lunar rocket Cluster target Cluster Launcher"), +(13,0,26521,0,18,0,180874,0,0,'',"Lucky Lunar rocket Cluster target Cluster Launcher"), +-- Targeting Firework Launcher (Again) +(13,0,26347,0,18,0,180771,0,0,'',"Rocket, RED target Firework Launcher"), +(13,0,26347,0,18,0,180850,0,0,'',"Rocket, RED target Firework Launcher"), +(13,0,26347,0,18,0,180868,0,0,'',"Rocket, RED target Firework Launcher"), +(13,0,26344,0,18,0,180771,0,0,'',"Rocket, BLUE target Firework Launcher"), +(13,0,26344,0,18,0,180850,0,0,'',"Rocket, BLUE target Firework Launcher"), +(13,0,26344,0,18,0,180868,0,0,'',"Rocket, BLUE target Firework Launcher"), +(13,0,26345,0,18,0,180771,0,0,'',"Rocket, GREEEN target Firework Launcher"), +(13,0,26345,0,18,0,180850,0,0,'',"Rocket, GREEEN target Firework Launcher"), +(13,0,26345,0,18,0,180868,0,0,'',"Rocket, GREEEN target Firework Launcher"), +(13,0,26348,0,18,0,180771,0,0,'',"Rocket, WHITE target Firework Launcher"), +(13,0,26348,0,18,0,180850,0,0,'',"Rocket, WHITE target Firework Launcher"), +(13,0,26348,0,18,0,180868,0,0,'',"Rocket, WHITE target Firework Launcher"), +(13,0,26349,0,18,0,180771,0,0,'',"Rocket, YELLOW target Firework Launcher"), +(13,0,26349,0,18,0,180850,0,0,'',"Rocket, YELLOW target Firework Launcher"), +(13,0,26349,0,18,0,180868,0,0,'',"Rocket, YELLOW target Firework Launcher"), +(13,0,26351,0,18,0,180771,0,0,'',"Rocket, BLUE BIG target Firework Launcher"), +(13,0,26351,0,18,0,180850,0,0,'',"Rocket, BLUE BIG target Firework Launcher"), +(13,0,26351,0,18,0,180868,0,0,'',"Rocket, BLUE BIG target Firework Launcher"), +(13,0,26352,0,18,0,180771,0,0,'',"Rocket, GREEN BIG target Firework Launcher"), +(13,0,26352,0,18,0,180850,0,0,'',"Rocket, GREEN BIG target Firework Launcher"), +(13,0,26352,0,18,0,180868,0,0,'',"Rocket, GREEN BIG target Firework Launcher"), +(13,0,26354,0,18,0,180771,0,0,'',"Rocket, RED BIG target Firework Launcher"), +(13,0,26354,0,18,0,180850,0,0,'',"Rocket, RED BIG target Firework Launcher"), +(13,0,26354,0,18,0,180868,0,0,'',"Rocket, RED BIG target Firework Launcher"), +(13,0,26355,0,18,0,180771,0,0,'',"Rocket, WHITE BIG target Firework Launcher"), +(13,0,26355,0,18,0,180850,0,0,'',"Rocket, WHITE BIG target Firework Launcher"), +(13,0,26355,0,18,0,180868,0,0,'',"Rocket, WHITE BIG target Firework Launcher"), +(13,0,26356,0,18,0,180771,0,0,'',"Rocket, YELLOW BIG target Firework Launcher"), +(13,0,26356,0,18,0,180850,0,0,'',"Rocket, YELLOW BIG target Firework Launcher"), +(13,0,26356,0,18,0,180868,0,0,'',"Rocket, YELLOW BIG target Firework Launcher"); + +UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`=15466; +DELETE FROM `smart_scripts` WHERE (`entryorguid`=15466 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 +(15466,0,0,0,8,0,100,0,26636,0,8000,9000,11,25495,0,0,0,0,0,1,0,0,0,0,0,0,0,"Minion of Omen - Cast Firework Dazzled when hitted by Elune's Candle firework"); + +-- Cast quest credit spell when getting Elune's Blessing buff +DELETE FROM `spell_scripts` WHERE `id`=26393; +INSERT INTO `spell_scripts`(`id`,`effIndex`,`delay`,`command`,`datalong`,`datalong2`,`dataint`,`x`,`y`,`z`,`o`) VALUES +(26393,1,0,15,26394,2,0,0,0,0,0); \ No newline at end of file diff --git a/src/server/scripts/Kalimdor/moonglade.cpp b/src/server/scripts/Kalimdor/moonglade.cpp index 595a72ec2bf..f9e4bce34d0 100644 --- a/src/server/scripts/Kalimdor/moonglade.cpp +++ b/src/server/scripts/Kalimdor/moonglade.cpp @@ -573,9 +573,151 @@ public: }; /*#### -# +# npc_omen ####*/ +enum Omen +{ + NPC_OMEN = 15467, + + SPELL_OMEN_CLEAVE = 15284, + SPELL_OMEN_STARFALL = 26540, + SPELL_OMEN_SUMMON_SPOTLIGHT = 26392, + SPELL_ELUNE_CANDLE = 26374, + + GO_ELUNE_TRAP_1 = 180876, + GO_ELUNE_TRAP_2 = 180877, + + EVENT_CAST_CLEAVE = 1, + EVENT_CAST_STARFALL = 2, + EVENT_DESPAWN = 3, +}; + +class npc_omen : public CreatureScript +{ +public: + npc_omen() : CreatureScript("npc_omen") { } + + struct npc_omenAI : public ScriptedAI + { + npc_omenAI(Creature* creature) : ScriptedAI(creature) + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + me->GetMotionMaster()->MovePoint(1, 7549.977f, -2855.137f, 456.9678f); + } + + EventMap events; + + void MovementInform(uint32 type, uint32 pointId) + { + if (type != POINT_MOTION_TYPE) + return; + + if (pointId == 1) + { + me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + if (Player* player = me->SelectNearestPlayer(40.0f)) + AttackStart(player); + } + } + + void EnterCombat(Unit* /*attacker*/) + { + events.Reset(); + events.ScheduleEvent(EVENT_CAST_CLEAVE, urand(3000, 5000)); + events.ScheduleEvent(EVENT_CAST_STARFALL, urand(8000, 10000)); + } + + void JustDied(Unit* /*killer*/) + { + DoCast(SPELL_OMEN_SUMMON_SPOTLIGHT); + } + + void SpellHit(Unit* /*caster*/, const SpellInfo* spell) + { + if (spell->Id == SPELL_ELUNE_CANDLE) + { + if (me->HasAura(SPELL_OMEN_STARFALL)) + me->RemoveAurasDueToSpell(SPELL_OMEN_STARFALL); + + events.RescheduleEvent(EVENT_CAST_STARFALL, urand(14000, 16000)); + } + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + switch (events.ExecuteEvent()) + { + case EVENT_CAST_CLEAVE: + DoCastVictim(SPELL_OMEN_CLEAVE); + events.ScheduleEvent(EVENT_CAST_CLEAVE, urand(8000, 10000)); + break; + case EVENT_CAST_STARFALL: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_OMEN_STARFALL); + events.ScheduleEvent(EVENT_CAST_STARFALL, urand(14000, 16000)); + break; + } + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_omenAI(creature); + } +}; + +class npc_giant_spotlight : public CreatureScript +{ +public: + npc_giant_spotlight() : CreatureScript("npc_giant_spotlight") { } + + struct npc_giant_spotlightAI : public ScriptedAI + { + npc_giant_spotlightAI(Creature* creature) : ScriptedAI(creature) {} + + EventMap events; + + void Reset() + { + events.Reset(); + events.ScheduleEvent(EVENT_DESPAWN, 5*MINUTE*IN_MILLISECONDS); + } + + void UpdateAI(const uint32 diff) + { + events.Update(diff); + + if (events.ExecuteEvent() == EVENT_DESPAWN) + { + if (GameObject* trap = me->FindNearestGameObject(GO_ELUNE_TRAP_1, 5.0f)) + trap->RemoveFromWorld(); + + if (GameObject* trap = me->FindNearestGameObject(GO_ELUNE_TRAP_2, 5.0f)) + trap->RemoveFromWorld(); + + if (Creature* omen = me->FindNearestCreature(NPC_OMEN, 5.0f, false)) + omen->DespawnOrUnsummon(); + + me->DespawnOrUnsummon(); + } + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_giant_spotlightAI(creature); + } +}; + void AddSC_moonglade() { new npc_bunthen_plainswind(); @@ -583,4 +725,6 @@ void AddSC_moonglade() new npc_silva_filnaveth(); new npc_clintar_dreamwalker(); new npc_clintar_spirit(); + new npc_omen(); + new npc_giant_spotlight(); } diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 2b31a50510d..d0307966795 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -412,6 +412,75 @@ class spell_gen_leeching_swarm : public SpellScriptLoader } }; +enum EluneCandle +{ + NPC_OMEN = 15467, + + SPELL_ELUNE_CANDLE_OMEN_HEAD = 26622, + SPELL_ELUNE_CANDLE_OMEN_CHEST = 26624, + SPELL_ELUNE_CANDLE_OMEN_HAND_R = 26625, + SPELL_ELUNE_CANDLE_OMEN_HAND_L = 26649, + SPELL_ELUNE_CANDLE_NORMAL = 26636, +}; + +class spell_gen_elune_candle : public SpellScriptLoader +{ + public: + spell_gen_elune_candle() : SpellScriptLoader("spell_gen_elune_candle") {} + + class spell_gen_elune_candle_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gen_elune_candle_SpellScript); + bool Validate(SpellInfo const* /*spellEntry*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_ELUNE_CANDLE_OMEN_HEAD)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_ELUNE_CANDLE_OMEN_CHEST)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_ELUNE_CANDLE_OMEN_HAND_R)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_ELUNE_CANDLE_OMEN_HAND_L)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_ELUNE_CANDLE_NORMAL)) + return false; + return true; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + { + uint32 spellId = 0; + + if (target->GetEntry() == NPC_OMEN) + { + switch (urand(0, 3)) + { + case 0: spellId = SPELL_ELUNE_CANDLE_OMEN_HEAD; break; + case 1: spellId = SPELL_ELUNE_CANDLE_OMEN_CHEST; break; + case 2: spellId = SPELL_ELUNE_CANDLE_OMEN_HAND_R; break; + case 3: spellId = SPELL_ELUNE_CANDLE_OMEN_HAND_L; break; + } + } + else + spellId = SPELL_ELUNE_CANDLE_NORMAL; + + GetCaster()->CastSpell(target, spellId, true, NULL); + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_gen_elune_candle_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_gen_elune_candle_SpellScript(); + } +}; + // 24750 Trick enum eTrickSpells { @@ -1592,4 +1661,5 @@ void AddSC_generic_spell_scripts() new spell_gen_luck_of_the_draw(); new spell_gen_dalaran_disguise("spell_gen_sunreaver_disguise"); new spell_gen_dalaran_disguise("spell_gen_silver_covenant_disguise"); + new spell_gen_elune_candle(); } diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index 21e4fe6a3a0..9227c0c1138 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -40,6 +40,7 @@ npc_sayge 100% Darkmoon event fortune teller, buff player based npc_snake_trap_serpents 80% AI for snakes that summoned by Snake Trap npc_shadowfiend 100% restore 5% of owner's mana when shadowfiend die from damage npc_locksmith 75% list of keys needs to be confirmed +npc_firework 100% NPC's summoned by rockets and rocket clusters, for making them cast visual EndContentData */ #include "ScriptPCH.h" @@ -2764,6 +2765,285 @@ public: } }; +enum Fireworks +{ + NPC_OMEN = 15467, + NPC_MINION_OF_OMEN = 15466, + NPC_FIREWORK_BLUE = 15879, + NPC_FIREWORK_GREEN = 15880, + NPC_FIREWORK_PURPLE = 15881, + NPC_FIREWORK_RED = 15882, + NPC_FIREWORK_YELLOW = 15883, + NPC_FIREWORK_WHITE = 15884, + NPC_FIREWORK_BIG_BLUE = 15885, + NPC_FIREWORK_BIG_GREEN = 15886, + NPC_FIREWORK_BIG_PURPLE = 15887, + NPC_FIREWORK_BIG_RED = 15888, + NPC_FIREWORK_BIG_YELLOW = 15889, + NPC_FIREWORK_BIG_WHITE = 15890, + + NPC_CLUSTER_BLUE = 15872, + NPC_CLUSTER_RED = 15873, + NPC_CLUSTER_GREEN = 15874, + NPC_CLUSTER_PURPLE = 15875, + NPC_CLUSTER_WHITE = 15876, + NPC_CLUSTER_YELLOW = 15877, + NPC_CLUSTER_BIG_BLUE = 15911, + NPC_CLUSTER_BIG_GREEN = 15912, + NPC_CLUSTER_BIG_PURPLE = 15913, + NPC_CLUSTER_BIG_RED = 15914, + NPC_CLUSTER_BIG_WHITE = 15915, + NPC_CLUSTER_BIG_YELLOW = 15916, + NPC_CLUSTER_ELUNE = 15918, + + GO_FIREWORK_LAUNCHER_1 = 180771, + GO_FIREWORK_LAUNCHER_2 = 180868, + GO_FIREWORK_LAUNCHER_3 = 180850, + GO_CLUSTER_LAUNCHER_1 = 180772, + GO_CLUSTER_LAUNCHER_2 = 180859, + GO_CLUSTER_LAUNCHER_3 = 180869, + GO_CLUSTER_LAUNCHER_4 = 180874, + + SPELL_ROCKET_BLUE = 26344, + SPELL_ROCKET_GREEN = 26345, + SPELL_ROCKET_PURPLE = 26346, + SPELL_ROCKET_RED = 26347, + SPELL_ROCKET_WHITE = 26348, + SPELL_ROCKET_YELLOW = 26349, + SPELL_ROCKET_BIG_BLUE = 26351, + SPELL_ROCKET_BIG_GREEN = 26352, + SPELL_ROCKET_BIG_PURPLE = 26353, + SPELL_ROCKET_BIG_RED = 26354, + SPELL_ROCKET_BIG_WHITE = 26355, + SPELL_ROCKET_BIG_YELLOW = 26356, + SPELL_LUNAR_FORTUNE = 26522, + + ANIM_GO_LAUNCH_FIREWORK = 3, + ZONE_MOONGLADE = 493, +}; + +Position omenSummonPos = {7558.993f, -2839.999f, 450.0214f, 4.46f}; + +class npc_firework : public CreatureScript +{ +public: + npc_firework() : CreatureScript("npc_firework") { } + + struct npc_fireworkAI : public ScriptedAI + { + npc_fireworkAI(Creature* creature) : ScriptedAI(creature) {} + + bool isCluster() + { + switch (me->GetEntry()) + { + case NPC_FIREWORK_BLUE: + case NPC_FIREWORK_GREEN: + case NPC_FIREWORK_PURPLE: + case NPC_FIREWORK_RED: + case NPC_FIREWORK_YELLOW: + case NPC_FIREWORK_WHITE: + case NPC_FIREWORK_BIG_BLUE: + case NPC_FIREWORK_BIG_GREEN: + case NPC_FIREWORK_BIG_PURPLE: + case NPC_FIREWORK_BIG_RED: + case NPC_FIREWORK_BIG_YELLOW: + case NPC_FIREWORK_BIG_WHITE: + return false; + case NPC_CLUSTER_BLUE: + case NPC_CLUSTER_GREEN: + case NPC_CLUSTER_PURPLE: + case NPC_CLUSTER_RED: + case NPC_CLUSTER_YELLOW: + case NPC_CLUSTER_WHITE: + case NPC_CLUSTER_BIG_BLUE: + case NPC_CLUSTER_BIG_GREEN: + case NPC_CLUSTER_BIG_PURPLE: + case NPC_CLUSTER_BIG_RED: + case NPC_CLUSTER_BIG_YELLOW: + case NPC_CLUSTER_BIG_WHITE: + case NPC_CLUSTER_ELUNE: + default: + return true; + } + } + + GameObject* FindNearestLauncher() + { + GameObject* launcher = NULL; + + if (isCluster()) + { + GameObject* launcher1 = GetClosestGameObjectWithEntry(me, GO_CLUSTER_LAUNCHER_1, 0.5f); + GameObject* launcher2 = GetClosestGameObjectWithEntry(me, GO_CLUSTER_LAUNCHER_2, 0.5f); + GameObject* launcher3 = GetClosestGameObjectWithEntry(me, GO_CLUSTER_LAUNCHER_3, 0.5f); + GameObject* launcher4 = GetClosestGameObjectWithEntry(me, GO_CLUSTER_LAUNCHER_4, 0.5f); + + if (launcher1) + launcher = launcher1; + else if (launcher2) + launcher = launcher2; + else if (launcher3) + launcher = launcher3; + else if (launcher4) + launcher = launcher4; + } + else + { + GameObject* launcher1 = GetClosestGameObjectWithEntry(me, GO_FIREWORK_LAUNCHER_1, 0.5f); + GameObject* launcher2 = GetClosestGameObjectWithEntry(me, GO_FIREWORK_LAUNCHER_2, 0.5f); + GameObject* launcher3 = GetClosestGameObjectWithEntry(me, GO_FIREWORK_LAUNCHER_3, 0.5f); + + if (launcher1) + launcher = launcher1; + else if (launcher2) + launcher = launcher2; + else if (launcher3) + launcher = launcher3; + } + + return launcher; + } + + uint32 GetFireworkSpell(uint32 entry) + { + switch (entry) + { + case NPC_FIREWORK_BLUE: + return SPELL_ROCKET_BLUE; + case NPC_FIREWORK_GREEN: + return SPELL_ROCKET_GREEN; + case NPC_FIREWORK_PURPLE: + return SPELL_ROCKET_PURPLE; + case NPC_FIREWORK_RED: + return SPELL_ROCKET_RED; + case NPC_FIREWORK_YELLOW: + return SPELL_ROCKET_YELLOW; + case NPC_FIREWORK_WHITE: + return SPELL_ROCKET_WHITE; + case NPC_FIREWORK_BIG_BLUE: + return SPELL_ROCKET_BIG_BLUE; + case NPC_FIREWORK_BIG_GREEN: + return SPELL_ROCKET_BIG_GREEN; + case NPC_FIREWORK_BIG_PURPLE: + return SPELL_ROCKET_BIG_PURPLE; + case NPC_FIREWORK_BIG_RED: + return SPELL_ROCKET_BIG_RED; + case NPC_FIREWORK_BIG_YELLOW: + return SPELL_ROCKET_BIG_YELLOW; + case NPC_FIREWORK_BIG_WHITE: + return SPELL_ROCKET_BIG_WHITE; + default: + return 0; + } + } + + uint32 GetFireworkGameObjectId() + { + uint32 spellId = 0; + + switch (me->GetEntry()) + { + case NPC_CLUSTER_BLUE: + spellId = GetFireworkSpell(NPC_FIREWORK_BLUE); + break; + case NPC_CLUSTER_GREEN: + spellId = GetFireworkSpell(NPC_FIREWORK_GREEN); + break; + case NPC_CLUSTER_PURPLE: + spellId = GetFireworkSpell(NPC_FIREWORK_PURPLE); + break; + case NPC_CLUSTER_RED: + spellId = GetFireworkSpell(NPC_FIREWORK_RED); + break; + case NPC_CLUSTER_YELLOW: + spellId = GetFireworkSpell(NPC_FIREWORK_YELLOW); + break; + case NPC_CLUSTER_WHITE: + spellId = GetFireworkSpell(NPC_FIREWORK_WHITE); + break; + case NPC_CLUSTER_BIG_BLUE: + spellId = GetFireworkSpell(NPC_FIREWORK_BIG_BLUE); + break; + case NPC_CLUSTER_BIG_GREEN: + spellId = GetFireworkSpell(NPC_FIREWORK_BIG_GREEN); + break; + case NPC_CLUSTER_BIG_PURPLE: + spellId = GetFireworkSpell(NPC_FIREWORK_BIG_PURPLE); + break; + case NPC_CLUSTER_BIG_RED: + spellId = GetFireworkSpell(NPC_FIREWORK_BIG_RED); + break; + case NPC_CLUSTER_BIG_YELLOW: + spellId = GetFireworkSpell(NPC_FIREWORK_BIG_YELLOW); + break; + case NPC_CLUSTER_BIG_WHITE: + spellId = GetFireworkSpell(NPC_FIREWORK_BIG_WHITE); + break; + case NPC_CLUSTER_ELUNE: + spellId = GetFireworkSpell(urand(NPC_FIREWORK_BLUE, NPC_FIREWORK_WHITE)); + break; + } + + const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId); + + if (spellInfo && spellInfo->Effects[0].Effect == SPELL_EFFECT_SUMMON_OBJECT_WILD) + return spellInfo->Effects[0].MiscValue; + + return 0; + } + + void Reset() + { + if (GameObject* launcher = FindNearestLauncher()) + { + launcher->SendCustomAnim(ANIM_GO_LAUNCH_FIREWORK); + me->SetOrientation(launcher->GetOrientation() + M_PI/2); + } + else + return; + + if (isCluster()) + { + // Check if we are near Elune'ara lake south, if so try to summon Omen or a minion + if (me->GetZoneId() == ZONE_MOONGLADE) + { + if (!me->FindNearestCreature(NPC_OMEN, 100.0f, false) && me->GetDistance2d(omenSummonPos.GetPositionX(), omenSummonPos.GetPositionY()) <= 100.0f) + { + switch (urand(0,9)) + { + case 0: + case 1: + case 2: + case 3: + if (Creature* minion = me->SummonCreature(NPC_MINION_OF_OMEN, me->GetPositionX()+frand(-5.0f, 5.0f), me->GetPositionY()+frand(-5.0f, 5.0f), me->GetPositionZ(), 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000)) + minion->AI()->AttackStart(me->SelectNearestPlayer(20.0f)); + break; + case 9: + me->SummonCreature(NPC_OMEN, omenSummonPos); + break; + } + } + } + if (me->GetEntry() == NPC_CLUSTER_ELUNE) + DoCast(SPELL_LUNAR_FORTUNE); + + float displacement = 0.7f; + for (uint8 i = 0; i < 4; i++) + me->SummonGameObject(GetFireworkGameObjectId(), me->GetPositionX() + (i%2 == 0 ? displacement : -displacement), me->GetPositionY() + (i > 1 ? displacement : -displacement), me->GetPositionZ() + 4.0f, me->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 1); + } + else + //me->CastSpell(me, GetFireworkSpell(me->GetEntry()), true); + me->CastSpell(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), GetFireworkSpell(me->GetEntry()), true); + } + }; + + CreatureAI *GetAI(Creature* creature) const + { + return new npc_fireworkAI(creature); + } +}; + void AddSC_npcs_special() { new npc_air_force_bots; @@ -2796,5 +3076,6 @@ void AddSC_npcs_special() new npc_experience; new npc_fire_elemental; new npc_earth_elemental; + new npc_firework; } -- cgit v1.2.3 From 75992143c193ec6afdd5897e06eb3694fc80a13f Mon Sep 17 00:00:00 2001 From: Souler Date: Mon, 30 Jan 2012 00:21:42 +0100 Subject: Scripts/Spells: Fix Argent Tournament mount spells: * Break-Shield * Charge * Defend (visual) * Mounted duel * Faction Pennants when riding argent tournament mounts Closes #4917. --- sql/updates/world/2012_01_29_04_world_misc.sql | 116 ++++ src/server/game/Entities/Player/Player.h | 3 +- src/server/game/Entities/Unit/Unit.cpp | 33 +- src/server/game/Spells/SpellEffects.cpp | 2 + src/server/game/Spells/SpellMgr.cpp | 17 + src/server/scripts/Spells/spell_generic.cpp | 749 +++++++++++++++++++++++ src/server/scripts/World/achievement_scripts.cpp | 12 + 7 files changed, 929 insertions(+), 3 deletions(-) create mode 100644 sql/updates/world/2012_01_29_04_world_misc.sql (limited to 'src/server/scripts') diff --git a/sql/updates/world/2012_01_29_04_world_misc.sql b/sql/updates/world/2012_01_29_04_world_misc.sql new file mode 100644 index 00000000000..3686957e433 --- /dev/null +++ b/sql/updates/world/2012_01_29_04_world_misc.sql @@ -0,0 +1,116 @@ +-- remove aura_required for clickspells on tournament mounts and add more cases (Thanks to @Tassader) +DELETE FROM `npc_spellclick_spells` WHERE npc_entry IN (33842,33796,33798,33791,33792,33799,33843,33800,33795,33790,33793,33794); +INSERT INTO `npc_spellclick_spells`(`npc_entry`,`spell_id`,`quest_start`,`quest_start_active`,`quest_end`,`cast_flags`,`aura_required`,`aura_forbidden`,`user_type`) VALUES +(33842,63791,13668,0,13687,1,0,0,0),-- Aspirant +(33799,62783,13691,0,0,1,0,0,0),-- A Valiant Of Orgrimmar +(33799,62783,13707,0,0,1,0,0,0),-- Valiant Of Orgrimmar +(33796,62784,13693,0,0,1,0,0,0),-- A Valiant Of Sen'jin +(33796,62784,13708,0,0,1,0,0,0),-- Valiant Of Sen'jin +(33792,62785,13694,0,0,1,0,0,0),-- A Valiant Of Thunder Bluff +(33792,62785,13709,0,0,1,0,0,0),-- Valiant Of Thunder Bluff +(33791,62786,13696,0,0,1,0,0,0),-- A Valiant Of Silvermoon +(33791,62786,13711,0,0,1,0,0,0),-- Valiant Of Silvermoon +(33798,62787,13695,0,0,1,0,0,0),-- A Valiant Of Undercity +(33798,62787,13710,0,0,1,0,0,0), -- Valiant Of Undercity +(33843,63792,13667,0,13686,1,0,0,0),-- Aspirant +(33800,62774,13593,0,0,1,0,0,0),-- A Valiant Of Stormwind +(33800,62774,13684,0,0,1,0,0,0),-- Valiant Of Stormwind +(33795,62779,13685,0,0,1,0,0,0),-- A Valiant Of Ironforge +(33795,62779,13703,0,0,1,0,0,0),-- Valiant Of Ironforge +(33793,62780,13688,0,0,1,0,0,0),-- A Valiant Of Gnomregan +(33793,62780,13704,0,0,1,0,0,0),-- Valiant Of Gnomregan +(33790,62781,13690,0,0,1,0,0,0),-- A Valiant Of Exodar +(33790,62781,13705,0,0,1,0,0,0),-- Valiant Of Exodar +(33794,62782,13689,0,0,1,0,0,0),-- A Valiant Of Darnassus +(33794,62782,13706,0,0,1,0,0,0); -- Valiant Of Darnassus +UPDATE `npc_spellclick_spells` SET `aura_required`=0 WHERE `aura_required`=62853; + +-- Break-Shield spells +DELETE FROM `spell_script_names` WHERE `spell_id` IN (62575,62626,64342,64507,64590,64595,64686,65147,66480,68504); +-- Charge spells +DELETE FROM `spell_script_names` WHERE `spell_id` IN (62874,62960,63661,62563,63003,63010,64591,66481,68282,68284,68321,68498,68501); +-- Defend spells +DELETE FROM `spell_script_names` WHERE `spell_id` IN (62552,62719,66482); +-- Pennant and summon spells +DELETE FROM `spell_script_names` WHERE `spell_id` IN (62863,63034,62774,62779,62780,62781,62782,62783,62784,62785,62786,62787,63663,63791,63792,62595,62596,62594,63394,63395,63396,63397,63398,63401,63402,63403,63404,63405,63406,63421,63422,63423,63425,63426,63427,63428,63429,63430,63431,63432,63433,63434,63435,63436,63606,63500,63501,63607,63608,63609); +INSERT INTO `spell_script_names`(`spell_id`,`ScriptName`) VALUES +(62575,'spell_gen_break_shield'), +(62626,'spell_gen_break_shield'), +(64342,'spell_gen_break_shield'), +(64507,'spell_gen_break_shield'), +(64590,'spell_gen_break_shield'), +(64595,'spell_gen_break_shield'), +(64686,'spell_gen_break_shield'), +(65147,'spell_gen_break_shield'), +(66480,'spell_gen_break_shield'), +(68504,'spell_gen_break_shield'), +(62874,'spell_gen_mounted_charge'), +(62960,'spell_gen_mounted_charge'), +(63661,'spell_gen_mounted_charge'), +(62563,'spell_gen_mounted_charge'), +(63003,'spell_gen_mounted_charge'), +(63010,'spell_gen_mounted_charge'), +(64591,'spell_gen_mounted_charge'), +(66481,'spell_gen_mounted_charge'), +(68282,'spell_gen_mounted_charge'), +(68284,'spell_gen_mounted_charge'), +(68321,'spell_gen_mounted_charge'), +(68498,'spell_gen_mounted_charge'), +(68501,'spell_gen_mounted_charge'), +(62552,'spell_gen_defend'), +(62719,'spell_gen_defend'), +(66482,'spell_gen_defend'), +(62863 ,'spell_gen_tournament_duel'), +(63034,'spell_gen_on_tournament_mount'), +(62595,'spell_gen_tournament_pennant'), +(62596,'spell_gen_tournament_pennant'), +(62594,'spell_gen_tournament_pennant'), +(63394,'spell_gen_tournament_pennant'), +(63395,'spell_gen_tournament_pennant'), +(63396,'spell_gen_tournament_pennant'), +(63397,'spell_gen_tournament_pennant'), +(63398,'spell_gen_tournament_pennant'), +(63401,'spell_gen_tournament_pennant'), +(63402,'spell_gen_tournament_pennant'), +(63403,'spell_gen_tournament_pennant'), +(63404,'spell_gen_tournament_pennant'), +(63405,'spell_gen_tournament_pennant'), +(63406,'spell_gen_tournament_pennant'), +(63421,'spell_gen_tournament_pennant'), +(63422,'spell_gen_tournament_pennant'), +(63423,'spell_gen_tournament_pennant'), +(63425,'spell_gen_tournament_pennant'), +(63426,'spell_gen_tournament_pennant'), +(63427,'spell_gen_tournament_pennant'), +(63428,'spell_gen_tournament_pennant'), +(63429,'spell_gen_tournament_pennant'), +(63430,'spell_gen_tournament_pennant'), +(63431,'spell_gen_tournament_pennant'), +(63432,'spell_gen_tournament_pennant'), +(63433,'spell_gen_tournament_pennant'), +(63434,'spell_gen_tournament_pennant'), +(63435,'spell_gen_tournament_pennant'), +(63436,'spell_gen_tournament_pennant'), +(63606,'spell_gen_tournament_pennant'), +(63500,'spell_gen_tournament_pennant'), +(63501,'spell_gen_tournament_pennant'), +(63607,'spell_gen_tournament_pennant'), +(63608,'spell_gen_tournament_pennant'), +(63609,'spell_gen_tournament_pennant'), +(62774,'spell_gen_summon_tournament_mount'), +(62779,'spell_gen_summon_tournament_mount'), +(62780,'spell_gen_summon_tournament_mount'), +(62781,'spell_gen_summon_tournament_mount'), +(62782,'spell_gen_summon_tournament_mount'), +(62783,'spell_gen_summon_tournament_mount'), +(62784,'spell_gen_summon_tournament_mount'), +(62785,'spell_gen_summon_tournament_mount'), +(62786,'spell_gen_summon_tournament_mount'), +(62787,'spell_gen_summon_tournament_mount'), +(63663,'spell_gen_summon_tournament_mount'), +(63791,'spell_gen_summon_tournament_mount'), +(63792,'spell_gen_summon_tournament_mount'); + +DELETE FROM `achievement_criteria_data` WHERE `criteria_id`=9798 AND `type`=11; +INSERT INTO `achievement_criteria_data` (`criteria_id`,`type`,`value1`,`value2`,`ScriptName`) VALUES +(9798,11,0,0, 'achievement_tilted'); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index c39d29db12a..2fa171cf3f9 100755 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -274,13 +274,14 @@ struct PvPInfo struct DuelInfo { - DuelInfo() : initiator(NULL), opponent(NULL), startTimer(0), startTime(0), outOfBound(0) {} + DuelInfo() : initiator(NULL), opponent(NULL), startTimer(0), startTime(0), outOfBound(0), isMounted(false) {} Player* initiator; Player* opponent; time_t startTimer; time_t startTime; time_t outOfBound; + bool isMounted; }; struct Areas diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 6bab63acf1b..e02331e00e7 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -628,6 +628,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam // duel ends when player has 1 or less hp bool duel_hasEnded = false; + bool duel_wasMounted = false; if (victim->GetTypeId() == TYPEID_PLAYER && victim->ToPlayer()->duel && damage >= (health-1)) { // prevent kill only if killed in duel and killed by opponent or opponent controlled creature @@ -636,6 +637,20 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam duel_hasEnded = true; } + else if (victim->IsVehicle() && damage >= (health-1) && victim->GetCharmer() && victim->GetCharmer()->GetTypeId() == TYPEID_PLAYER) + { + Player* victimRider = victim->GetCharmer()->ToPlayer(); + + if (victimRider && victimRider->duel && victimRider->duel->isMounted) + { + // prevent kill only if killed in duel and killed by opponent or opponent controlled creature + if (victimRider->duel->opponent == this || victimRider->duel->opponent->GetGUID() == GetCharmerGUID()) + damage = health - 1; + + duel_wasMounted = true; + duel_hasEnded = true; + } + } if (GetTypeId() == TYPEID_PLAYER && this != victim) { @@ -745,8 +760,18 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam // last damage from duel opponent if (duel_hasEnded) { - ASSERT(victim->GetTypeId() == TYPEID_PLAYER); - Player* he = victim->ToPlayer(); + Player* he; + + if (duel_wasMounted) + { + ASSERT(victim->GetCharmer()->GetTypeId() == TYPEID_PLAYER); + he = victim->GetCharmer()->ToPlayer(); + } + else + { + ASSERT(victim->GetTypeId() == TYPEID_PLAYER); + he = victim->ToPlayer(); + } ASSERT(he->duel); @@ -16954,6 +16979,10 @@ void Unit::_ExitVehicle(Position const* exitPosition) m_vehicle->RemovePassenger(this); + // If player is on mouted duel and exits the mount should immediatly lose the duel + if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->duel && ToPlayer()->duel->isMounted) + ToPlayer()->DuelComplete(DUEL_FLED); + // This should be done before dismiss, because there may be some aura removal Vehicle* vehicle = m_vehicle; m_vehicle = NULL; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index c3357b99601..d5a9bf923b4 100755 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -5607,6 +5607,7 @@ void Spell::EffectDuel(SpellEffIndex effIndex) duel->opponent = target; duel->startTime = 0; duel->startTimer = 0; + duel->isMounted = (GetSpellInfo()->Id == 62875); // Mounted Duel caster->duel = duel; DuelInfo* duel2 = new DuelInfo; @@ -5614,6 +5615,7 @@ void Spell::EffectDuel(SpellEffIndex effIndex) duel2->opponent = caster; duel2->startTime = 0; duel2->startTimer = 0; + duel2->isMounted = (GetSpellInfo()->Id == 62875); // Mounted Duel target->duel = duel2; caster->SetUInt64Value(PLAYER_DUEL_ARBITER, pGameObj->GetGUID()); diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index f3d5697c672..171382ba4f7 100755 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -2889,6 +2889,22 @@ void SpellMgr::LoadSpellCustomAttr() case 69293: // Wing Buffet case 74439: // Machine Gun case 63278: // Mark of the Faceless (General Vezax) + case 62544: // Thrust (Argent Tournament) + case 64588: // Thrust (Argent Tournament) + case 66479: // Thrust (Argent Tournament) + case 68505: // Thrust (Argent Tournament) + case 62626: // Break-Shield (Argent Tournament, Player) + case 64590: // Break-Shield (Argent Tournament, Player) + case 64342: // Break-Shield (Argent Tournament, NPC) + case 64686: // Break-Shield (Argent Tournament, NPC) + case 65147: // Break-Shield (Argent Tournament, NPC) + case 68504: // Break-Shield (Argent Tournament, NPC) + case 62874: // Charge (Argent Tournament, Player) + case 68498: // Charge (Argent Tournament, Player) + case 64591: // Charge (Argent Tournament, Player) + case 63003: // Charge (Argent Tournament, NPC) + case 63010: // Charge (Argent Tournament, NPC) + case 68321: // Charge (Argent Tournament, NPC) case 72255: // Mark of the Fallen Champion (Deathbringer Saurfang) case 72444: // Mark of the Fallen Champion (Deathbringer Saurfang) case 72445: // Mark of the Fallen Champion (Deathbringer Saurfang) @@ -2972,6 +2988,7 @@ void SpellMgr::LoadDbcDataCorrections() spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ENEMY; spellInfo->EffectImplicitTargetB[0] = 0; break; + case 63665: // Charge (Argent Tournament emote on riders) case 31447: // Mark of Kaz'rogal (needs target selection script) case 31298: // Sleep (needs target selection script) case 51904: // Summon Ghouls On Scarlet Crusade (this should use conditions table, script for this spell needs to be fixed) diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index d0307966795..96d259817c0 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -1626,6 +1626,748 @@ class spell_gen_dalaran_disguise : public SpellScriptLoader } }; +/* DOCUMENTATION: Break-Shield spells + Break-Shield spells can be classified in three groups: + + - Spells on vehicle bar used by players: + + EFFECT_0: SCRIPT_EFFECT + + EFFECT_1: NONE + + EFFECT_2: NONE + - Spells casted by players triggered by script: + + EFFECT_0: SCHOOL_DAMAGE + + EFFECT_1: SCRIPT_EFFECT + + EFFECT_2: FORCE_CAST + - Spells casted by NPCs on players: + + EFFECT_0: SCHOOL_DAMAGE + + EFFECT_1: SCRIPT_EFFECT + + EFFECT_2: NONE + + In the following script we handle the SCRIPT_EFFECT for effIndex EFFECT_0 and EFFECT_1. + - When handling EFFECT_0 we're in the "Spells on vehicle bar used by players" case + and we'll trigger "Spells casted by players triggered by script" + - When handling EFFECT_1 we're in the "Spells casted by players triggered by script" + or "Spells casted by NPCs on players" so we'll search for the first defend layer and drop it. +*/ + +enum BreakShieldSpells +{ + SPELL_BREAK_SHIELD_DAMAGE_2K = 62626, + SPELL_BREAK_SHIELD_DAMAGE_10K = 64590, + + SPELL_BREAK_SHIELD_TRIGGER_FACTION_MOUNTS = 62575, // Also on ToC5 mounts + SPELL_BREAK_SHIELD_TRIGGER_CAMPAING_WARHORSE = 64595, + SPELL_BREAK_SHIELD_TRIGGER_UNK = 66480, +}; + +class spell_gen_break_shield: public SpellScriptLoader +{ +public: + spell_gen_break_shield() : SpellScriptLoader("spell_gen_break_shield") { } + + class spell_gen_break_shield_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gen_break_shield_SpellScript) + + void HandleScriptEffect(SpellEffIndex effIndex) + { + Unit* caster = GetCaster(); + Unit* target = GetTargetUnit(); + + if (!caster || !target) + return; + + switch (effIndex) + { + case EFFECT_0: // On spells wich trigger the damaging spell (and also the visual) + uint32 spellId; + switch (GetSpellInfo()->Id) + { + case SPELL_BREAK_SHIELD_TRIGGER_UNK: + case SPELL_BREAK_SHIELD_TRIGGER_CAMPAING_WARHORSE: + spellId = SPELL_BREAK_SHIELD_DAMAGE_10K; + break; + case SPELL_BREAK_SHIELD_TRIGGER_FACTION_MOUNTS: + spellId = SPELL_BREAK_SHIELD_DAMAGE_2K; + break; + default: + return; + } + + if (Unit* rider = caster->GetCharmer()) + rider->CastSpell(target, spellId, false); + else + caster->CastSpell(target, spellId, false); + break; + case EFFECT_1: // On damaging spells, for removing the a defend layer + Unit::AuraApplicationMap const& auras = target->GetAppliedAuras(); + for (Unit::AuraApplicationMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) + { + Aura* aura = itr->second->GetBase(); + SpellInfo const* auraInfo = aura->GetSpellInfo(); + if (aura && auraInfo->SpellIconID == 2007 && aura->HasEffectType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN)) + aura->ModStackAmount(-1, AURA_REMOVE_BY_ENEMY_SPELL); + } + break; + } + } + + void Register() + { + OnEffectHit += SpellEffectFn(spell_gen_break_shield_SpellScript::HandleScriptEffect, EFFECT_FIRST_FOUND, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_gen_break_shield_SpellScript(); + } +}; + +/* DOCUMENTATION: Charge spells + Charge spells can be classified in four groups: + + - Spells on vehicle bar used by players: + + EFFECT_0: SCRIPT_EFFECT + + EFFECT_1: TRIGGER_SPELL + + EFFECT_2: NONE + - Spells casted by player's mounts triggered by script: + + EFFECT_0: CHARGE + + EFFECT_1: TRIGGER_SPELL + + EFFECT_2: APPLY_AURA + - Spells casted by players on the target triggered by script: + + EFFECT_0: SCHOOL_DAMAGE + + EFFECT_1: SCRIPT_EFFECT + + EFFECT_2: NONE + - Spells casted by NPCs on players: + + EFFECT_0: SCHOOL_DAMAGE + + EFFECT_1: CHARGE + + EFFECT_2: SCRIPT_EFFECT + + In the following script we handle the SCRIPT_EFFECT and CHARGE + - When handling SCRIPT_EFFECT: + + EFFECT_0: Corresponds to "Spells on vehicle bar used by players" and we make player's mount cast + the charge effect on the current target ("Spells casted by player's mounts triggered by script"). + + EFFECT_1 and EFFECT_2: Triggered when "Spells casted by player's mounts triggered by script" hits target, + corresponding to "Spells casted by players on the target triggered by script" and "Spells casted by + NPCs on players" and we check Defend layers and drop a charge of the first found. + - When handling CHARGE: + + Only launched for "Spells casted by player's mounts triggered by script", makes the player cast the + damaging spell on target with a small chance of failing it. +*/ + +enum ChargeSpells +{ + SPELL_CHARGE_DAMAGE_8K5 = 62874, + SPELL_CHARGE_DAMAGE_20K = 68498, + SPELL_CHARGE_DAMAGE_45K = 64591, + + SPELL_CHARGE_CHARGING_EFFECT_8K5 = 63661, + SPELL_CHARGE_CHARGING_EFFECT_20K_1 = 68284, + SPELL_CHARGE_CHARGING_EFFECT_20K_2 = 68501, + SPELL_CHARGE_CHARGING_EFFECT_45K_1 = 62563, + SPELL_CHARGE_CHARGING_EFFECT_45K_2 = 66481, + + SPELL_CHARGE_TRIGGER_FACTION_MOUNTS = 62960, + SPELL_CHARGE_TRIGGER_TRIAL_CHAMPION = 68282, + + SPELL_CHARGE_MISS_EFFECT = 62977, +}; + +class spell_gen_mounted_charge: public SpellScriptLoader +{ +public: + spell_gen_mounted_charge() : SpellScriptLoader("spell_gen_mounted_charge") { } + + class spell_gen_mounted_charge_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gen_mounted_charge_SpellScript) + + void HandleScriptEffect(SpellEffIndex effIndex) + { + Unit* caster = GetCaster(); + Unit* target = GetTargetUnit(); + + if (!caster || !target) + return; + + switch (effIndex) + { + case EFFECT_0: // On spells wich trigger the damaging spell (and also the visual) + uint32 spellId; + + switch (GetSpellInfo()->Id) + { + case SPELL_CHARGE_TRIGGER_TRIAL_CHAMPION: + spellId = SPELL_CHARGE_CHARGING_EFFECT_20K_1; + case SPELL_CHARGE_TRIGGER_FACTION_MOUNTS: + spellId = SPELL_CHARGE_CHARGING_EFFECT_8K5; + break; + default: + return; + } + + if (Unit* vehicle = caster->GetVehicleBase()) + vehicle->CastSpell(target, spellId, false); + else + caster->CastSpell(target, spellId, false); + break; + case EFFECT_1: // On damaging spells, for removing the a defend layer + case EFFECT_2: + Unit::AuraApplicationMap const& auras = target->GetAppliedAuras(); + for (Unit::AuraApplicationMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) + { + Aura* aura = itr->second->GetBase(); + SpellInfo const* auraInfo = aura->GetSpellInfo(); + if (aura && auraInfo->SpellIconID == 2007 && aura->HasEffectType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN)) + aura->ModStackAmount(-1, AURA_REMOVE_BY_ENEMY_SPELL); + } + break; + } + } + + void HandleChargeEffect(SpellEffIndex effIndex) + { + Unit* caster = GetCaster(); + Unit* target = GetTargetUnit(); + + if (!caster || !target) + return; + + uint32 spellId; + + switch (GetSpellInfo()->Id) + { + case SPELL_CHARGE_CHARGING_EFFECT_8K5: + spellId = SPELL_CHARGE_DAMAGE_8K5; + break; + case SPELL_CHARGE_CHARGING_EFFECT_20K_1: + case SPELL_CHARGE_CHARGING_EFFECT_20K_2: + spellId = SPELL_CHARGE_DAMAGE_20K; + break; + case SPELL_CHARGE_CHARGING_EFFECT_45K_1: + case SPELL_CHARGE_CHARGING_EFFECT_45K_2: + spellId = SPELL_CHARGE_DAMAGE_45K; + break; + default: + return; + } + + // If target isn't a training dummy there's a chance of failing the charge + if (!target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE) && urand(0,7) == 0) + spellId = SPELL_CHARGE_MISS_EFFECT; + + if (Unit* rider = caster->GetCharmer()) + rider->CastSpell(target, spellId, false); + else + caster->CastSpell(target, spellId, false); + } + + void Register() + { + SpellInfo const* spell = sSpellMgr->GetSpellInfo(m_scriptSpellId); + + if (spell->HasEffect(SPELL_EFFECT_SCRIPT_EFFECT)) + OnEffectHit += SpellEffectFn(spell_gen_mounted_charge_SpellScript::HandleScriptEffect, EFFECT_FIRST_FOUND, SPELL_EFFECT_SCRIPT_EFFECT); + + if (spell->Effects[EFFECT_0].Effect == SPELL_EFFECT_CHARGE) + OnEffectHit += SpellEffectFn(spell_gen_mounted_charge_SpellScript::HandleChargeEffect, EFFECT_0, SPELL_EFFECT_CHARGE); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_gen_mounted_charge_SpellScript(); + } +}; + +enum DefendVisuals +{ + SPELL_VISUAL_SHIELD_1 = 63130, + SPELL_VISUAL_SHIELD_2 = 63131, + SPELL_VISUAL_SHIELD_3 = 63132, +}; + +class spell_gen_defend : public SpellScriptLoader +{ + public: + spell_gen_defend() : SpellScriptLoader("spell_gen_defend") { } + + class spell_gen_defendAuraScript : public AuraScript + { + PrepareAuraScript(spell_gen_defendAuraScript); + + bool Validate(SpellInfo const* /*spellEntry*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_VISUAL_SHIELD_1)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_VISUAL_SHIELD_2)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_VISUAL_SHIELD_3)) + return false; + return true; + } + + void RefreshVisualShields(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* caster = GetCaster(); + Unit* target = GetTarget(); + + if(!target) + return; + + if (!caster) + { + target->RemoveAurasDueToSpell(GetId()); + return; + } + + for (uint8 i = 0; i < GetSpellInfo()->StackAmount; ++i) + target->RemoveAurasDueToSpell(SPELL_VISUAL_SHIELD_1 + i); + + target->CastSpell(target, SPELL_VISUAL_SHIELD_1 + GetAura()->GetStackAmount() - 1); + } + + void RemoveVisualShields(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* target = GetTarget(); + + if(!target) + return; + + for (uint8 i = 0; i < GetSpellInfo()->StackAmount; ++i) + target->RemoveAurasDueToSpell(SPELL_VISUAL_SHIELD_1 + i); + } + + void RemoveDummyFromDriver(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* caster = GetCaster(); + + if (caster && caster->ToTempSummon()) + if (Unit* rider = caster->ToTempSummon()->GetSummoner()) + rider->RemoveAurasDueToSpell(GetId()); + } + + void Register() + { + SpellInfo const* spell = sSpellMgr->GetSpellInfo(m_scriptSpellId); + + // Defend spells casted by NPCs (add visuals) + if (spell->Effects[EFFECT_0].ApplyAuraName == SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN) + { + AfterEffectApply += AuraEffectApplyFn(spell_gen_defendAuraScript::RefreshVisualShields, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); + OnEffectRemove += AuraEffectRemoveFn(spell_gen_defendAuraScript::RemoveVisualShields, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL); + } + + // Remove Defend spell from player when he dismounts + if (spell->Effects[EFFECT_2].ApplyAuraName == SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN) + OnEffectRemove += AuraEffectRemoveFn(spell_gen_defendAuraScript::RemoveDummyFromDriver, EFFECT_2, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL); + + // Defend spells casted by players (add/remove visuals) + if (spell->Effects[EFFECT_1].ApplyAuraName == SPELL_AURA_DUMMY) + { + AfterEffectApply += AuraEffectApplyFn(spell_gen_defendAuraScript::RefreshVisualShields, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); + OnEffectRemove += AuraEffectRemoveFn(spell_gen_defendAuraScript::RemoveVisualShields, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_gen_defendAuraScript(); + } +}; + +enum MountedDuelSpells +{ + SPELL_ON_TOURNAMENT_MOUNT = 63034, + SPELL_MOUNTED_DUEL = 62875, +}; + +class spell_gen_tournament_duel : public SpellScriptLoader +{ + public: + spell_gen_tournament_duel() : SpellScriptLoader("spell_gen_tournament_duel") { } + + class spell_gen_tournament_duel_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gen_tournament_duel_SpellScript); + + bool Validate(SpellInfo const* /*spellEntry*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_ON_TOURNAMENT_MOUNT)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_MOUNTED_DUEL)) + return false; + return true; + } + + void HandleScriptEffect(SpellEffIndex effIndex) + { + Unit* caster = GetCaster(); + Unit* target = GetTargetUnit(); + Unit* player = GetCaster()->GetCharmer(); + + if (!caster || !target || !player) + return; + + if (target->GetTypeId() == TYPEID_PLAYER) + { + + if (!target->HasAura(SPELL_ON_TOURNAMENT_MOUNT) || !target->GetVehicleBase()) + return; + + player->CastSpell(target, SPELL_MOUNTED_DUEL, true); + } + else if (target->GetTypeId() == TYPEID_UNIT) + { + if (!target->GetCharmer() || target->GetCharmer()->GetTypeId() != TYPEID_PLAYER || !target->GetCharmer()->HasAura(SPELL_ON_TOURNAMENT_MOUNT)) + return; + + player->CastSpell(target->GetCharmer(), SPELL_MOUNTED_DUEL, true); + } + } + + void Register() + { + OnEffectHit += SpellEffectFn(spell_gen_tournament_duel_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_gen_tournament_duel_SpellScript(); + } +}; + +enum TournamentMountsSpells +{ + SPELL_LANCE_EQUIPPED = 62853, +}; + +class spell_gen_summon_tournament_mount : public SpellScriptLoader +{ + public: + spell_gen_summon_tournament_mount() : SpellScriptLoader("spell_gen_summon_tournament_mount") { } + + class spell_gen_summon_tournament_mount_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gen_summon_tournament_mount_SpellScript); + + bool Validate(SpellInfo const* /*spellEntry*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_LANCE_EQUIPPED)) + return false; + return true; + } + + SpellCastResult CheckIfLanceEquiped() + { + Unit* caster = GetCaster(); + + if (!caster->HasAura(SPELL_LANCE_EQUIPPED)) + { + SetCustomCastResultMessage(SPELL_CUSTOM_ERROR_MUST_HAVE_LANCE_EQUIPPED); + return SPELL_FAILED_CUSTOM_ERROR; + } + + return SPELL_CAST_OK; + } + + void Register() + { + OnCheckCast += SpellCheckCastFn(spell_gen_summon_tournament_mount_SpellScript::CheckIfLanceEquiped); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_gen_summon_tournament_mount_SpellScript(); + } +}; + +enum TournamentPennantSpells +{ + SPELL_PENNANT_STORMWIND_ASPIRANT = 62595, + SPELL_PENNANT_STORMWIND_VALIANT = 62596, + SPELL_PENNANT_STORMWIND_CHAMPION = 62594, + SPELL_PENNANT_GNOMEREGAN_ASPIRANT = 63394, + SPELL_PENNANT_GNOMEREGAN_VALIANT = 63395, + SPELL_PENNANT_GNOMEREGAN_CHAMPION = 63396, + SPELL_PENNANT_SEN_JIN_ASPIRANT = 63397, + SPELL_PENNANT_SEN_JIN_VALIANT = 63398, + SPELL_PENNANT_SEN_JIN_CHAMPION = 63399, + SPELL_PENNANT_SILVERMOON_ASPIRANT = 63401, + SPELL_PENNANT_SILVERMOON_VALIANT = 63402, + SPELL_PENNANT_SILVERMOON_CHAMPION = 63403, + SPELL_PENNANT_DARNASSUS_ASPIRANT = 63404, + SPELL_PENNANT_DARNASSUS_VALIANT = 63405, + SPELL_PENNANT_DARNASSUS_CHAMPION = 63406, + SPELL_PENNANT_EXODAR_ASPIRANT = 63421, + SPELL_PENNANT_EXODAR_VALIANT = 63422, + SPELL_PENNANT_EXODAR_CHAMPION = 63423, + SPELL_PENNANT_IRONFORGE_ASPIRANT = 63425, + SPELL_PENNANT_IRONFORGE_VALIANT = 63426, + SPELL_PENNANT_IRONFORGE_CHAMPION = 63427, + SPELL_PENNANT_UNDERCITY_ASPIRANT = 63428, + SPELL_PENNANT_UNDERCITY_VALIANT = 63429, + SPELL_PENNANT_UNDERCITY_CHAMPION = 63430, + SPELL_PENNANT_ORGRIMMAR_ASPIRANT = 63431, + SPELL_PENNANT_ORGRIMMAR_VALIANT = 63432, + SPELL_PENNANT_ORGRIMMAR_CHAMPION = 63433, + SPELL_PENNANT_THUNDER_BLUFF_ASPIRANT = 63434, + SPELL_PENNANT_THUNDER_BLUFF_VALIANT = 63435, + SPELL_PENNANT_THUNDER_BLUFF_CHAMPION = 63436, + SPELL_PENNANT_ARGENT_CRUSADE_ASPIRANT = 63606, + SPELL_PENNANT_ARGENT_CRUSADE_VALIANT = 63500, + SPELL_PENNANT_ARGENT_CRUSADE_CHAMPION = 63501, + SPELL_PENNANT_EBON_BLADE_ASPIRANT = 63607, + SPELL_PENNANT_EBON_BLADE_VALIANT = 63608, + SPELL_PENNANT_EBON_BLADE_CHAMPION = 63609, +}; + +enum TournamentMounts +{ + NPC_STORMWIND_STEED = 33217, + NPC_IRONFORGE_RAM = 33316, + NPC_GNOMEREGAN_MECHANOSTRIDER = 33317, + NPC_EXODAR_ELEKK = 33318, + NPC_DARNASSIAN_NIGHTSABER = 33319, + NPC_ORGRIMMAR_WOLF = 33320, + NPC_DARK_SPEAR_RAPTOR = 33321, + NPC_THUNDER_BLUFF_KODO = 33322, + NPC_SILVERMOON_HAWKSTRIDER = 33323, + NPC_FORSAKEN_WARHORSE = 33324, + NPC_ARGENT_WARHORSE = 33782, + NPC_ARGENT_STEED_ASPIRANT = 33845, + NPC_ARGENT_HAWKSTRIDER_ASPIRANT = 33844, +}; + +enum TournamentQuestsAchievements +{ + ACHIEVEMENT_CHAMPION_STORMWIND = 2781, + ACHIEVEMENT_CHAMPION_DARNASSUS = 2777, + ACHIEVEMENT_CHAMPION_IRONFORGE = 2780, + ACHIEVEMENT_CHAMPION_GNOMEREGAN = 2779, + ACHIEVEMENT_CHAMPION_THE_EXODAR = 2778, + ACHIEVEMENT_CHAMPION_ORGRIMMAR = 2783, + ACHIEVEMENT_CHAMPION_SEN_JIN = 2784, + ACHIEVEMENT_CHAMPION_THUNDER_BLUFF = 2786, + ACHIEVEMENT_CHAMPION_UNDERCITY = 2787, + ACHIEVEMENT_CHAMPION_SILVERMOON = 2785, + ACHIEVEMENT_ARGENT_VALOR = 2758, + ACHIEVEMENT_CHAMPION_ALLIANCE = 2782, + ACHIEVEMENT_CHAMPION_HORDE = 2788, + + QUEST_VALIANT_OF_STORMWIND = 13593, + QUEST_A_VALIANT_OF_STORMWIND = 13684, + QUEST_VALIANT_OF_DARNASSUS = 13706, + QUEST_A_VALIANT_OF_DARNASSUS = 13689, + QUEST_VALIANT_OF_IRONFORGE = 13703, + QUEST_A_VALIANT_OF_IRONFORGE = 13685, + QUEST_VALIANT_OF_GNOMEREGAN = 13704, + QUEST_A_VALIANT_OF_GNOMEREGAN = 13688, + QUEST_VALIANT_OF_THE_EXODAR = 13705, + QUEST_A_VALIANT_OF_THE_EXODAR = 13690, + QUEST_VALIANT_OF_ORGRIMMAR = 13707, + QUEST_A_VALIANT_OF_ORGRIMMAR = 13691, + QUEST_VALIANT_OF_SEN_JIN = 13708, + QUEST_A_VALIANT_OF_SEN_JIN = 13693, + QUEST_VALIANT_OF_THUNDER_BLUFF = 13709, + QUEST_A_VALIANT_OF_THUNDER_BLUFF = 13694, + QUEST_VALIANT_OF_UNDERCITY = 13710, + QUEST_A_VALIANT_OF_UNDERCITY = 13695, + QUEST_VALIANT_OF_SILVERMOON = 13711, + QUEST_A_VALIANT_OF_SILVERMOON = 13696, +}; + +class spell_gen_on_tournament_mount : public SpellScriptLoader +{ + public: + spell_gen_on_tournament_mount() : SpellScriptLoader("spell_gen_on_tournament_mount") { } + + class spell_gen_on_tournament_mountAuraScript : public AuraScript + { + PrepareAuraScript(spell_gen_on_tournament_mountAuraScript); + + uint32 _pennantSpellId; + + bool Load() + { + _pennantSpellId = 0; + return (GetCaster()->GetTypeId() == TYPEID_PLAYER); + } + + void HandleApplyEffect(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* caster = GetCaster(); + + if (caster && caster->GetVehicleBase()) + { + _pennantSpellId = GetPennatSpellId(caster->ToPlayer(), caster->GetVehicleBase()); + caster->CastSpell(caster, _pennantSpellId,true); + } + } + + void HandleRemoveEffect(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* caster = GetCaster(); + + if (caster) + caster->RemoveAurasDueToSpell(_pennantSpellId); + } + + uint32 GetPennatSpellId(Player* player, Unit* mount) + { + switch (mount->GetEntry()) + { + case NPC_ARGENT_STEED_ASPIRANT: + case NPC_STORMWIND_STEED: + { + if (player->GetAchievementMgr().HasAchieved(ACHIEVEMENT_CHAMPION_STORMWIND)) + return SPELL_PENNANT_STORMWIND_CHAMPION; + else if (player->GetQuestRewardStatus(QUEST_VALIANT_OF_STORMWIND) || player->GetQuestRewardStatus(QUEST_A_VALIANT_OF_STORMWIND)) + return SPELL_PENNANT_STORMWIND_VALIANT; + else + return SPELL_PENNANT_STORMWIND_ASPIRANT; + } + case NPC_GNOMEREGAN_MECHANOSTRIDER: + { + if (player->GetAchievementMgr().HasAchieved(ACHIEVEMENT_CHAMPION_GNOMEREGAN)) + return SPELL_PENNANT_GNOMEREGAN_CHAMPION; + else if (player->GetQuestRewardStatus(QUEST_VALIANT_OF_GNOMEREGAN) || player->GetQuestRewardStatus(QUEST_A_VALIANT_OF_GNOMEREGAN)) + return SPELL_PENNANT_GNOMEREGAN_VALIANT; + else + return SPELL_PENNANT_GNOMEREGAN_ASPIRANT; + } + case NPC_DARK_SPEAR_RAPTOR: + { + if (player->GetAchievementMgr().HasAchieved(ACHIEVEMENT_CHAMPION_SEN_JIN)) + return SPELL_PENNANT_SEN_JIN_CHAMPION; + else if (player->GetQuestRewardStatus(QUEST_VALIANT_OF_SEN_JIN) || player->GetQuestRewardStatus(QUEST_A_VALIANT_OF_SEN_JIN)) + return SPELL_PENNANT_SEN_JIN_VALIANT; + else + return SPELL_PENNANT_SEN_JIN_ASPIRANT; + } + case NPC_ARGENT_HAWKSTRIDER_ASPIRANT: + case NPC_SILVERMOON_HAWKSTRIDER: + { + if (player->GetAchievementMgr().HasAchieved(ACHIEVEMENT_CHAMPION_SILVERMOON)) + return SPELL_PENNANT_SILVERMOON_CHAMPION; + else if (player->GetQuestRewardStatus(QUEST_VALIANT_OF_SILVERMOON) || player->GetQuestRewardStatus(QUEST_A_VALIANT_OF_SILVERMOON)) + return SPELL_PENNANT_SILVERMOON_VALIANT; + else + return SPELL_PENNANT_SILVERMOON_ASPIRANT; + } + case NPC_DARNASSIAN_NIGHTSABER: + { + if (player->GetAchievementMgr().HasAchieved(ACHIEVEMENT_CHAMPION_DARNASSUS)) + return SPELL_PENNANT_DARNASSUS_CHAMPION; + else if (player->GetQuestRewardStatus(QUEST_VALIANT_OF_DARNASSUS) || player->GetQuestRewardStatus(QUEST_A_VALIANT_OF_DARNASSUS)) + return SPELL_PENNANT_DARNASSUS_VALIANT; + else + return SPELL_PENNANT_DARNASSUS_ASPIRANT; + } + case NPC_EXODAR_ELEKK: + { + if (player->GetAchievementMgr().HasAchieved(ACHIEVEMENT_CHAMPION_THE_EXODAR)) + return SPELL_PENNANT_EXODAR_CHAMPION; + else if (player->GetQuestRewardStatus(QUEST_VALIANT_OF_THE_EXODAR) || player->GetQuestRewardStatus(QUEST_A_VALIANT_OF_THE_EXODAR)) + return SPELL_PENNANT_EXODAR_VALIANT; + else + return SPELL_PENNANT_EXODAR_ASPIRANT; + } + case NPC_IRONFORGE_RAM: + { + if (player->GetAchievementMgr().HasAchieved(ACHIEVEMENT_CHAMPION_IRONFORGE)) + return SPELL_PENNANT_IRONFORGE_CHAMPION; + else if (player->GetQuestRewardStatus(QUEST_VALIANT_OF_IRONFORGE) || player->GetQuestRewardStatus(QUEST_A_VALIANT_OF_IRONFORGE)) + return SPELL_PENNANT_IRONFORGE_VALIANT; + else + return SPELL_PENNANT_IRONFORGE_ASPIRANT; + } + case NPC_FORSAKEN_WARHORSE: + { + if (player->GetAchievementMgr().HasAchieved(ACHIEVEMENT_CHAMPION_UNDERCITY)) + return SPELL_PENNANT_UNDERCITY_CHAMPION; + else if (player->GetQuestRewardStatus(QUEST_VALIANT_OF_UNDERCITY) || player->GetQuestRewardStatus(QUEST_A_VALIANT_OF_UNDERCITY)) + return SPELL_PENNANT_UNDERCITY_VALIANT; + else + return SPELL_PENNANT_UNDERCITY_ASPIRANT; + } + case NPC_ORGRIMMAR_WOLF: + { + if (player->GetAchievementMgr().HasAchieved(ACHIEVEMENT_CHAMPION_ORGRIMMAR)) + return SPELL_PENNANT_ORGRIMMAR_CHAMPION; + else if (player->GetQuestRewardStatus(QUEST_VALIANT_OF_ORGRIMMAR) || player->GetQuestRewardStatus(QUEST_A_VALIANT_OF_ORGRIMMAR)) + return SPELL_PENNANT_ORGRIMMAR_VALIANT; + else + return SPELL_PENNANT_ORGRIMMAR_ASPIRANT; + } + case NPC_THUNDER_BLUFF_KODO: + { + if (player->GetAchievementMgr().HasAchieved(ACHIEVEMENT_CHAMPION_THUNDER_BLUFF)) + return SPELL_PENNANT_THUNDER_BLUFF_CHAMPION; + else if (player->GetQuestRewardStatus(QUEST_VALIANT_OF_THUNDER_BLUFF) || player->GetQuestRewardStatus(QUEST_A_VALIANT_OF_THUNDER_BLUFF)) + return SPELL_PENNANT_THUNDER_BLUFF_VALIANT; + else + return SPELL_PENNANT_THUNDER_BLUFF_ASPIRANT; + } + case NPC_ARGENT_WARHORSE: + { + if (player->GetAchievementMgr().HasAchieved(ACHIEVEMENT_CHAMPION_ALLIANCE) || player->GetAchievementMgr().HasAchieved(ACHIEVEMENT_CHAMPION_HORDE)) + return player->getClass() == CLASS_DEATH_KNIGHT ? SPELL_PENNANT_EBON_BLADE_CHAMPION : SPELL_PENNANT_ARGENT_CRUSADE_CHAMPION; + else if (player->GetAchievementMgr().HasAchieved(ACHIEVEMENT_ARGENT_VALOR)) + return player->getClass() == CLASS_DEATH_KNIGHT ? SPELL_PENNANT_EBON_BLADE_VALIANT : SPELL_PENNANT_ARGENT_CRUSADE_VALIANT; + else + return player->getClass() == CLASS_DEATH_KNIGHT ? SPELL_PENNANT_EBON_BLADE_ASPIRANT : SPELL_PENNANT_ARGENT_CRUSADE_ASPIRANT; + } + default: + return 0; + } + } + + void Register() + { + AfterEffectApply += AuraEffectApplyFn(spell_gen_on_tournament_mountAuraScript::HandleApplyEffect, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); + OnEffectRemove += AuraEffectRemoveFn(spell_gen_on_tournament_mountAuraScript::HandleRemoveEffect, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_gen_on_tournament_mountAuraScript(); + } +}; + +class spell_gen_tournament_pennant : public SpellScriptLoader +{ + public: + spell_gen_tournament_pennant() : SpellScriptLoader("spell_gen_tournament_pennant") { } + + class spell_gen_tournament_pennantAuraScript : public AuraScript + { + PrepareAuraScript(spell_gen_tournament_pennantAuraScript); + + void HandleApplyEffect(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* caster = GetCaster(); + + if (caster && caster->GetTypeId() == TYPEID_PLAYER && !caster->GetVehicleBase()) + caster->RemoveAurasDueToSpell(GetId()); + } + + void Register() + { + OnEffectApply += AuraEffectApplyFn(spell_gen_tournament_pennantAuraScript::HandleApplyEffect, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_gen_tournament_pennantAuraScript(); + } +}; + void AddSC_generic_spell_scripts() { new spell_gen_absorb0_hitlimit1(); @@ -1662,4 +2404,11 @@ void AddSC_generic_spell_scripts() new spell_gen_dalaran_disguise("spell_gen_sunreaver_disguise"); new spell_gen_dalaran_disguise("spell_gen_silver_covenant_disguise"); new spell_gen_elune_candle(); + new spell_gen_break_shield(); + new spell_gen_mounted_charge(); + new spell_gen_defend(); + new spell_gen_tournament_duel(); + new spell_gen_summon_tournament_mount(); + new spell_gen_on_tournament_mount(); + new spell_gen_tournament_pennant(); } diff --git a/src/server/scripts/World/achievement_scripts.cpp b/src/server/scripts/World/achievement_scripts.cpp index 8ce06685893..135f22e0a01 100755 --- a/src/server/scripts/World/achievement_scripts.cpp +++ b/src/server/scripts/World/achievement_scripts.cpp @@ -285,6 +285,17 @@ class achievement_bg_sa_defense_of_ancients : public AchievementCriteriaScript } }; +class achievement_tilted : public AchievementCriteriaScript +{ + public: + achievement_tilted() : AchievementCriteriaScript("achievement_tilted") {} + + bool OnCheck(Player* player, Unit* /*target*/) + { + return player && player->duel && player->duel->isMounted; + } +}; + void AddSC_achievement_scripts() { new achievement_resilient_victory(); @@ -302,4 +313,5 @@ void AddSC_achievement_scripts() new achievement_arena_kills("achievement_arena_3v3_kills", ARENA_TYPE_3v3); new achievement_arena_kills("achievement_arena_5v5_kills", ARENA_TYPE_5v5); new achievement_bg_sa_defense_of_ancients(); + new achievement_tilted(); } -- cgit v1.2.3 From 83e0486e59ddf17ef8abc83b57ff459f8b9e1e9c Mon Sep 17 00:00:00 2001 From: Shauren Date: Mon, 30 Jan 2012 12:31:59 +0100 Subject: Scripts/Icecrown Citadel: Professor Putricide will now remove Mutated Plague from players when dying --- .../world/2012_01_30_01_world_conditions.sql | 3 +++ .../2012_01_30_01_world_spell_script_names.sql | 3 +++ .../IcecrownCitadel/boss_professor_putricide.cpp | 31 ++++++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 sql/updates/world/2012_01_30_01_world_conditions.sql create mode 100644 sql/updates/world/2012_01_30_01_world_spell_script_names.sql (limited to 'src/server/scripts') diff --git a/sql/updates/world/2012_01_30_01_world_conditions.sql b/sql/updates/world/2012_01_30_01_world_conditions.sql new file mode 100644 index 00000000000..bcaf0af435a --- /dev/null +++ b/sql/updates/world/2012_01_30_01_world_conditions.sql @@ -0,0 +1,3 @@ +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=72618; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES +(13,0,72618,0,0,18,1,0,0,0, '', 'Mutated Plague Clear - target players'); diff --git a/sql/updates/world/2012_01_30_01_world_spell_script_names.sql b/sql/updates/world/2012_01_30_01_world_spell_script_names.sql new file mode 100644 index 00000000000..6e4b10094e5 --- /dev/null +++ b/sql/updates/world/2012_01_30_01_world_spell_script_names.sql @@ -0,0 +1,3 @@ +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_putricide_clear_mutated_plague'; +INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES +(72618,'spell_putricide_clear_mutated_plague'); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index 0d3640504c1..cf22338995b 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -75,6 +75,7 @@ enum Spells SPELL_PLAGUE_SICKNESS = 70953, SPELL_UNBOUND_PLAGUE_PROTECTION = 70955, SPELL_MUTATED_PLAGUE = 72451, + SPELL_MUTATED_PLAGUE_CLEAR = 72618, // Slime Puddle SPELL_GROW_STACKER = 70345, @@ -244,6 +245,7 @@ class boss_professor_putricide : public CreatureScript { _JustDied(); Talk(SAY_DEATH); + DoCast(SPELL_MUTATED_PLAGUE_CLEAR); } void JustSummoned(Creature* summon) @@ -1427,6 +1429,34 @@ class spell_putricide_regurgitated_ooze : public SpellScriptLoader } }; +class spell_putricide_clear_mutated_plague : public SpellScriptLoader +{ + public: + spell_putricide_clear_mutated_plague() : SpellScriptLoader("spell_putricide_clear_mutated_plague") { } + + class spell_putricide_clear_mutated_plague_SpellScript : public SpellScript + { + PrepareSpellScript(spell_putricide_clear_mutated_plague_SpellScript); + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + uint32 auraId = sSpellMgr->GetSpellIdForDifficulty(uint32(GetEffectValue()), GetCaster()); + GetHitUnit()->RemoveAurasDueToSpell(auraId); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_putricide_clear_mutated_plague_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_putricide_clear_mutated_plague_SpellScript(); + } +}; + // Stinky and Precious spell, it's here because its used for both (Festergut and Rotface "pets") class spell_stinky_precious_decimate : public SpellScriptLoader { @@ -1478,5 +1508,6 @@ void AddSC_boss_professor_putricide() new spell_putricide_mutated_transformation(); new spell_putricide_mutated_transformation_dmg(); new spell_putricide_regurgitated_ooze(); + new spell_putricide_clear_mutated_plague(); new spell_stinky_precious_decimate(); } -- cgit v1.2.3 From 0f0672ef3ba755e1963036a12280d479915ee42d Mon Sep 17 00:00:00 2001 From: Bootz Date: Mon, 30 Jan 2012 06:13:20 -0600 Subject: Build System: Remove the 14month old source directories out of CMakeLists.txts These were added back when trinity dropped framework...and are no longer needed. Signed-off-by: Bootz --- src/server/game/CMakeLists.txt | 2 -- src/server/scripts/CMakeLists.txt | 2 -- src/server/worldserver/CMakeLists.txt | 2 -- 3 files changed, 6 deletions(-) (limited to 'src/server/scripts') diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index e97b8961554..745e5962eb6 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -117,12 +117,10 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Database ${CMAKE_SOURCE_DIR}/src/server/shared/DataStores ${CMAKE_SOURCE_DIR}/src/server/shared/Debugging - ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/CountedReference ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/LinkedReference ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic ${CMAKE_SOURCE_DIR}/src/server/shared/Logging ${CMAKE_SOURCE_DIR}/src/server/shared/Packets - ${CMAKE_SOURCE_DIR}/src/server/shared/Policies ${CMAKE_SOURCE_DIR}/src/server/shared/Threading ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities ${CMAKE_CURRENT_SOURCE_DIR} diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt index d43cce45c00..56e63af5bbf 100644 --- a/src/server/scripts/CMakeLists.txt +++ b/src/server/scripts/CMakeLists.txt @@ -61,12 +61,10 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Database ${CMAKE_SOURCE_DIR}/src/server/shared/DataStores ${CMAKE_SOURCE_DIR}/src/server/shared/Debugging - ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/CountedReference ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/LinkedReference ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic ${CMAKE_SOURCE_DIR}/src/server/shared/Logging ${CMAKE_SOURCE_DIR}/src/server/shared/Packets - ${CMAKE_SOURCE_DIR}/src/server/shared/Policies ${CMAKE_SOURCE_DIR}/src/server/shared/Threading ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities ${CMAKE_SOURCE_DIR}/src/server/collision diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt index e2b70c9c673..191bbbf35b4 100644 --- a/src/server/worldserver/CMakeLists.txt +++ b/src/server/worldserver/CMakeLists.txt @@ -57,12 +57,10 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Database ${CMAKE_SOURCE_DIR}/src/server/shared/DataStores ${CMAKE_SOURCE_DIR}/src/server/shared/Debugging - ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/CountedReference ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/LinkedReference ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic ${CMAKE_SOURCE_DIR}/src/server/shared/Logging ${CMAKE_SOURCE_DIR}/src/server/shared/Packets - ${CMAKE_SOURCE_DIR}/src/server/shared/Policies ${CMAKE_SOURCE_DIR}/src/server/shared/Threading ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities ${CMAKE_SOURCE_DIR}/src/server/game -- cgit v1.2.3