diff --git a/data/sql/updates/pending_db_world/rev_1674333933272138700.sql b/data/sql/updates/pending_db_world/rev_1674333933272138700.sql new file mode 100644 index 000000000..72f2d5f52 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1674333933272138700.sql @@ -0,0 +1,238 @@ +-- +UPDATE `creature_template` SET `ScriptName` = "npc_chesspiece", `flags_extra`=`flags_extra`|0x01000000 WHERE `entry` IN (17469,17211,21748,21664,21750,21683,21747,21682,21726,21160,21752,21684); +UPDATE `creature_template` SET `ScriptName` = "npc_echo_of_medivh" WHERE `entry`=16816; +UPDATE `creature_template` SET `ScriptName` = "npc_chess_move_trigger", `flags_extra`=130 WHERE `entry`=22519; + +DELETE FROM `creature` WHERE `id1`=22519; + +DELETE FROM `creature_template_addon` WHERE `entry`=22521; +INSERT INTO `creature_template_addon` (`entry`,`bytes2`,`auras`) VALUES +(22521,1,'39383'); + +UPDATE `creature_template` SET `flags_extra` = 130 WHERE `entry` = 22521; + +DELETE FROM `creature_template_spell` WHERE `CreatureID` IN (21684,21683,21682,21664,21160,17211,21752,21750,21747,21748,21726,17469); +INSERT INTO `creature_template_spell` (`CreatureID`, `Index`, `Spell`, `VerifiedBuild`) VALUES +(21684, 0, 37146, 12340), -- King Llane +(21684, 1, 30284, 12340), +(21684, 2, 37471, 12340), +(21684, 3, 37474, 12340), +(21683, 0, 37148, 12340), -- Human Conjurer +(21683, 1, 30284, 12340), +(21683, 2, 37462, 12340), +(21683, 3, 37465, 12340), +(21682, 0, 37146, 12340), -- Human Cleric +(21682, 1, 30284, 12340), +(21682, 2, 37455, 12340), +(21682, 3, 37459, 12340), +(21664, 0, 37144, 12340), -- Human Charger +(21664, 1, 30284, 12340), +(21664, 2, 37453, 12340), +(21664, 3, 37498, 12340), +(21160, 0, 37146, 12340), -- Conjured Water Elemental +(21160, 1, 30284, 12340), +(21160, 2, 37427, 12340), +(21160, 3, 37432, 12340), +(17211, 0, 37146, 12340), -- Human Footman +(17211, 1, 30284, 12340), +(17211, 2, 37406, 12340), +(17211, 3, 37414, 12340), +(21752, 0, 37146, 12340), -- Warchief Blackhand +(21752, 1, 30284, 12340), +(21752, 2, 37472, 12340), +(21752, 3, 37476, 12340), +(21750, 0, 37148, 12340), -- Orc Warlock +(21750, 1, 30284, 12340), +(21750, 2, 37463, 12340), +(21750, 3, 37461, 12340), +(21747, 0, 37146, 12340), -- Orc Necrolyte +(21747, 1, 30284, 12340), +(21747, 2, 37456, 12340), +(21747, 3, 37461, 12340), +(21748, 0, 37144, 12340), -- Orc Wolf +(21748, 1, 30284, 12340), +(21748, 2, 37454, 12340), +(21748, 3, 37502, 12340), +(21726, 0, 37146, 12340), -- Summoned Daemon +(21726, 1, 30284, 12340), +(21726, 2, 37428, 12340), +(21726, 3, 37434, 12340), +(17469, 0, 37146, 12340), -- Orc Grunt +(17469, 1, 30284, 12340), +(17469, 2, 37413, 12340), +(17469, 3, 37416, 12340); + +UPDATE `creature_template` SET `RegenHealth`=0, `BaseAttackTime`=3000 WHERE `entry` IN (21726,21748,21747,21750,21752,17469,21160,21664,21682,21684,21683,17211); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 13 AND `SourceEntry` IN (37465,37476,30012,37144,37148,37151,37152,37153,37472,37461,37454,37502,37428,37413,37471,37474,37459,37453,37498,37427,37406,39384,37462,37455,37463,37456,37144,37146,37148,30284,37469); +INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`ScriptName`,`Comment`) VALUES +(13,1,37146,0,31,3,22519,0,'',"Move - Target Chess Piece: Karazhan Invisible Stalker"), +(13,1,30012,0,31,3,22519,0,'',"Move - Target Chess Piece: Karazhan Invisible Stalker"), +(13,1,37144,0,31,3,22519,0,'',"Move - Target Chess Piece: Karazhan Invisible Stalker"), +(13,1,37148,0,31,3,22519,0,'',"Move - Target Chess Piece: Karazhan Invisible Stalker"), +(13,1,37151,0,31,3,22519,0,'',"Move - Target Chess Piece: Karazhan Invisible Stalker"), +(13,1,37152,0,31,3,22519,0,'',"Move - Target Chess Piece: Karazhan Invisible Stalker"), +(13,1,37153,0,31,3,22519,0,'',"Move - Target Chess Piece: Karazhan Invisible Stalker"), + +(13,3,30284,0,31,3,22519,0,'',"Change Facing - Target Chess Piece: Karazhan Invisible Stalker"), + +(13,1,39384,0,31,3,21752,0,'',"Alliance and Horde Chess Spell - Burning Flames - Target Alliance and Horde Pieces"), +(13,1,39384,1,31,3,21750,0,'',"Alliance and Horde Chess Spell - Burning Flames - Target Alliance and Horde Pieces"), +(13,1,39384,2,31,3,21747,0,'',"Alliance and Horde Chess Spell - Burning Flames - Target Alliance and Horde Pieces"), +(13,1,39384,3,31,3,21748,0,'',"Alliance and Horde Chess Spell - Burning Flames - Target Alliance and Horde Pieces"), +(13,1,39384,4,31,3,21726,0,'',"Alliance and Horde Chess Spell - Burning Flames - Target Alliance and Horde Pieces"), +(13,1,39384,5,31,3,17469,0,'',"Alliance and Horde Chess Spell - Burning Flames - Target Alliance and Horde Pieces"), +(13,2,39384,0,31,3,21683,0,'',"Alliance and Horde Chess Spell - Burning Flames - Target Alliance and Horde Pieces"), +(13,2,39384,1,31,3,21684,0,'',"Alliance and Horde Chess Spell - Burning Flames - Target Alliance and Horde Pieces"), +(13,2,39384,2,31,3,21682,0,'',"Alliance and Horde Chess Spell - Burning Flames - Target Alliance and Horde Pieces"), +(13,2,39384,3,31,3,21664,0,'',"Alliance and Horde Chess Spell - Burning Flames - Target Alliance and Horde Pieces"), +(13,2,39384,4,31,3,21160,0,'',"Alliance and Horde Chess Spell - Burning Flames - Target Alliance and Horde Pieces"), +(13,2,39384,5,31,3,17211,0,'',"Alliance and Horde Chess Spell - Burning Flames - Target Alliance and Horde Pieces"), + +(13,1,37471,0,31,3,21683,0,'',"Alliance Chess Spell - Heroism - Target Alliance Pieces"), +(13,1,37471,1,31,3,21684,0,'',"Alliance Chess Spell - Heroism - Target Alliance Pieces"), +(13,1,37471,2,31,3,21682,0,'',"Alliance Chess Spell - Heroism - Target Alliance Pieces"), +(13,1,37471,3,31,3,21664,0,'',"Alliance Chess Spell - Heroism - Target Alliance Pieces"), +(13,1,37471,4,31,3,21160,0,'',"Alliance Chess Spell - Heroism - Target Alliance Pieces"), +(13,1,37471,5,31,3,17211,0,'',"Alliance Chess Spell - Heroism - Target Alliance Pieces"), + +(13,1,37459,0,31,3,21752,0,'',"Alliance Chess Spell - Holy Lance - Target Horde Pieces"), +(13,1,37459,1,31,3,21750,0,'',"Alliance Chess Spell - Holy Lance - Target Horde Pieces"), +(13,1,37459,2,31,3,21747,0,'',"Alliance Chess Spell - Holy Lance - Target Horde Pieces"), +(13,1,37459,3,31,3,21748,0,'',"Alliance Chess Spell - Holy Lance - Target Horde Pieces"), +(13,1,37459,4,31,3,21726,0,'',"Alliance Chess Spell - Holy Lance - Target Horde Pieces"), +(13,1,37459,5,31,3,17469,0,'',"Alliance Chess Spell - Holy Lance - Target Horde Pieces"), + +(13,1,37453,0,31,3,21752,0,'',"Alliance Chess Spell - Smash - Target Horde Pieces"), +(13,1,37453,1,31,3,21750,0,'',"Alliance Chess Spell - Smash - Target Horde Pieces"), +(13,1,37453,2,31,3,21747,0,'',"Alliance Chess Spell - Smash - Target Horde Pieces"), +(13,1,37453,3,31,3,21748,0,'',"Alliance Chess Spell - Smash - Target Horde Pieces"), +(13,1,37453,4,31,3,21726,0,'',"Alliance Chess Spell - Smash - Target Horde Pieces"), +(13,1,37453,5,31,3,17469,0,'',"Alliance Chess Spell - Smash - Target Horde Pieces"), + +(13,1,37427,0,31,3,21752,0,'',"Alliance Chess Spell - Geyser - Target Horde Pieces"), +(13,1,37427,1,31,3,21750,0,'',"Alliance Chess Spell - Geyser - Target Horde Pieces"), +(13,1,37427,2,31,3,21747,0,'',"Alliance Chess Spell - Geyser - Target Horde Pieces"), +(13,1,37427,3,31,3,21748,0,'',"Alliance Chess Spell - Geyser - Target Horde Pieces"), +(13,1,37427,4,31,3,21726,0,'',"Alliance Chess Spell - Geyser - Target Horde Pieces"), +(13,1,37427,5,31,3,17469,0,'',"Alliance Chess Spell - Geyser - Target Horde Pieces"), + +(13,1,37474,0,31,3,21752,0,'',"Alliance Chess Spell - Sweep - Target Horde Pieces"), +(13,1,37474,1,31,3,21750,0,'',"Alliance Chess Spell - Sweep - Target Horde Pieces"), +(13,1,37474,2,31,3,21747,0,'',"Alliance Chess Spell - Sweep - Target Horde Pieces"), +(13,1,37474,3,31,3,21748,0,'',"Alliance Chess Spell - Sweep - Target Horde Pieces"), +(13,1,37474,4,31,3,21726,0,'',"Alliance Chess Spell - Sweep - Target Horde Pieces"), +(13,1,37474,5,31,3,17469,0,'',"Alliance Chess Spell - Sweep - Target Horde Pieces"), + +(13,1,37465,0,31,3,21752,0,'',"Alliance Chess Spell - Rain of Fire - Target Horde Pieces"), +(13,1,37465,1,31,3,21750,0,'',"Alliance Chess Spell - Rain of Fire - Target Horde Pieces"), +(13,1,37465,2,31,3,21747,0,'',"Alliance Chess Spell - Rain of Fire - Target Horde Pieces"), +(13,1,37465,3,31,3,21748,0,'',"Alliance Chess Spell - Rain of Fire - Target Horde Pieces"), +(13,1,37465,4,31,3,21726,0,'',"Alliance Chess Spell - Rain of Fire - Target Horde Pieces"), +(13,1,37465,5,31,3,17469,0,'',"Alliance Chess Spell - Rain of Fire - Target Horde Pieces"), + +(13,1,37498,0,31,3,21752,0,'',"Alliance Chess Spell - Stomp - Target Horde Pieces"), +(13,1,37498,1,31,3,21750,0,'',"Alliance Chess Spell - Stomp - Target Horde Pieces"), +(13,1,37498,2,31,3,21747,0,'',"Alliance Chess Spell - Stomp - Target Horde Pieces"), +(13,1,37498,3,31,3,21748,0,'',"Alliance Chess Spell - Stomp - Target Horde Pieces"), +(13,1,37498,4,31,3,21726,0,'',"Alliance Chess Spell - Stomp - Target Horde Pieces"), +(13,1,37498,5,31,3,17469,0,'',"Alliance Chess Spell - Stomp - Target Horde Pieces"), + +(13,1,37406,0,31,3,21752,0,'',"Alliance Chess Spell - Heroic Blow - Target Horde Pieces"), +(13,1,37406,1,31,3,21750,0,'',"Alliance Chess Spell - Heroic Blow - Target Horde Pieces"), +(13,1,37406,2,31,3,21747,0,'',"Alliance Chess Spell - Heroic Blow - Target Horde Pieces"), +(13,1,37406,3,31,3,21748,0,'',"Alliance Chess Spell - Heroic Blow - Target Horde Pieces"), +(13,1,37406,4,31,3,21726,0,'',"Alliance Chess Spell - Heroic Blow - Target Horde Pieces"), +(13,1,37406,5,31,3,17469,0,'',"Alliance Chess Spell - Heroic Blow - Target Horde Pieces"), + +(13,1,37472,0,31,3,21752,0,'',"Horde Chess Spell - Bloodlust - Target Horde Pieces"), +(13,1,37472,1,31,3,21750,0,'',"Horde Chess Spell - Bloodlust - Target Horde Pieces"), +(13,1,37472,2,31,3,21747,0,'',"Horde Chess Spell - Bloodlust - Target Horde Pieces"), +(13,1,37472,3,31,3,21748,0,'',"Horde Chess Spell - Bloodlust - Target Horde Pieces"), +(13,1,37472,4,31,3,21726,0,'',"Horde Chess Spell - Bloodlust - Target Horde Pieces"), +(13,1,37472,5,31,3,17469,0,'',"Horde Chess Spell - Bloodlust - Target Horde Pieces"), + +(13,1,37461,0,31,3,21683,0,'',"Horde Chess Spell - Shadow Spear - Target Alliance Pieces"), +(13,1,37461,1,31,3,21684,0,'',"Horde Chess Spell - Shadow Spear - Target Alliance Pieces"), +(13,1,37461,2,31,3,21682,0,'',"Horde Chess Spell - Shadow Spear - Target Alliance Pieces"), +(13,1,37461,3,31,3,21664,0,'',"Horde Chess Spell - Shadow Spear - Target Alliance Pieces"), +(13,1,37461,4,31,3,21160,0,'',"Horde Chess Spell - Shadow Spear - Target Alliance Pieces"), +(13,1,37461,5,31,3,17211,0,'',"Horde Chess Spell - Shadow Spear - Target Alliance Pieces"), + +(13,1,37502,0,31,3,21683,0,'',"Horde Chess Spell - Howl - Target Alliance Pieces"), +(13,1,37502,1,31,3,21684,0,'',"Horde Chess Spell - Howl - Target Alliance Pieces"), +(13,1,37502,2,31,3,21682,0,'',"Horde Chess Spell - Howl - Target Alliance Pieces"), +(13,1,37502,3,31,3,21664,0,'',"Horde Chess Spell - Howl - Target Alliance Pieces"), +(13,1,37502,4,31,3,21160,0,'',"Horde Chess Spell - Howl - Target Alliance Pieces"), +(13,1,37502,5,31,3,17211,0,'',"Horde Chess Spell - Howl - Target Alliance Pieces"), + +(13,1,37428,0,31,3,21683,0,'',"Horde Chess Spell - Hellfire - Target Alliance Pieces"), +(13,1,37428,1,31,3,21684,0,'',"Horde Chess Spell - Hellfire - Target Alliance Pieces"), +(13,1,37428,2,31,3,21682,0,'',"Horde Chess Spell - Hellfire - Target Alliance Pieces"), +(13,1,37428,3,31,3,21664,0,'',"Horde Chess Spell - Hellfire - Target Alliance Pieces"), +(13,1,37428,4,31,3,21160,0,'',"Horde Chess Spell - Hellfire - Target Alliance Pieces"), +(13,1,37428,5,31,3,17211,0,'',"Horde Chess Spell - Hellfire - Target Alliance Pieces"), + +(13,1,37476,0,31,3,21683,0,'',"Horde Chess Spell - Cleave - Target Alliance Pieces"), +(13,1,37476,1,31,3,21684,0,'',"Horde Chess Spell - Cleave - Target Alliance Pieces"), +(13,1,37476,2,31,3,21682,0,'',"Horde Chess Spell - Cleave - Target Alliance Pieces"), +(13,1,37476,3,31,3,21664,0,'',"Horde Chess Spell - Cleave - Target Alliance Pieces"), +(13,1,37476,4,31,3,21160,0,'',"Horde Chess Spell - Cleave - Target Alliance Pieces"), +(13,1,37476,5,31,3,17211,0,'',"Horde Chess Spell - Cleave - Target Alliance Pieces"), + +(13,1,37469,0,31,3,21683,0,'',"Horde Chess Spell - Poison Cloud - Target Alliance Pieces"), +(13,1,37469,1,31,3,21684,0,'',"Horde Chess Spell - Poison Cloud - Target Alliance Pieces"), +(13,1,37469,2,31,3,21682,0,'',"Horde Chess Spell - Poison Cloud - Target Alliance Pieces"), +(13,1,37469,3,31,3,21664,0,'',"Horde Chess Spell - Poison Cloud - Target Alliance Pieces"), +(13,1,37469,4,31,3,21160,0,'',"Horde Chess Spell - Poison Cloud - Target Alliance Pieces"), +(13,1,37469,5,31,3,17211,0,'',"Horde Chess Spell - Poison Cloud - Target Alliance Pieces"), + +(13,1,37454,0,31,3,21683,0,'',"Horde Chess Spell - Bite - Target Alliance Pieces"), +(13,1,37454,1,31,3,21684,0,'',"Horde Chess Spell - Bite - Target Alliance Pieces"), +(13,1,37454,2,31,3,21682,0,'',"Horde Chess Spell - Bite - Target Alliance Pieces"), +(13,1,37454,3,31,3,21664,0,'',"Horde Chess Spell - Bite - Target Alliance Pieces"), +(13,1,37454,4,31,3,21160,0,'',"Horde Chess Spell - Bite - Target Alliance Pieces"), +(13,1,37454,5,31,3,17211,0,'',"Horde Chess Spell - Bite - Target Alliance Pieces"), + +(13,1,37413,0,31,3,21683,0,'',"Horde Chess Spell - Vicious Strike - Target Alliance Pieces"), +(13,1,37413,1,31,3,21684,0,'',"Horde Chess Spell - Vicious Strike - Target Alliance Pieces"), +(13,1,37413,2,31,3,21682,0,'',"Horde Chess Spell - Vicious Strike - Target Alliance Pieces"), +(13,1,37413,3,31,3,21664,0,'',"Horde Chess Spell - Vicious Strike - Target Alliance Pieces"), +(13,1,37413,4,31,3,21160,0,'',"Horde Chess Spell - Vicious Strike - Target Alliance Pieces"), +(13,1,37413,5,31,3,17211,0,'',"Horde Chess Spell - Vicious Strike - Target Alliance Pieces"); + +DELETE FROM `creature_text` WHERE `CreatureID`=16816; +INSERT INTO `creature_text` VALUES +(16816,0,0,'Very well. Let the game begin.',14,0,100,0,0,10338,0,0,'Echo of Medivh - EventBegin'), +(16816,1,0,'Perhaps a change is in order.',14,0,100,0,0,10357,0,0,'Echo of Medivh - Cheat 1'), +(16816,1,1,'Time for an alternative scenario.',14,0,100,0,0,10358,0,0,'Echo of Medivh - Cheat 2'), +(16816,1,2,'One must not become too complacent.',14,0,100,0,0,10359,0,0,'Echo of Medivh - Cheat 3'), +(16816,2,0,'%s cheats',16,0,100,0,0,0,21910,0,'Echo of Medivh - CheatEmote'), +(16816,3,0,'Let us see.',14,0,100,0,0,10340,0,0,'Echo of Medivh - Player Loose Pawn 1'), +(16816,3,1,'A transparent stratagem.',14,0,100,0,0,10339,0,0,'Echo of Medivh - Player Loose Pawn 2'), +(16816,3,2,'Ah, the wheels have begun to turn.',14,0,100,0,0,10341,0,0,'Echo of Medivh - Player Loose Pawn 3'), +(16816,4,0,'Foolish! Very foolish!',14,0,100,0,0,10345,0,0,'Echo of Medivh - Player Loose Rook'), +(16816,5,0,'Yes... all according to plan.',14,0,100,0,0,10349,0,0,'Echo of Medivh - Player Loose Knight'), +(16816,6,0,'The slightest loss of concentration is all it takes.',14,0,100,0,0,10347,0,0,'Echo of Medivh - Player Loose Bishop'), +(16816,7,0,'Now it gets interesting.',14,0,100,0,0,10351,0,0,'Echo of Medivh - Player Loose Queen'), +(16816,8,0,'As it should be.',14,0,100,0,0,10354,0,0,'Echo of Medivh - Player Loose King'), +(16816,9,0,'Hmm.',14,0,100,0,0,10342,0,0,'Echo of Medivh - Medivh Loose Pawn 1'), +(16816,9,1,'No matter.',14,0,100,0,0,10344,0,0,'Echo of Medivh - Medivh Loose Pawn 2'), +(16816,9,2,'Interesting.',14,0,100,0,0,10343,0,0,'Echo of Medivh - Medivh Loose Pawn 3'), +(16816,10,0,'A minor concern.',14,0,100,0,0,10346,0,0,'Echo of Medivh - Medivh Loose Rook'), +(16816,11,0,'Yes...of course.',14,0,100,0,0,10350,0,0,'Echo of Medivh - Medivh Loose Knight'), +(16816,12,0,'A necessary sacrifice.',14,0,100,0,0,10348,0,0,'Echo of Medivh - Medivh Loose Bishop'), +(16816,13,0,'Ahh, I should have known.',14,0,100,0,0,10352,0,0,'Echo of Medivh - Medivh Loose Queen'), +(16816,14,0,'And so, the end draws near',14,0,100,0,0,10353,0,0,'Echo of Medivh - Medivh Loose King'), +(16816,15,0,'Nothing less than perfection will do.',14,0,100,0,0,10356,0,0,'Echo of Medivh - Checkmate 1'), +(16816,15,1,'And so it ends.',14,0,100,0,0,10355,0,0,'Echo of Medivh - Checkmate 2'), +(16816,16,0,'The halls of Karazhan shake, as the curse binding the doors of the Gamesman\'s Hall is lifted.',16,0,100,0,0,0,20430,0,'Echo of Medivh - Event Ended'); + +DELETE FROM `gossip_menu_option` WHERE `menuid` IN (8404,7413,8354,8345,8346,8347,8348,8349,8355,8362,8366,8367,8368); +UPDATE `creature_template` SET `npcflag`=0 WHERE `entry` IN (17469,17211,21748,21664,21750,21683,21747,21682,21726,21160,21752,21684); + +UPDATE `creature_template` SET `flags_extra`=130 WHERE `entry` IN (17208,17305,17317,17316); + +DELETE FROM `spell_script_names` WHERE `spell_id`=30019; +INSERT INTO `spell_script_names` VALUES +(30019,'spell_control_piece'); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index ac26e58a8..ec753508f 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -9183,32 +9183,47 @@ Pet* Player::CreatePet(uint32 creatureEntry, uint32 spellID /*= 0*/) return pet; } -void Player::StopCastingCharm() +void Player::StopCastingCharm(Aura* except /*= nullptr*/) { Unit* charm = GetCharm(); if (!charm) + { return; + } if (charm->GetTypeId() == TYPEID_UNIT) { if (charm->ToCreature()->HasUnitTypeMask(UNIT_MASK_PUPPET)) + { ((Puppet*)charm)->UnSummon(); + } else if (charm->IsVehicle()) + { ExitVehicle(); + } } + if (GetCharmGUID()) - charm->RemoveCharmAuras(); + { + charm->RemoveAurasByType(SPELL_AURA_MOD_CHARM, ObjectGuid::Empty, except); + charm->RemoveAurasByType(SPELL_AURA_MOD_POSSESS_PET, ObjectGuid::Empty, except); + charm->RemoveAurasByType(SPELL_AURA_MOD_POSSESS, ObjectGuid::Empty, except); + charm->RemoveAurasByType(SPELL_AURA_AOE_CHARM, ObjectGuid::Empty, except); + } if (GetCharmGUID()) { LOG_FATAL("entities.player", "Player {} ({} is not able to uncharm unit ({})", GetName(), GetGUID().ToString(), GetCharmGUID().ToString()); + if (charm->GetCharmerGUID()) { LOG_FATAL("entities.player", "Charmed unit has charmer {}", charm->GetCharmerGUID().ToString()); ABORT(); } else + { SetCharm(charm, false); + } } } @@ -13031,15 +13046,15 @@ bool ItemPosCount::isContainedIn(ItemPosCountVec const& vec) const return false; } -void Player::StopCastingBindSight() +void Player::StopCastingBindSight(Aura* except /*= nullptr*/) { if (WorldObject* target = GetViewpoint()) { if (target->isType(TYPEMASK_UNIT)) { - ((Unit*)target)->RemoveAurasByType(SPELL_AURA_BIND_SIGHT, GetGUID()); - ((Unit*)target)->RemoveAurasByType(SPELL_AURA_MOD_POSSESS, GetGUID()); - ((Unit*)target)->RemoveAurasByType(SPELL_AURA_MOD_POSSESS_PET, GetGUID()); + ((Unit*)target)->RemoveAurasByType(SPELL_AURA_BIND_SIGHT, GetGUID(), except); + ((Unit*)target)->RemoveAurasByType(SPELL_AURA_MOD_POSSESS, GetGUID(), except); + ((Unit*)target)->RemoveAurasByType(SPELL_AURA_MOD_POSSESS_PET, GetGUID(), except); } } } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 4b5ecd818..52dec4b03 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2298,8 +2298,8 @@ public: void SetSeer(WorldObject* target) { m_seer = target; } void SetViewpoint(WorldObject* target, bool apply); [[nodiscard]] WorldObject* GetViewpoint() const; - void StopCastingCharm(); - void StopCastingBindSight(); + void StopCastingCharm(Aura* except = nullptr); + void StopCastingBindSight(Aura* except = nullptr); [[nodiscard]] uint32 GetSaveTimer() const { return m_nextSave; } void SetSaveTimer(uint32 timer) { m_nextSave = timer; } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index f0905f83c..a98efc706 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -18575,15 +18575,15 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au // Charmer stop charming if (playerCharmer) { - playerCharmer->StopCastingCharm(); - playerCharmer->StopCastingBindSight(); + playerCharmer->StopCastingCharm(aurApp ? aurApp->GetBase() : nullptr); + playerCharmer->StopCastingBindSight(aurApp ? aurApp->GetBase() : nullptr); } // Charmed stop charming if (GetTypeId() == TYPEID_PLAYER) { - ToPlayer()->StopCastingCharm(); - ToPlayer()->StopCastingBindSight(); + ToPlayer()->StopCastingCharm(aurApp ? aurApp->GetBase() : nullptr); + ToPlayer()->StopCastingBindSight(aurApp ? aurApp->GetBase() : nullptr); } // StopCastingCharm may remove a possessed pet? @@ -18695,8 +18695,11 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(GameTime::GetGameTime().count())); // cast can't be helped } } - GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, GetFollowAngle()); - playerCharmer->CharmSpellInitialize(); + if (playerCharmer->m_seer != this) + { + GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, GetFollowAngle()); + playerCharmer->CharmSpellInitialize(); + } break; default: break; diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 536d18dce..6d3eac9ee 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -2461,6 +2461,8 @@ public: std::string GetDebugInfo() const override; + [[nodiscard]] uint32 GetOldFactionId() const { return _oldFactionId; } + protected: explicit Unit (bool isWorldObject); diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp index 61d1feaa1..9794ca8d9 100644 --- a/src/server/game/Handlers/NPCHandler.cpp +++ b/src/server/game/Handlers/NPCHandler.cpp @@ -289,10 +289,6 @@ void WorldSession::HandleGossipHelloOpcode(WorldPacket& recvData) if (unit->GetNpcFlags() == UNIT_NPC_FLAG_NONE) return; - // xinef: do not allow to open gossip when npc is in combat - if (unit->GetNpcFlags() == UNIT_NPC_FLAG_GOSSIP && unit->IsInCombat()) // should work on all flags? - return; - // set faction visible if needed if (FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->GetFaction())) _player->GetReputationMgr().SetVisible(factionTemplateEntry); diff --git a/src/server/game/Spells/SpellInfoCorrections.cpp b/src/server/game/Spells/SpellInfoCorrections.cpp index e0c4d4b59..be47d6793 100644 --- a/src/server/game/Spells/SpellInfoCorrections.cpp +++ b/src/server/game/Spells/SpellInfoCorrections.cpp @@ -4470,7 +4470,13 @@ void SpellMgr::LoadSpellInfoCorrections() { spellInfo->AttributesEx2 |= SPELL_ATTR2_IGNORE_LINE_OF_SIGHT; }); - + // Game In Session + ApplySpellFix({ 39331 }, [](SpellInfo* spellInfo) + { + spellInfo->Effects[EFFECT_0].Effect = SPELL_EFFECT_APPLY_AURA; + spellInfo->Attributes |= SPELL_ATTR0_NO_AURA_CANCEL; + spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CHANGE_MAP; + }); // Death Ray Warning Visual, Death Ray Damage Visual ApplySpellFix({ 63882, 63886 }, [](SpellInfo* spellInfo) { diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_chess_event.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_chess_event.cpp new file mode 100644 index 000000000..5f40a5155 --- /dev/null +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_chess_event.cpp @@ -0,0 +1,2092 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by the + * Free Software Foundation; either version 3 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 Affero 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 "karazhan.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "ScriptedEscortAI.h" +#include "ScriptedFollowerAI.h" +#include "ScriptedGossip.h" +#include "SpellInfo.h" +#include "SpellAuras.h" +#include "SpellScript.h" +#include "Unit.h" +#include "World.h" + +#include + +enum EchoOfMedivhGossipOptions +{ + MEDIVH_GOSSIP_START_PVE = 1, + MEDIVH_GOSSIP_RESTART, + MEDIVH_GOSSIP_START_PVP +}; + +enum KarazhanChessSpells +{ + SPELL_MOVE_1 = 37146, // 8y + SPELL_MOVE_2 = 37144, // 15y + SPELL_MOVE_3 = 37148, // 20y + SPELL_MOVE_4 = 37151, // 8y + SPELL_MOVE_5 = 37152, // 8y + SPELL_MOVE_6 = 37153, // 8y + + SPELL_MOVE_GENERIC = 30012, // Unlimited + + SPELL_CHANGE_FACING = 30284, + SPELL_MOVE_MARKER = 32261, + SPELL_MOVE_COOLDOWN = 30543, + SPELL_CONTROL_PIECE = 30019, + SPELL_RECENTLY_INGAME = 30529, + + SPELL_FURY_OF_MEDIVH_FIRE = 39345, + SPELL_MELEE_ATTACK_TIMER = 32226, + SPELL_MELEE_ATTACK_TIMER_TRIGGER = 32225, + SPELL_MELEE_DAMAGE = 32247 +}; + +enum KarazhanChessNPCs +{ + NPC_CHESS_MOVE_TRIGGER = 22519 +}; + +enum KarazhanChessTeam +{ + DEAD_ALLIANCE = 0, + DEAD_HORDE = 1, +}; + +enum KarazhanChessOrientationType : uint8 +{ + ORI_SE = 0, // Horde start + ORI_S = 1, + ORI_SW = 2, + ORI_W = 3, + ORI_NW = 4, // Alliance start + ORI_N = 5, + ORI_NE = 6, + ORI_E = 7, + + MAX_ORI +}; + +enum KarazhanChessPiecesSpells +{ + //ability 1 + SPELL_KING_H_1 = 37472, //Bloodlust + SPELL_KING_A_1 = 37471, //Heroism + SPELL_QUEEN_H_1 = 37463, //Fireball + SPELL_QUEEN_A_1 = 37462, //Elemental Blast + SPELL_BISHOP_H_1 = 37461, //Shadow Spear + SPELL_BISHOP_A_1 = 37459, //Holy Lance + SPELL_KNIGHT_H_1 = 37502, //Howl + SPELL_KNIGHT_A_1 = 37453, //Smash + SPELL_ROOK_H_1 = 37428, //Hellfire + SPELL_ROOK_A_1 = 37427, //Geyser + SPELL_PAWN_H_1 = 37416, //Weapon Deflection + SPELL_PAWN_A_1 = 37414, //Shield Block + + //ability 2 + SPELL_KING_H_2 = 37476, //Cleave + SPELL_KING_A_2 = 37474, //Sweep + SPELL_QUEEN_H_2 = 37469, //Poison Cloud + SPELL_QUEEN_A_2 = 37465, //Rain of Fire + SPELL_BISHOP_H_2 = 37456, //Shadow Mend + SPELL_BISHOP_A_2 = 37455, //Healing + SPELL_KNIGHT_H_2 = 37454, //Bite + SPELL_KNIGHT_A_2 = 37498, //Stomp + SPELL_ROOK_H_2 = 37434, //Fire Shield + SPELL_ROOK_A_2 = 37432, //Water Shield + SPELL_PAWN_H_2 = 37413, //Vicious Strike + SPELL_PAWN_A_2 = 37406 //Heroic Blow +}; + +enum ChessEventTalks +{ + TALK_EVENT_BEGIN = 0, + + TALK_MEDIHV_CHEAT = 1, + TALK_MEDIHV_CHEAT_EMOTE = 2, + + TALK_PLAYER_LOOSE_PAWN = 3, + TALK_PLAYER_LOOSE_ROOK = 4, + TALK_PLAYER_LOOSE_KNIGHT = 5, + TALK_PLAYER_LOOSE_BISHOP = 6, + TALK_PLAYER_LOOSE_QUEEN = 7, + TALK_PLAYER_LOOSE_KING = 8, + + TALK_MEDIVH_LOOSE_PAWN = 9, + TALK_MEDIVH_LOOSE_ROOK = 10, + TALK_MEDIVH_LOOSE_KNIGHT = 11, + TALK_MEDIVH_LOOSE_BISHOP = 12, + TALK_MEDIVH_LOOSE_QUEEN = 13, + TALK_MEDIVH_LOOSE_KING = 14, + + TALK_CHECKMATE = 15, + TALK_EVENT_ENDED = 16 +}; + +static constexpr uint8 MAX_ROW = 8; +static constexpr uint8 MAX_COL = 8; + +struct BoardCell +{ + BoardCell() : pieceEntry(0), row(0), col(0) { } + + ObjectGuid triggerGUID; + ObjectGuid pieceGUID; + uint32 pieceEntry; + uint8 row; + uint8 col; + + void SetData(ObjectGuid _triggerGUID, uint8 _row, uint8 _col) + { + triggerGUID = _triggerGUID; + row = _row; + col = _col; + } + + void Reset() + { + pieceGUID.Clear(); + pieceEntry = 0; + } + + void SetPiece(Creature* piece) + { + pieceGUID = piece->GetGUID(); + pieceEntry = piece->GetEntry(); + } +}; + +// ORI_SE ORI_S ORI_SW ORI_W ORI_NW ORI_N ORI_NE ORI_E +static std::array orientations = { 3.809080f, 3.022091f, 2.235102f, 1.448113f, 0.661124f, 6.1724616f, 5.385472f, 4.598483f }; + +static bool IsFriendly(Creature* piece, Creature* target) +{ + return piece->GetFaction() == target->GetFaction(); +} + +enum ChessPieceSearchType +{ + CHESS_PIECE_SEARCH_TYPE_CLOSEST = 1, + CHESS_PIECE_SEARCH_TYPE_RANDOM = 2 +}; + +struct npc_echo_of_medivh : public ScriptedAI +{ + npc_echo_of_medivh(Creature* creature) : ScriptedAI(creature), _summons(me) + { + _instance = creature->GetInstanceScript(); + } + + void Reset() override + { + for (uint8 row = 0; row < MAX_ROW; ++row) + { + for (uint8 col = 0; col < MAX_COL; ++col) + { + _boards[row][col].Reset(); + } + } + + _summons.DespawnAll(); + + _cheatTimer = urand(45 * IN_MILLISECONDS, 100 * IN_MILLISECONDS); + } + + void JustSummoned(Creature* summon) override + { + _summons.Summon(summon); + } + + void SummonedCreatureDespawn(Creature* summon) override + { + _summons.Despawn(summon); + } + + void RemoveCheats() + { + // Buffs + for (uint8 row = 0; row < MAX_ROW; ++row) + { + for (uint8 col = 0; col < MAX_COL; ++col) + { + if (ObjectGuid guid = _boards[row][col].pieceGUID) + { + if (Creature* piece = ObjectAccessor::GetCreature(*me, guid)) + { + piece->RemoveAurasDueToSpell(SPELL_HAND_OF_MEDIVH); + } + } + } + } + } + + void SetupBoard() + { + _instance->SetData(DATA_CHESS_REINIT_PIECES, 0); + + _summons.DespawnAll(); + + for (uint8 row = 0; row < MAX_ROW; ++row) + { + for (uint8 col = 0; col < MAX_COL; ++col) + { + BoardCell& cell = _boards[row][col]; + + if (Creature* trigger = me->SummonCreature(NPC_CHESS_MOVE_TRIGGER, (-11108.099609f + (3.49f * col) + (4.4f * row)), (-1872.910034f - (4.4f * col) + (3.45f * row)), 220.667f, 0, TEMPSUMMON_MANUAL_DESPAWN, 0)) + { + cell.SetData(trigger->GetGUID(), row, col); + HandleCellInitialData(row, col, trigger, cell); + } + } + } + + _deadCount.fill(0); + } + + void HandleCellInitialData(uint8 row, uint8 col, Creature* trigger, BoardCell& cell) + { + switch (row) + { + case 0: // Alliance first row + { + switch (col) + { + case 0: + case 7: // Rook + if (Creature* rook = trigger->FindNearestCreature(NPC_ROOK_A, 4.0f, true)) + { + cell.SetPiece(rook); + } + break; + case 1: + case 6: // Knight + if (Creature* knight = trigger->FindNearestCreature(NPC_KNIGHT_A, 4.0f, true)) + { + cell.SetPiece(knight); + } + break; + case 2: + case 5: // Bishop + if (Creature* bishop = trigger->FindNearestCreature(NPC_BISHOP_A, 4.0f, true)) + { + cell.SetPiece(bishop); + } + break; + case 3: // Queen + if (Creature* queen = trigger->FindNearestCreature(NPC_QUEEN_A, 4.0f, true)) + { + cell.SetPiece(queen); + } + break; + case 4: // King + if (Creature* king = trigger->FindNearestCreature(NPC_KING_A, 4.0f, true)) + { + cell.SetPiece(king); + } + break; + } + break; + } + case 1: // Alliance second row + // All pawns + if (Creature* pawn = trigger->FindNearestCreature(NPC_PAWN_A, 4.0f, true)) + { + cell.SetPiece(pawn); + } + break; + case 6: // Horde second row + // All pawns + if (Creature* pawn = trigger->FindNearestCreature(NPC_PAWN_H, 4.0f, true)) + { + cell.SetPiece(pawn); + } + break; + case 7: // Horde first row + { + switch (col) + { + case 0: + case 7: // Rook + if (Creature* rook = trigger->FindNearestCreature(NPC_ROOK_H, 4.0f, true)) + { + cell.SetPiece(rook); + } + break; + case 1: + case 6: // Knight + if (Creature* knight = trigger->FindNearestCreature(NPC_KNIGHT_H, 4.0f, true)) + { + cell.SetPiece(knight); + } + break; + case 2: + case 5: // Bishop + if (Creature* bishop = trigger->FindNearestCreature(NPC_BISHOP_H, 4.0f, true)) + { + cell.SetPiece(bishop); + } + break; + case 3: // Queen + if (Creature* queen = trigger->FindNearestCreature(NPC_QUEEN_H, 4.0f, true)) + { + cell.SetPiece(queen); + } + break; + case 4: // King + if (Creature* king = trigger->FindNearestCreature(NPC_KING_H, 4.0f, true)) + { + cell.SetPiece(king); + } + break; + default: + break; + } + break; + } + default: + cell.Reset(); + break; + } + } + + bool IsMedivhPiece(uint32 entry) const + { + switch (entry) + { + case NPC_PAWN_H: + case NPC_KNIGHT_H: + case NPC_QUEEN_H: + case NPC_BISHOP_H: + case NPC_ROOK_H: + case NPC_KING_H: + return _instance->GetData(CHESS_EVENT_TEAM) == TEAM_ALLIANCE; + case NPC_PAWN_A: + case NPC_KNIGHT_A: + case NPC_QUEEN_A: + case NPC_BISHOP_A: + case NPC_ROOK_A: + case NPC_KING_A: + return _instance->GetData(CHESS_EVENT_TEAM) == TEAM_HORDE; + } + + return false; + } + + Creature* GetHostileTargetForChangeFacing(Creature* piece, KarazhanChessOrientationType orientation) + { + for (uint8 row = 0; row < MAX_ROW; ++row) + { + for (uint8 col = 0; col < MAX_COL; ++col) + { + BoardCell const& cell = _boards[row][col]; + if (cell.pieceGUID == piece->GetGUID()) + { + std::vector orientations; + switch (orientation) + { + case ORI_SE: + orientations = { ORI_NE, ORI_E, ORI_S, ORI_SW }; + break; + case ORI_S: + orientations = { ORI_E, ORI_SE, ORI_SW, ORI_W }; + break; + case ORI_SW: + orientations = { ORI_SE, ORI_S, ORI_W, ORI_NW }; + break; + case ORI_W: + orientations = { ORI_NE, ORI_SW, ORI_NW, ORI_N }; + break; + case ORI_NW: + orientations = { ORI_SW, ORI_W, ORI_N, ORI_NE }; + break; + case ORI_N: + orientations = { ORI_W, ORI_NW, ORI_NE, ORI_E }; + break; + case ORI_NE: + orientations = { ORI_NW, ORI_N, ORI_E, ORI_SE }; + break; + case ORI_E: + orientations = { ORI_N, ORI_NE, ORI_SE, ORI_S }; + break; + default: + break; + } + + for (KarazhanChessOrientationType orient : orientations) + { + uint8 newRow = row; + uint8 newCol = col; + switch (orient) + { + case ORI_SE: + newRow -= 1; + break; + case ORI_S: + newRow -= 1; + newCol -= 1; + break; + case ORI_SW: + newCol -= 1; + break; + case ORI_W: + newRow += 1; + newCol -= 1; + break; + case ORI_NW: + newRow += 1; + break; + case ORI_N: + newRow += 1; + newCol += 1; + break; + case ORI_NE: + newCol += 1; + break; + case ORI_E: + newRow -= 1; + newCol += 1; + break; + default: + break; + } + + if (Creature* targetPiece = ObjectAccessor::GetCreature(*me, _boards[newRow][newCol].pieceGUID)) + { + if (!IsFriendly(piece, targetPiece)) + { + return targetPiece; + } + } + } + + return nullptr; + } + } + } + + return nullptr; + } + + void HandlePieceJustDied(Creature* piece) + { + switch (piece->GetFaction()) + { + case CHESS_FACTION_ALLIANCE: + { + float baseX = -11078.116211f; + float baseY = -1908.443115f; + float deltaX = 2.148438f; + float deltaY = 1.723755f; + float extraX = 2.416992f; + float extraY = -2.889649f; + float offset = 1.3f * (_deadCount[DEAD_ALLIANCE] % MAX_ROW); + float finalX = baseX + offset * deltaX + (_deadCount[DEAD_ALLIANCE] >= MAX_ROW ? 1 : 0) * extraX; + float finalY = baseY + offset * deltaY + (_deadCount[DEAD_ALLIANCE] >= MAX_ROW ? 1 : 0) * extraY; + piece->NearTeleportTo(finalX, finalY, 221.0f, orientations[ORI_SW]); + ++_deadCount[DEAD_ALLIANCE]; + + piece->CombatStop(); + piece->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + piece->setDeathState(JUST_RESPAWNED); + piece->SetHealth(piece->GetMaxHealth()); + break; + } + case CHESS_FACTION_HORDE: + { + float baseX = -11081.393555f; + float baseY = -1844.194092f; + float deltaX = -2.148438f; + float deltaY = -1.723755f; + float extraX = -2.416992f; + float extraY = 2.889649f; + + float offset = 1.3f * (_deadCount[DEAD_HORDE] % MAX_ROW); + + float finalX = baseX + offset * deltaX + (_deadCount[DEAD_HORDE] >= MAX_ROW ? 1 : 0) * extraX; + float finalY = baseY + offset * deltaY + (_deadCount[DEAD_HORDE] >= MAX_ROW ? 1 : 0) * extraY; + piece->NearTeleportTo(finalX, finalY, 221.0f, orientations[ORI_NE]); + ++_deadCount[DEAD_HORDE]; + + piece->CombatStop(); + piece->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + piece->setDeathState(JUST_RESPAWNED); + piece->SetHealth(piece->GetMaxHealth()); + break; + } + } + + for (uint8 row = 0; row < MAX_ROW; ++row) + { + for (uint8 col = 0; col < MAX_COL; ++col) + { + if (_boards[row][col].pieceGUID == piece->GetGUID()) + { + _boards[row][col].Reset(); + } + } + } + + if (_instance->GetData(CHESS_EVENT_TEAM) == TEAM_HORDE) + { + bool ended = false; + switch (piece->GetEntry()) + { + case NPC_KING_H: + _instance->SetData(DATA_CHESS_EVENT, NOT_STARTED); + _instance->SetData(DATA_CHESS_REINIT_PIECES, 0); + _instance->SetData(DATA_CHESS_GAME_PHASE, CHESS_PHASE_NOT_STARTED); + break; + case NPC_KING_A: + if (_instance->GetData(DATA_CHESS_EVENT) == IN_PROGRESS) + { + _instance->SetData(DATA_CHESS_EVENT, DONE); + _instance->SetData(DATA_CHESS_GAME_PHASE, CHESS_PHASE_PVE_FINISHED); + _instance->SetData(DATA_CHESS_REINIT_PIECES, 0); + _instance->DoRespawnGameObject(_instance->GetGuidData(DATA_DUST_COVERED_CHEST), DAY); + Talk(TALK_EVENT_ENDED); + ended = true; + _instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_GAME_IN_SESSION); + } + else if (_instance->GetData(DATA_CHESS_EVENT) == SPECIAL) + { + _instance->SetData(DATA_CHESS_EVENT, DONE); + _instance->SetData(DATA_CHESS_REINIT_PIECES, 0); + _instance->SetData(DATA_CHESS_GAME_PHASE, CHESS_PHASE_PVE_FINISHED); + ended = true; + _instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_GAME_IN_SESSION); + } + break; + default: + break; + } + + if (!ended) + { + uint8 talkIndex = TALK_PLAYER_LOOSE_PAWN; + if (piece->GetFaction() == CHESS_FACTION_ALLIANCE) + { + talkIndex = TALK_MEDIVH_LOOSE_PAWN; + } + + switch (piece->GetEntry()) + { + case NPC_ROOK_A: + case NPC_ROOK_H: + talkIndex += 1; + break; + case NPC_KNIGHT_A: + case NPC_KNIGHT_H: + talkIndex += 2; + break; + case NPC_BISHOP_A: + case NPC_BISHOP_H: + talkIndex += 3; + break; + case NPC_QUEEN_A: + case NPC_QUEEN_H: + talkIndex += 4; + break; + case NPC_KING_H: + case NPC_KING_A: + talkIndex += 5; + break; + } + + Talk(talkIndex); + } + } + else if (_instance->GetData(CHESS_EVENT_TEAM) == TEAM_ALLIANCE) + { + bool ended = false; + switch (piece->GetEntry()) + { + case NPC_KING_A: + _instance->SetData(DATA_CHESS_EVENT, NOT_STARTED); + _instance->SetData(DATA_CHESS_REINIT_PIECES, 0); + _instance->SetData(DATA_CHESS_GAME_PHASE, CHESS_PHASE_NOT_STARTED); + break; + case NPC_KING_H: + if (_instance->GetData(DATA_CHESS_EVENT) == IN_PROGRESS) + { + _instance->SetData(DATA_CHESS_EVENT, DONE); + _instance->SetData(DATA_CHESS_GAME_PHASE, CHESS_PHASE_PVE_FINISHED); + _instance->SetData(DATA_CHESS_REINIT_PIECES, 0); + Talk(TALK_EVENT_ENDED); + _instance->DoRespawnGameObject(_instance->GetGuidData(DATA_DUST_COVERED_CHEST), DAY); + ended = true; + _instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_GAME_IN_SESSION); + } + else if (_instance->GetData(DATA_CHESS_EVENT) == SPECIAL) + { + _instance->SetData(DATA_CHESS_EVENT, DONE); + _instance->SetData(DATA_CHESS_REINIT_PIECES, 0); + _instance->SetData(DATA_CHESS_GAME_PHASE, CHESS_PHASE_PVE_FINISHED); + _instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_GAME_IN_SESSION); + ended = true; + } + break; + default: + break; + } + + if (!ended) + { + uint8 talkIndex = TALK_PLAYER_LOOSE_PAWN; + if (piece->GetFaction() == CHESS_FACTION_HORDE) + { + talkIndex = TALK_MEDIVH_LOOSE_PAWN; + } + + switch (piece->GetEntry()) + { + case NPC_ROOK_A: + case NPC_ROOK_H: + talkIndex += 1; + break; + case NPC_KNIGHT_A: + case NPC_KNIGHT_H: + talkIndex += 2; + break; + case NPC_BISHOP_A: + case NPC_BISHOP_H: + talkIndex += 3; + break; + case NPC_QUEEN_A: + case NPC_QUEEN_H: + talkIndex += 4; + break; + case NPC_KING_H: + case NPC_KING_A: + talkIndex += 5; + break; + } + + Talk(talkIndex); + } + } + else + { + switch (piece->GetEntry()) + { + case NPC_KING_H: + case NPC_KING_A: + _instance->SetData(DATA_CHESS_EVENT, DONE); + _instance->SetData(DATA_CHESS_REINIT_PIECES, 0); + _instance->SetData(DATA_CHESS_GAME_PHASE, CHESS_PHASE_PVE_FINISHED); + _instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_GAME_IN_SESSION); + break; + } + + uint8 talkIndex = TALK_PLAYER_LOOSE_PAWN; + if (piece->GetFaction() == CHESS_FACTION_HORDE) + { + talkIndex = TALK_MEDIVH_LOOSE_PAWN; + } + + switch (piece->GetEntry()) + { + case NPC_ROOK_A: + case NPC_ROOK_H: + talkIndex += 1; + break; + case NPC_KNIGHT_A: + case NPC_KNIGHT_H: + talkIndex += 2; + break; + case NPC_BISHOP_A: + case NPC_BISHOP_H: + talkIndex += 3; + break; + case NPC_QUEEN_A: + case NPC_QUEEN_H: + talkIndex += 4; + break; + case NPC_KING_H: + case NPC_KING_A: + talkIndex += 5; + break; + } + + Talk(talkIndex); + } + } + + int8 HandlePieceRotate(Creature* piece, ObjectGuid const& triggerGUID) + { + bool foundOld = false; + bool foundNew = false; + int8 pieceRow = MAX_ROW; + int8 pieceCol = MAX_COL; + int8 targetRow = -1; + int8 targetCol = -1; + + for (uint8 row = 0; row < MAX_ROW; ++row) + { + for (uint8 col = 0; col < MAX_COL; ++col) + { + BoardCell const& cell = _boards[row][col]; + if (!foundNew && cell.triggerGUID == triggerGUID) + { + targetRow = row; + targetCol = col; + foundNew = true; + } + + if (!foundOld && cell.pieceGUID == piece->GetGUID()) + { + pieceRow = row; + pieceCol = col; + foundOld = true; + } + + if (foundNew && foundOld) + { + break; + } + } + + if (foundNew && foundOld) + { + break; + } + } + + if (targetRow == -1 || targetCol == -1) + { + return -1; + } + + int8 deltaRow = targetRow - pieceRow; + int8 deltaCol = targetCol - pieceCol; + + if (!deltaRow && !deltaCol) + { + return -1; + } + + switch (deltaRow) + { + case -3: + case -2: + case -1: + { + switch (deltaCol) + { + case -3: + case -2: + case -1: + return ORI_S; + case 0: + return ORI_SE; + case 1: + case 2: + case 3: + return ORI_E; + default: + break; + } + break; + } + case 0: + { + switch (deltaCol) + { + case -3: + case -2: + case -1: + return ORI_SW; + case 1: + case 2: + case 3: + return ORI_NE; + default: + break; + } + break; + } + case 1: + case 2: + case 3: + { + switch (deltaCol) + { + case -3: + case -2: + case -1: + return ORI_W; + case 0: + return ORI_NW; + case 1: + case 2: + case 3: + return ORI_N; + default: + break; + } + break; + } + default: + break; + } + + return -1; + } + + int8 HandlePieceMove(Creature* piece, ObjectGuid const& triggerGUID, bool moveByAI) + { + bool foundProperCell = false; + bool foundOld = false; + bool foundNew = false; + int8 oldRow = MAX_ROW; + int8 oldCol = MAX_COL; + int8 newRow = -1; + int8 newCol = -1; + + for (uint8 row = 0; row < MAX_ROW; ++row) + { + for (uint8 col = 0; col < MAX_COL; ++col) + { + BoardCell const& cell = _boards[row][col]; + if (!foundNew) + { + if (cell.triggerGUID == triggerGUID) + { + //is there already a piece on this cell ? + if (cell.pieceGUID) + { + return -1; + } + + newCol = col; + newRow = row; + foundProperCell = true; + foundNew = true; + } + } + + if (!foundOld) + { + if (cell.pieceGUID == piece->GetGUID()) + { + oldCol = col; + oldRow = row; + foundOld = true; + } + } + + if (foundNew && foundOld) + { + break; + } + } + + if (foundNew && foundOld) + { + break; + } + } + + if (newCol == -1 || newRow == -1) + { + return -1; + } + + if (!moveByAI && foundProperCell) + { + uint8 deltaRow = abs(oldRow - newRow); + uint8 deltaCol = abs(oldCol - newCol); + + switch (piece->GetEntry()) + { + case NPC_PAWN_H: + case NPC_PAWN_A: + case NPC_BISHOP_H: + case NPC_BISHOP_A: + case NPC_ROOK_H: + case NPC_ROOK_A: + case NPC_KING_H: + case NPC_KING_A: + if (deltaRow > 1 || deltaCol > 1) + { + foundProperCell = false; + } + break; + case NPC_QUEEN_H: + case NPC_QUEEN_A: + if (deltaRow > 3 || deltaCol > 3) + { + foundProperCell = false; + } + break; + case NPC_KNIGHT_H: + case NPC_KNIGHT_A: + if (deltaRow > 2 || deltaCol > 2) + { + foundProperCell = false; + } + break; + default: + break; + } + } + + if (foundProperCell || moveByAI) + { + int8 orientation = HandlePieceRotate(piece, triggerGUID); + if (orientation != -1) + { + _boards[newRow][newCol].triggerGUID = triggerGUID; + _boards[newRow][newCol].SetPiece(piece); + + if (oldRow != MAX_ROW && oldCol != MAX_COL) + { + _boards[oldRow][oldCol].Reset(); + } + } + + return orientation; + } + + return -1; + } + + void CastChangeFacing(Creature* piece, Creature* trigger) + { + piece->CastSpell(trigger, SPELL_CHANGE_FACING, true); + } + + bool HandlePieceMoveByAI(Creature* piece, KarazhanChessOrientationType orientation) + { + uint8 pieceRow = 0; + uint8 pieceCol = 0; + bool found = false; + + for (uint8 row = 0; row < MAX_ROW; ++row) + { + for (uint8 col = 0; col < MAX_COL; ++col) + { + if (_boards[row][col].pieceGUID == piece->GetGUID()) + { + pieceRow = row; + pieceCol = col; + found = true; + break; + } + } + + if (found) + { + break; + } + } + + //! Change orientation at edges + if (orientation == ORI_SE && pieceRow == 0) + { + if (Creature* trigger = ObjectAccessor::GetCreature(*me, _boards[pieceRow + 1][pieceCol].triggerGUID)) + { + CastChangeFacing(piece, trigger); + } + + return true; + } + else if (orientation == ORI_NW && pieceRow == 7) + { + if (Creature* trigger = ObjectAccessor::GetCreature(*me, _boards[pieceRow - 1][pieceCol].triggerGUID)) + { + CastChangeFacing(piece, trigger); + } + + return true; + } + else if (orientation == ORI_SW && pieceCol == 0) + { + if (Creature* trigger = ObjectAccessor::GetCreature(*me, _boards[pieceRow][pieceCol + 1].triggerGUID)) + { + CastChangeFacing(piece, trigger); + } + + return true; + } + else if (orientation == ORI_NE && pieceCol == 7) + { + if (Creature* trigger = ObjectAccessor::GetCreature(*me, _boards[pieceRow][pieceCol - 1].triggerGUID)) + { + CastChangeFacing(piece, trigger); + } + + return true; + } + else if (urand(0, 1)) // 50% chance to check for nearby enemies + { + if (Creature* target = GetHostileTargetForChangeFacing(piece, orientation)) + { + CastChangeFacing(me, target); + return true; + } + } + + switch (orientation) + { + case ORI_W: + case ORI_N: + orientation = ORI_NW; + break; + case ORI_S: + case ORI_E: + orientation = ORI_SE; + break; + default: + break; + } + + switch (orientation) //! Here we shouldn't be facing the edges of the board, check in the 4 first if statements + { + case ORI_SE: + case ORI_NW: + { + int32 randomRow = (orientation == ORI_SE) ? pieceRow - 1 : pieceRow + 1; + int32 randomCol = pieceCol; + switch (urand(0, 2)) + { + case 0: + if ((me->GetEntry() == NPC_QUEEN_A || me->GetEntry() == NPC_QUEEN_H)) + { + randomCol -= irand(1, 2); + } + else + { + randomCol -= 1; + } + break; + case 1: + if ((me->GetEntry() == NPC_QUEEN_A || me->GetEntry() == NPC_QUEEN_H)) + { + randomCol += irand(1, 2); + } + else + { + randomCol += 1; + } + break; + case 2: + if ((me->GetEntry() == NPC_QUEEN_A || me->GetEntry() == NPC_QUEEN_H)) + { + randomRow += (orientation == ORI_SE) ? irand(-2, 0) : irand(0, 2); + } + else if ((me->GetEntry() == NPC_KNIGHT_A || me->GetEntry() == NPC_KNIGHT_H) && urand(0, 1)) + { + randomRow += (orientation == ORI_SE) ? -1 : 1; + } + break; + } + + randomRow = RoundToInterval(randomRow, 0, 7); + randomCol = RoundToInterval(randomCol, 0, 7); + + BoardCell const& cell = _boards[randomRow][randomCol]; + if (Creature* trigger = ObjectAccessor::GetCreature(*me, cell.triggerGUID)) + { + if (!cell.pieceGUID) + { + piece->CastSpell(trigger, SPELL_MOVE_GENERIC, false); + return true; + } + } + break; + } + case ORI_SW: + case ORI_NE: + { + int32 randomRow = pieceRow; + int32 randomCol = orientation == ORI_SW ? pieceCol - 1 : pieceCol + 1; + switch (urand(0, 2)) + { + case 0: + if ((me->GetEntry() == NPC_QUEEN_A || me->GetEntry() == NPC_QUEEN_H)) + { + randomRow -= irand(1, 2); + } + else + { + randomRow -= 1; + } + break; + case 1: + if ((me->GetEntry() == NPC_QUEEN_A || me->GetEntry() == NPC_QUEEN_H)) + { + randomRow += irand(1, 2); + } + else + { + randomRow += 1; + } + break; + case 2: + if ((me->GetEntry() == NPC_QUEEN_A || me->GetEntry() == NPC_QUEEN_H)) + { + randomCol += (orientation == ORI_SW) ? irand(-2, 0) : irand(0, 2); + } + else if ((me->GetEntry() == NPC_KNIGHT_A || me->GetEntry() == NPC_KNIGHT_H) && urand(0, 1)) + { + randomCol += (orientation == ORI_SW) ? -1 : 1; + } + break; + } + + randomRow = RoundToInterval(randomRow, 0, 7); + randomCol = RoundToInterval(randomCol, 0, 7); + + BoardCell const& cell = _boards[randomRow][randomCol]; + if (Creature* trigger = ObjectAccessor::GetCreature(*me, cell.triggerGUID)) + { + if (!cell.pieceGUID) + { + piece->CastSpell(trigger, SPELL_MOVE_GENERIC, false); + return true; + } + } + break; + } + default: + break; + } + + return false; + } + + void HandleCheat() + { + Talk(TALK_MEDIHV_CHEAT); + + switch (urand(0, 2)) + { + case 0: // Heal king + { + if (_instance->GetData(CHESS_EVENT_TEAM) == TEAM_ALLIANCE) + { + if (Creature* king = me->FindNearestCreature(NPC_KING_H, 80.0f, true)) + { + king->SetHealth(king->GetMaxHealth()); + } + } + else if (_instance->GetData(CHESS_EVENT_TEAM) == TEAM_HORDE) + { + if (Creature* king = me->FindNearestCreature(NPC_KING_A, 80.0f, true)) + { + king->SetHealth(king->GetMaxHealth()); + } + } + + break; + } + case 1: // Fire + { + std::list targetList; + for (uint8 row = 0; row < MAX_ROW; ++row) + { + for (uint8 col = 0; col < MAX_COL; ++col) + { + BoardCell const& cell = _boards[row][col]; + if (!cell.pieceGUID || IsMedivhPiece(cell.pieceEntry)) + { + continue; + } + + if (Creature* trigger = ObjectAccessor::GetCreature(*me, cell.triggerGUID)) + { + targetList.push_back(trigger); + } + } + } + + if (targetList.size() > 3) + { + Acore::Containers::RandomResize(targetList, 3); + } + + for (Creature* target : targetList) + { + DoCast(target, SPELL_FURY_OF_MEDIVH_FIRE, true); + } + + break; + } + case 2: // Buff + { + std::list targetList; + for (uint8 row = 0; row < MAX_ROW; ++row) + { + for (uint8 col = 0; col < MAX_COL; ++col) + { + BoardCell const& cell = _boards[row][col]; + if (!cell.pieceGUID || !IsMedivhPiece(cell.pieceEntry)) + { + continue; + } + + if (Creature* piece = ObjectAccessor::GetCreature(*me, cell.pieceGUID)) + { + targetList.push_back(piece); + } + } + } + + uint8 resizeMax = urand(1, 4); + if (targetList.size() > resizeMax) + { + Acore::Containers::RandomResize(targetList, resizeMax); + } + + for (Creature* target : targetList) + { + DoCast(target, SPELL_HAND_OF_MEDIVH, true); + } + + break; + } + } + + Talk(TALK_MEDIHV_CHEAT_EMOTE); + } + + Creature* GetPiece(Creature* sourcePiece, uint8 searchType, float distance, bool hostile, uint32 minHPDiff, bool checkFront) + { + if (!sourcePiece) + { + return nullptr; + } + + Creature* target = nullptr; + std::vector targets; + + for (uint8 row = 0; row < MAX_ROW; ++row) + { + for (uint8 col = 0; col < MAX_COL; ++col) + { + if (Creature* piece = ObjectAccessor::GetCreature(*me, _boards[row][col].pieceGUID)) + { + if (IsFriendly(piece, sourcePiece) == hostile) + { + continue; + } + + if (checkFront && !sourcePiece->HasInArc(float(M_PI) / 3.0f, piece)) + { + continue; + } + + if (minHPDiff) + { + if (piece->GetMaxHealth() - piece->GetHealth() <= minHPDiff) + { + continue; + } + + minHPDiff = piece->GetMaxHealth() - piece->GetHealth(); + } + + float dist = sourcePiece->GetExactDist2d(piece); + if (dist < distance) + { + if (searchType == CHESS_PIECE_SEARCH_TYPE_CLOSEST) + { + distance = dist; + target = piece; + } + else + { + targets.push_back(piece); + } + } + } + } + } + + if (!targets.empty()) + { + target = Acore::Containers::SelectRandomContainerElement(targets); + } + + return target; + } + + void UpdateAI(uint32 diff) override + { + uint32 chessPhase = _instance->GetData(DATA_CHESS_GAME_PHASE); + if (chessPhase != CHESS_PHASE_INPROGRESS_PVE && chessPhase != CHESS_PHASE_INPROGRESS_PVP) + return; + + if (chessPhase == CHESS_PHASE_INPROGRESS_PVE) + { + if (_cheatTimer <= diff) + { + HandleCheat(); + _cheatTimer = urand(45000, 100000); + } + else + { + _cheatTimer -= diff; + } + } + } + + void sGossipHello(Player* player) override + { + uint32 chessPhase = _instance->GetData(DATA_CHESS_GAME_PHASE); + switch (chessPhase) + { + case CHESS_PHASE_NOT_STARTED: + AddGossipItemFor(player, GOSSIP_ICON_CHAT, "We want to play a game against you!", GOSSIP_SENDER_MAIN, MEDIVH_GOSSIP_START_PVE); + break; + case CHESS_PHASE_INPROGRESS_PVE: + case CHESS_PHASE_INPROGRESS_PVP: + AddGossipItemFor(player, GOSSIP_ICON_CHAT, "Restart", GOSSIP_SENDER_MAIN, MEDIVH_GOSSIP_RESTART); // We want to player another game against you + break; + case CHESS_PHASE_PVE_FINISHED: + AddGossipItemFor(player, GOSSIP_ICON_CHAT, "PvP", GOSSIP_SENDER_MAIN, MEDIVH_GOSSIP_START_PVP); // We'd like to fight each other + break; + } + + SendGossipMenuFor(player, player->GetGossipTextId(me), me->GetGUID()); + } + + void sGossipSelect(Player* player, uint32 /*sender*/, uint32 gossipListId) override + { + uint32 chessPhase = _instance->GetData(DATA_CHESS_GAME_PHASE); + _instance->SetData(CHESS_EVENT_TEAM, chessPhase < CHESS_PHASE_PVE_FINISHED ? player->GetTeamId() : TEAM_NEUTRAL); + + CloseGossipMenuFor(player); + + uint32 const action = player->PlayerTalkClass->GetGossipOptionAction(gossipListId); + switch (action) + { + case MEDIVH_GOSSIP_START_PVE: + _instance->SetData(DATA_CHESS_GAME_PHASE, CHESS_PHASE_PVE_WARMUP); + SetupBoard(); + _instance->SetData(DATA_CHESS_EVENT, IN_PROGRESS); + Talk(TALK_EVENT_BEGIN); + break; + case MEDIVH_GOSSIP_RESTART: + _instance->SetData(DATA_CHESS_GAME_PHASE, CHESS_PHASE_FAILED); + _instance->SetData(DATA_CHESS_REINIT_PIECES, 0); + _deadCount.fill(0); + if (_instance->GetData(DATA_CHESS_EVENT) == IN_PROGRESS) + { + _instance->SetData(DATA_CHESS_EVENT, NOT_STARTED); + _instance->SetData(DATA_CHESS_GAME_PHASE, CHESS_PHASE_NOT_STARTED); + } + else if (_instance->GetData(DATA_CHESS_EVENT) == SPECIAL) + { + _instance->SetData(DATA_CHESS_EVENT, DONE); + _instance->SetData(DATA_CHESS_GAME_PHASE, CHESS_PHASE_PVE_FINISHED); + } + _instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_GAME_IN_SESSION); + break; + case MEDIVH_GOSSIP_START_PVP: + _instance->SetData(DATA_CHESS_GAME_PHASE, CHESS_PHASE_PVP_WARMUP); + SetupBoard(); + _instance->SetData(DATA_CHESS_EVENT, SPECIAL); + Talk(TALK_EVENT_BEGIN); + break; + default: + break; + } + } + +private: + InstanceScript* _instance; + SummonList _summons; + std::array, MAX_ROW> _boards; + std::array _deadCount; + uint32 _cheatTimer; +}; + +struct npc_chesspiece : public ScriptedAI +{ + npc_chesspiece(Creature* creature) : ScriptedAI(creature) + { + _instance = creature->GetInstanceScript(); + + _currentOrientation = GetDefaultOrientationForTeam(); + + _nextMoveTimer = urand(8 * IN_MILLISECONDS, 20 * IN_MILLISECONDS); + + InitializeCombatSpellsByEntry(); + + switch (_instance->GetData(CHESS_EVENT_TEAM)) + { + case TEAM_ALLIANCE: + _teamControlledByRaid = me->GetFaction() == CHESS_FACTION_ALLIANCE; + break; + case TEAM_HORDE: + _teamControlledByRaid = me->GetFaction() == CHESS_FACTION_HORDE; + break; + case TEAM_NEUTRAL: + _teamControlledByRaid = true; + break; + } + } + + void Reset() override + { + me->ApplySpellImmune(0, IMMUNITY_ID, SPELL_GAME_IN_SESSION, true); + + me->SetSheath(SHEATH_STATE_MELEE); + me->SetReactState(REACT_PASSIVE); + me->SetWalk(true); + + DoCastSelf(SPELL_MELEE_ATTACK_TIMER, true); + + for (uint8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i) + { + me->SetResistance(SpellSchools(i), 0); + } + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + } + + void MovementInform(uint32 movementType, uint32 /*pointId*/) override + { + if (movementType != POINT_MOTION_TYPE) + { + return; + } + + if (!me->IsCharmed()) + { + me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); + + if (!_nextMoveTimer) + { + _nextMoveTimer = urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS); + } + + if (Creature* medivh = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_ECHO_OF_MEDIVH))) + { + if (Creature* target = CAST_AI(npc_echo_of_medivh, medivh->AI())->GetHostileTargetForChangeFacing(me, _currentOrientation)) + { + CastChangeFacing(me, target); + } + } + } + } + + void AttackStart(Unit* /*victim*/) override + { + } + + KarazhanChessOrientationType GetDefaultOrientationForTeam() + { + switch (me->GetFaction()) + { + case CHESS_FACTION_ALLIANCE: + return ORI_NW; + case CHESS_FACTION_HORDE: + return ORI_SE; + } + + return ORI_SE; + } + + void CastChangeFacing(Creature* piece, Creature* trigger) + { + piece->CastSpell(trigger, SPELL_CHANGE_FACING, true); + } + + void OnCharmed(bool apply) override + { + Unit* charmer = me->GetCharmer(); + if (apply) + { + ASSERT(charmer); + _charmerGUID = charmer->GetGUID(); + me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); + me->SetWalk(true); + charmer->RemoveAurasDueToSpell(SPELL_GAME_IN_SESSION); + + // Build new action bar + if (Player* playerCharmer = charmer->ToPlayer()) + { + WorldPacket data(SMSG_PET_SPELLS, 1 + 8 + 2 + 4 + 1 + 1 + 2 + MAX_SPELL_CONTROL_BAR * 4 + 1 + 1); + data << me->GetGUID(); + data << uint16(0); + data << uint32(0); + data << uint8(me->GetReactState()); + data << uint8(0); + data << uint16(0); + + for (uint32 i = 0; i < MAX_CREATURE_SPELLS; ++i) + { + uint32 spellId = me->m_spells[i]; + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + if (!spellInfo) + { + data << uint16(0) << uint8(0) << uint8(i + 8); + continue; + } + + data << uint32(MAKE_UNIT_ACTION_BUTTON(spellId, ACT_ENABLED)); + } + + for (uint32 i = MAX_CREATURE_SPELLS; i < MAX_SPELL_CONTROL_BAR; ++i) + data << uint32(0); + + data << uint8(0); + data << uint8(0); + + playerCharmer->SendDirectMessage(&data); + } + } + else + { + me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); + + if (Unit* charmer = ObjectAccessor::GetUnit(*me, _charmerGUID)) + { + charmer->RemoveAurasDueToSpell(SPELL_CONTROL_PIECE); + charmer->CastSpell(charmer, SPELL_GAME_IN_SESSION, true); + charmer->CastSpell(charmer, SPELL_RECENTLY_INGAME, true); + charmer->NearTeleportTo(-11106.92f, -1843.32f, 229.626f, 4.2331f); + } + + _charmerGUID.Clear(); + } + + if (apply) + { + if (_instance->GetData(CHESS_EVENT_TEAM) == TEAM_ALLIANCE) + { + me->SetFaction(CHESS_FACTION_ALLIANCE); + } + else if (_instance->GetData(CHESS_EVENT_TEAM) == TEAM_HORDE) + { + me->SetFaction(CHESS_FACTION_HORDE); + } + else if (uint32 oldFaction = me->GetOldFactionId()) + { + me->SetFaction(oldFaction); + } + else if (FactionTemplateEntry const* factionTemplateEntry = me->GetFactionTemplateEntry()) + { + me->SetFaction(factionTemplateEntry->faction); + } + else + { + me->SetFaction(CHESS_FACTION_BOTH); + } + } + else + { + switch (me->GetEntry()) + { + case NPC_PAWN_A: + case NPC_KING_A: + case NPC_KNIGHT_A: + case NPC_QUEEN_A: + case NPC_BISHOP_A: + case NPC_ROOK_A: + me->SetFaction(CHESS_FACTION_ALLIANCE); + break; + case NPC_KING_H: + case NPC_ROOK_H: + case NPC_BISHOP_H: + case NPC_QUEEN_H: + case NPC_KNIGHT_H: + case NPC_PAWN_H: + me->SetFaction(CHESS_FACTION_HORDE); + break; + default: + break; + } + } + } + + void DoAction(int32 param) override + { + switch (param) + { + case ACTION_CHESS_PIECE_RESET_ORIENTATION: + _currentOrientation = GetDefaultOrientationForTeam(); + _nextMoveTimer = urand(8 * IN_MILLISECONDS, 20 * IN_MILLISECONDS); + break; + default: + break; + } + } + + void JustDied(Unit* /*killer*/) override + { + if (Creature* medivh = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_ECHO_OF_MEDIVH))) + { + CAST_AI(npc_echo_of_medivh, medivh->AI())->HandlePieceJustDied(me); + } + + me->RemoveCharmedBy(me->GetCharmer()); + } + + Creature* GetEnemyPiece(float maxDistance, uint8 searchType = CHESS_PIECE_SEARCH_TYPE_CLOSEST, bool checkFront = true) + { + if (Creature* medivh = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_ECHO_OF_MEDIVH))) + { + return CAST_AI(npc_echo_of_medivh, medivh->AI())->GetPiece(me, searchType, maxDistance, true, 0, checkFront); + } + + return nullptr; + } + + Creature* GetLowestHpFriendlyPiece(float maxDistance, uint32 minHPDiff) + { + if (Creature* medivh = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_ECHO_OF_MEDIVH))) + { + return CAST_AI(npc_echo_of_medivh, medivh->AI())->GetPiece(me, CHESS_PIECE_SEARCH_TYPE_RANDOM, maxDistance, false, minHPDiff, false); + } + + return nullptr; + } + + void UpdateAI(uint32 diff) override + { + if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE) || me->IsNonMeleeSpellCast(false)) + { + return; + } + + uint32 chessPhase = _instance->GetData(DATA_CHESS_GAME_PHASE); + if (chessPhase != CHESS_PHASE_INPROGRESS_PVE && chessPhase != CHESS_PHASE_INPROGRESS_PVP) + { + return; + } + + if (!me->IsCharmed()) + { + switch (_instance->GetData(CHESS_EVENT_TEAM)) + { + case TEAM_ALLIANCE: + _teamControlledByRaid = me->GetFaction() == CHESS_FACTION_ALLIANCE; + break; + case TEAM_HORDE: + _teamControlledByRaid = me->GetFaction() == CHESS_FACTION_HORDE; + break; + case TEAM_NEUTRAL: + _teamControlledByRaid = false; + break; + } + + if (!_teamControlledByRaid) + { + if (_nextMoveTimer) + { + if (_nextMoveTimer <= diff) + { + if (Creature* medivh = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_ECHO_OF_MEDIVH))) + { + if (CAST_AI(npc_echo_of_medivh, medivh->AI())->HandlePieceMoveByAI(me, _currentOrientation)) + { + _nextMoveTimer = 0; + } + else + { + _nextMoveTimer = 1 * IN_MILLISECONDS; //! Re-check after a second + } + } + } + else + { + _nextMoveTimer -= diff; + } + } + } + + if (_combatSpellTimer) + { + if (_combatSpellTimer <= diff) + { + _combatSpellTimer = _combatSpellTimerBase + (_teamControlledByRaid ? urand(6 * IN_MILLISECONDS, 12 * IN_MILLISECONDS) : urand(3 * IN_MILLISECONDS, 6 * IN_MILLISECONDS)); + + switch (me->GetEntry()) + { + case NPC_PAWN_A: + DoCastSelf(SPELL_PAWN_A_1); //! Shield Block + break; + case NPC_KING_A: + DoCastSelf(SPELL_KING_A_1); //! Heroism + break; + case NPC_KNIGHT_A: + DoCastAOE(SPELL_KNIGHT_A_1); //! Smash + break; + case NPC_QUEEN_A: + if (Creature* victim = GetEnemyPiece(20.0f)) + { + DoCast(victim, SPELL_QUEEN_A_1); //! Elemental Blast + } + break; + case NPC_BISHOP_A: + DoCastAOE(SPELL_BISHOP_A_1); //! Holy Lance + break; + case NPC_ROOK_A: + DoCastAOE(SPELL_ROOK_A_1); //! Geyser + break; + case NPC_KING_H: + DoCastAOE(SPELL_KING_H_1); //! Bloodlust + break; + case NPC_ROOK_H: + DoCastAOE(SPELL_ROOK_H_1); //! Hellfire + break; + case NPC_BISHOP_H: + DoCastAOE(SPELL_BISHOP_H_1); //! Shadow Spear + break; + case NPC_QUEEN_H: + if (Creature* victim = GetEnemyPiece(20.0f)) + { + DoCast(victim, SPELL_QUEEN_H_1); //! Fireball + } + break; + case NPC_KNIGHT_H: + DoCastAOE(SPELL_KNIGHT_H_1); //! Howl + break; + case NPC_PAWN_H: + DoCastSelf(SPELL_PAWN_H_1); //! Weapon Deflection + break; + default: + break; + } + } + else + { + _combatSpellTimer -= diff; + } + } + + if (_combatSpellTimer2) + { + if (_combatSpellTimer2 <= diff) + { + _combatSpellTimer2 = _combatSpellTimerBase2 + (_teamControlledByRaid ? urand(6 * IN_MILLISECONDS, 12 * IN_MILLISECONDS) : urand(3 * IN_MILLISECONDS, 6 * IN_MILLISECONDS)); + + switch (me->GetEntry()) + { + case NPC_PAWN_A: + DoCastAOE(SPELL_PAWN_A_2); //! Heroic Blow + break; + case NPC_KING_A: + DoCastAOE(SPELL_KING_A_2); //! Sweep + break; + case NPC_KNIGHT_A: + DoCastAOE(SPELL_KNIGHT_A_2); //! Stomp + break; + case NPC_QUEEN_A: + if (Creature* victim = GetEnemyPiece(25.0f, CHESS_PIECE_SEARCH_TYPE_RANDOM, false)) + { + DoCast(victim, SPELL_QUEEN_A_2); //! Rain of Fire + } + break; + case NPC_BISHOP_A: + if (Creature* target = GetLowestHpFriendlyPiece(25.0f, 5000)) + { + DoCast(target, SPELL_BISHOP_A_2); + } + break; + case NPC_ROOK_A: + DoCast(SPELL_ROOK_A_2); //! Water Shield + break; + case NPC_KING_H: + DoCastAOE(SPELL_KING_H_2); //! Cleave + break; + case NPC_ROOK_H: + DoCast(SPELL_ROOK_H_2); //! Fire Shield + break; + case NPC_QUEEN_H: + if (Creature* victim = GetEnemyPiece(25.0f, CHESS_PIECE_SEARCH_TYPE_RANDOM, false)) + { + DoCast(victim, SPELL_QUEEN_H_2); //! Poison Cloud + } + break; + case NPC_BISHOP_H: + if (Unit* target = GetLowestHpFriendlyPiece(25.0f, 5000)) + { + DoCast(target, SPELL_BISHOP_H_2); + } + break; + case NPC_KNIGHT_H: + DoCastAOE(SPELL_KNIGHT_H_2); //! Bite + break; + case NPC_PAWN_H: + DoCastAOE(SPELL_PAWN_H_2); //! Vicious Strike + break; + default: + break; + } + } + else + { + _combatSpellTimer2 -= diff; + } + } + } + } + + void InitializeCombatSpellsByEntry() + { + switch (me->GetEntry()) + { + case NPC_PAWN_A: + case NPC_PAWN_H: + _combatSpellTimer = urand(7 * IN_MILLISECONDS, 27 * IN_MILLISECONDS); + _combatSpellTimer2 = urand(3 * IN_MILLISECONDS, 5 * IN_MILLISECONDS); + break; + case NPC_KING_A: + case NPC_KING_H: + _combatSpellTimer = urand(13 * IN_MILLISECONDS, 15 * IN_MILLISECONDS); + _combatSpellTimer2 = urand(3 * IN_MILLISECONDS, 5 * IN_MILLISECONDS); + break; + case NPC_BISHOP_A: + case NPC_BISHOP_H: + _combatSpellTimer = urand(7 * IN_MILLISECONDS, 15 * IN_MILLISECONDS); + _combatSpellTimer2 = urand(15 * IN_MILLISECONDS, 90 * IN_MILLISECONDS); + break; + case NPC_ROOK_A: + case NPC_ROOK_H: + case NPC_KNIGHT_A: + case NPC_KNIGHT_H: + case NPC_QUEEN_A: + case NPC_QUEEN_H: + _combatSpellTimer = urand(7 * IN_MILLISECONDS, 15 * IN_MILLISECONDS); + _combatSpellTimer2 = urand(7 * IN_MILLISECONDS, 27 * IN_MILLISECONDS); + break; + + default: + return; + } + + _combatSpellTimerBase = _combatSpellTimer; + _combatSpellTimerBase2 = _combatSpellTimer2; + } + + void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_MELEE_ATTACK_TIMER_TRIGGER) + { + if (Creature* victim = GetEnemyPiece(10.0f)) + { + DoCast(victim, SPELL_MELEE_DAMAGE, true); + } + + return; + } + + if (target->GetEntry() != NPC_CHESS_MOVE_TRIGGER || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) + { + return; + } + + switch (spellInfo->Id) + { + case SPELL_MOVE_1: + case SPELL_MOVE_2: + case SPELL_MOVE_3: + case SPELL_MOVE_4: + case SPELL_MOVE_5: + case SPELL_MOVE_6: + case SPELL_MOVE_GENERIC: + if (Creature* medivh = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_ECHO_OF_MEDIVH))) + { + int8 result = CAST_AI(npc_echo_of_medivh, medivh->AI())->HandlePieceMove(me, target->GetGUID(), spellInfo->Id == SPELL_MOVE_GENERIC); + if (result != -1) + { + DoCast(SPELL_MOVE_COOLDOWN); + me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); + me->GetMotionMaster()->MovePoint(0, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()); + target->CastSpell(target, SPELL_MOVE_MARKER, false); + _currentOrientation = KarazhanChessOrientationType(result); + } + } + break; + case SPELL_CHANGE_FACING: + if (Creature* medivh = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_ECHO_OF_MEDIVH))) + { + int8 result = CAST_AI(npc_echo_of_medivh, medivh->AI())->HandlePieceRotate(me, target->GetGUID()); + if (result != -1) + { + DoCast(SPELL_MOVE_COOLDOWN); + _currentOrientation = KarazhanChessOrientationType(result); + me->SetFacingTo(orientations[_currentOrientation]); + if (!_nextMoveTimer) + { + _nextMoveTimer = urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS); + } + } + } + break; + default: + break; + } + } + + void sGossipHello(Player* player) override + { + uint32 chessPhase = _instance->GetData(DATA_CHESS_GAME_PHASE); + if (player->GetTeamId() == TEAM_ALLIANCE && me->GetFaction() != CHESS_FACTION_ALLIANCE && chessPhase < CHESS_PHASE_PVE_FINISHED) + { + SendGossipMenuFor(player, player->GetGossipTextId(me), me->GetGUID()); + return; + } + + if (player->GetTeamId() == TEAM_HORDE && me->GetFaction() != CHESS_FACTION_HORDE && chessPhase < CHESS_PHASE_PVE_FINISHED) + { + SendGossipMenuFor(player, player->GetGossipTextId(me), me->GetGUID()); + return; + } + + bool ok = true; + switch (me->GetEntry()) + { + case NPC_PAWN_H: + case NPC_PAWN_A: + case NPC_KNIGHT_H: + case NPC_KNIGHT_A: + case NPC_QUEEN_H: + case NPC_QUEEN_A: + case NPC_BISHOP_H: + case NPC_BISHOP_A: + case NPC_ROOK_H: + case NPC_ROOK_A: + if (chessPhase != CHESS_PHASE_INPROGRESS_PVE && chessPhase != CHESS_PHASE_INPROGRESS_PVP) + { + ok = false; + } + break; + case NPC_KING_H: + case NPC_KING_A: + if (chessPhase != CHESS_PHASE_INPROGRESS_PVE && chessPhase != CHESS_PHASE_INPROGRESS_PVP && chessPhase != CHESS_PHASE_PVE_WARMUP && chessPhase != CHESS_PHASE_PVP_WARMUP) + { + ok = false; + } + break; + default: + ok = false; + break; + } + + if (ok && !player->HasAura(SPELL_RECENTLY_INGAME)) + { + AddGossipItemFor(player, GOSSIP_ICON_CHAT, "Control " + me->GetName(), GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + } + + SendGossipMenuFor(player, player->GetGossipTextId(me), me->GetGUID()); + } + + void sGossipSelect(Player* player, uint32 /*sender*/, uint32 gossipListId) override + { + if (me->IsCharmed() && me->GetCharmerGUID() == player->GetGUID()) + { + me->RemoveCharmedBy(me->GetCharmer()); + player->StopCastingCharm(); + } + + uint32 const action = player->PlayerTalkClass->GetGossipOptionAction(gossipListId); + if (action == GOSSIP_ACTION_INFO_DEF + 1) + { + player->CastSpell(me, SPELL_CONTROL_PIECE, false); + + switch (me->GetEntry()) + { + case NPC_KING_H: + case NPC_KING_A: + { + uint32 chessPhase = _instance->GetData(DATA_CHESS_GAME_PHASE); + if (chessPhase == CHESS_PHASE_PVE_WARMUP) + { + _instance->SetData(DATA_CHESS_GAME_PHASE, CHESS_PHASE_INPROGRESS_PVE); + } + else if (chessPhase == CHESS_PHASE_PVP_WARMUP) + { + _instance->SetData(DATA_CHESS_GAME_PHASE, CHESS_PHASE_INPROGRESS_PVP); + } + break; + } + default: + break; + } + } + + CloseGossipMenuFor(player); + } + +private: + InstanceScript* _instance; + + ObjectGuid _charmerGUID; + + uint32 _nextMoveTimer; + uint32 _combatSpellTimer; + uint32 _combatSpellTimerBase; + uint32 _combatSpellTimer2; + uint32 _combatSpellTimerBase2; + + KarazhanChessOrientationType _currentOrientation; + + bool _teamControlledByRaid; +}; + +struct npc_chess_move_trigger : public ScriptedAI +{ + npc_chess_move_trigger(Creature* creature) : ScriptedAI(creature) + { + me->SetReactState(REACT_PASSIVE); + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + damage = 0; + } +}; + +class spell_control_piece : public AuraScript +{ + PrepareAuraScript(spell_control_piece) + + void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Player* player = GetTarget()->ToPlayer()) + { + player->StopCastingBindSight(); + } + } + + void Register() override + { + OnEffectRemove += AuraEffectRemoveFn(spell_control_piece::HandleEffectRemove, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); + } +}; + +void AddSC_boss_chess_event() +{ + RegisterKarazhanCreatureAI(npc_echo_of_medivh); + RegisterKarazhanCreatureAI(npc_chesspiece); + RegisterKarazhanCreatureAI(npc_chess_move_trigger); + + RegisterSpellScript(spell_control_piece); +} diff --git a/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp b/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp index ddcb44139..f5aa16bf1 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp @@ -60,6 +60,10 @@ public: OperaEvent = urand(EVENT_OZ, EVENT_RAJ); OzDeathCount = 0; OptionalBossCount = 0; + + _chessTeam = TEAM_NEUTRAL; + _chessGamePhase = CHESS_PHASE_NOT_STARTED; + _chessEvent = NOT_STARTED; } void OnCreatureCreate(Creature* creature) override @@ -88,6 +92,27 @@ public: creature->Respawn(true); } break; + case NPC_PAWN_H: + case NPC_KNIGHT_H: + case NPC_QUEEN_H: + case NPC_BISHOP_H: + case NPC_ROOK_H: + case NPC_KING_H: + case NPC_PAWN_A: + case NPC_KNIGHT_A: + case NPC_QUEEN_A: + case NPC_BISHOP_A: + case NPC_ROOK_A: + case NPC_KING_A: + _chessPiecesGUID.insert(creature->GetGUID()); + creature->SetHealth(creature->GetMaxHealth()); + break; + case NPC_CHESS_EVENT_MEDIVH_CHEAT_FIRES: + _medivhCheatFiresGUID.insert(creature->GetGUID()); + break; + case NPC_ECHO_OF_MEDIVH: + _echoOfMedivhGUID = creature->GetGUID(); + break; default: break; } @@ -160,6 +185,82 @@ public: break; } + case DATA_CHESS_EVENT: + { + _chessEvent = data; + + switch (data) + { + case IN_PROGRESS: + case SPECIAL: + { + DoCastSpellOnPlayers(SPELL_GAME_IN_SESSION); + for (ObjectGuid const& chessPieceGUID : _chessPiecesGUID) + { + if (Creature* piece = instance->GetCreature(chessPieceGUID)) + { + if (_chessTeam == TEAM_ALLIANCE) + { + if (piece->GetFaction() == CHESS_FACTION_ALLIANCE) + { + piece->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); + } + } + else if (_chessTeam == TEAM_HORDE) + { + if (piece->GetFaction() == CHESS_FACTION_HORDE) + { + piece->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); + } + } + else + { + piece->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); + } + } + } + break; + } + default: + DoRemoveAurasDueToSpellOnPlayers(SPELL_GAME_IN_SESSION); + break; + } + break; + } + case CHESS_EVENT_TEAM: + _chessTeam = data; + break; + case DATA_CHESS_REINIT_PIECES: + for (ObjectGuid const& chessPieceGUID : _chessPiecesGUID) + { + if (Creature* piece = instance->GetCreature(chessPieceGUID)) + { + piece->RemoveAllAuras(); + piece->setDeathState(JUST_RESPAWNED); + piece->SetHealth(piece->GetMaxHealth()); + float x, y, z, o; + piece->GetHomePosition(x, y, z, o); + piece->NearTeleportTo(x, y, z, o); + piece->AI()->DoAction(ACTION_CHESS_PIECE_RESET_ORIENTATION); + piece->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + piece->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); + piece->AI()->Reset(); + } + } + + for (ObjectGuid const& medivhCheatFireGUID : _medivhCheatFiresGUID) + { + if (Creature* fire = instance->GetCreature(medivhCheatFireGUID)) + { + fire->DespawnOrUnsummon(); + } + } + + _medivhCheatFiresGUID.clear(); + break; + case DATA_CHESS_GAME_PHASE: + _chessGamePhase = data; + break; default: break; } @@ -189,10 +290,6 @@ public: DoRespawnCreature(_barnesGUID, true); } break; - case DATA_CHESS: - if (state == DONE) - DoRespawnGameObject(DustCoveredChest, DAY); - break; default: break; } @@ -291,6 +388,12 @@ public: return OperaEvent; case DATA_OPERA_OZ_DEATHCOUNT: return OzDeathCount; + case CHESS_EVENT_TEAM: + return _chessTeam; + case DATA_CHESS_GAME_PHASE: + return _chessGamePhase; + case DATA_CHESS_EVENT: + return _chessEvent; } return 0; @@ -332,6 +435,10 @@ public: return ImageGUID; case DATA_NIGHTBANE: return m_uiNightBaneGUID; + case DATA_ECHO_OF_MEDIVH: + return _echoOfMedivhGUID; + case DATA_DUST_COVERED_CHEST: + return DustCoveredChest; } return ObjectGuid::Empty; @@ -341,8 +448,10 @@ public: uint32 OperaEvent; uint32 OzDeathCount; uint32 OptionalBossCount; - //uint32 m_auiEncounter[MAX_ENCOUNTERS]; - //uint32 m_uiTeam; + uint32 _chessTeam; + uint32 _chessGamePhase; + uint32 _chessEvent; + ObjectGuid m_uiCurtainGUID; ObjectGuid m_uiStageDoorLeftGUID; ObjectGuid m_uiStageDoorRightGUID; @@ -350,20 +459,22 @@ public: ObjectGuid m_uiTerestianGUID; ObjectGuid m_uiMoroesGUID; ObjectGuid m_uiNightBaneGUID; - //ObjectGuid EchoOfMedivhGUID; ObjectGuid m_uiLibraryDoor; // Door at Shade of Aran ObjectGuid m_uiMassiveDoor; // Door at Netherspite ObjectGuid m_uiSideEntranceDoor; // Side Entrance ObjectGuid m_uiGamesmansDoor; // Door before Chess ObjectGuid m_uiGamesmansExitDoor; // Door after Chess ObjectGuid m_uiNetherspaceDoor; // Door at Malchezaar - //ObjectGuid m_uiServantsAccessDoor; // Door to Brocken Stair ObjectGuid MastersTerraceDoor[2]; ObjectGuid ImageGUID; ObjectGuid DustCoveredChest; ObjectGuid m_uiRelayGUID; ObjectGuid _barnesGUID; + ObjectGuid _echoOfMedivhGUID; + GuidVector _operaDecorations[EVENT_RAJ]; + GuidSet _chessPiecesGUID; + GuidSet _medivhCheatFiresGUID; }; }; diff --git a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.h b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.h index 3da5b5775..dd71b2b8b 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.h +++ b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.h @@ -36,7 +36,7 @@ enum KZDataTypes DATA_ARAN = 6, DATA_TERESTIAN = 7, DATA_NETHERSPITE = 8, - DATA_CHESS = 9, + DATA_CHESS_EVENT = 9, DATA_MALCHEZZAR = 10, DATA_NIGHTBANE = 11, DATA_SERVANT_QUARTERS = 12, @@ -60,40 +60,63 @@ enum KZDataTypes DATA_GO_SIDE_ENTRANCE_DOOR = 29, DATA_PRINCE = 30, DATA_SPAWN_OPERA_DECORATIONS = 31, - DATA_MIDNIGHT = 32 + DATA_MIDNIGHT = 32, + + // Chess Event + CHESS_EVENT_TEAM = 33, + DATA_CHESS_REINIT_PIECES = 34, + DATA_CHESS_GAME_PHASE = 35, + DATA_ECHO_OF_MEDIVH = 36, + DATA_DUST_COVERED_CHEST = 37 }; enum KZOperaEvents { - EVENT_OZ = 1, - EVENT_HOOD = 2, - EVENT_RAJ = 3 + EVENT_OZ = 1, + EVENT_HOOD = 2, + EVENT_RAJ = 3 }; -enum KZMiscCreatures +enum KZCreatures { - NPC_HYAKISS_THE_LURKER = 16179, - NPC_ROKAD_THE_RAVAGER = 16181, - NPC_SHADIKITH_THE_GLIDER = 16180, - NPC_TERESTIAN_ILLHOOF = 15688, - NPC_MOROES = 15687, - NPC_ATTUMEN_THE_HUNTSMAN = 15550, - NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED = 16152, - NPC_MIDNIGHT = 16151, - NPC_NIGHTBANE = 17225, + NPC_HYAKISS_THE_LURKER = 16179, + NPC_ROKAD_THE_RAVAGER = 16181, + NPC_SHADIKITH_THE_GLIDER = 16180, + NPC_TERESTIAN_ILLHOOF = 15688, + NPC_MOROES = 15687, + NPC_ATTUMEN_THE_HUNTSMAN = 15550, + NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED = 16152, + NPC_MIDNIGHT = 16151, + NPC_NIGHTBANE = 17225, // Trash - NPC_COLDMIST_WIDOW = 16171, - NPC_COLDMIST_STALKER = 16170, - NPC_SHADOWBAT = 16173, - NPC_VAMPIRIC_SHADOWBAT = 16175, - NPC_GREATER_SHADOWBAT = 16174, - NPC_PHASE_HOUND = 16178, - NPC_DREADBEAST = 16177, - NPC_SHADOWBEAST = 16176, - NPC_KILREK = 17229, - NPC_RELAY = 17645, - NPC_BARNES = 16812 + NPC_COLDMIST_WIDOW = 16171, + NPC_COLDMIST_STALKER = 16170, + NPC_SHADOWBAT = 16173, + NPC_VAMPIRIC_SHADOWBAT = 16175, + NPC_GREATER_SHADOWBAT = 16174, + NPC_PHASE_HOUND = 16178, + NPC_DREADBEAST = 16177, + NPC_SHADOWBEAST = 16176, + NPC_KILREK = 17229, + NPC_RELAY = 17645, + NPC_BARNES = 16812, + + // Chess Event + NPC_ECHO_OF_MEDIVH = 16816, + NPC_PAWN_H = 17469, + NPC_PAWN_A = 17211, + NPC_KNIGHT_H = 21748, + NPC_KNIGHT_A = 21664, + NPC_QUEEN_H = 21750, + NPC_QUEEN_A = 21683, + NPC_BISHOP_H = 21747, + NPC_BISHOP_A = 21682, + NPC_ROOK_H = 21726, + NPC_ROOK_A = 21160, + NPC_KING_H = 21752, + NPC_KING_A = 21684, + NPC_CHESS_EVENT_MEDIVH_CHEAT_FIRES = 22521 }; enum KZGameObjectIds @@ -124,14 +147,39 @@ enum KZGameObjectIds enum KZMisc { - OPTIONAL_BOSS_REQUIRED_DEATH_COUNT = 50 + OPTIONAL_BOSS_REQUIRED_DEATH_COUNT = 50, + + ACTION_CHESS_PIECE_RESET_ORIENTATION = 1 }; enum KarazhanSpells { - SPELL_RATTLED = 32437, - SPELL_OVERLOAD = 29766, - SPELL_BLINK = 29884 + SPELL_RATTLED = 32437, + SPELL_OVERLOAD = 29766, + SPELL_BLINK = 29884, + + // Chess Event + SPELL_GAME_IN_SESSION = 39331, + SPELL_HAND_OF_MEDIVH = 39339, // 1st cheat: AOE spell burn cell under enemy chesspieces. + SPELL_FURY_OF_MEDIVH = 39383 // 2nd cheat: Berserk own chesspieces. +}; + +enum KarazhanChessGamePhase +{ + CHESS_PHASE_NOT_STARTED = 0, + CHESS_PHASE_PVE_WARMUP = 1, // Medivh has been spoken too but king isn't controlled yet + CHESS_PHASE_INPROGRESS_PVE = 2, + CHESS_PHASE_FAILED = 3, + CHESS_PHASE_PVE_FINISHED = 4, + CHESS_PHASE_PVP_WARMUP = 5, + CHESS_PHASE_INPROGRESS_PVP = 6 // Get back to PVE_FINISHED after that +}; + +enum KarazhanChessGameFactions +{ + CHESS_FACTION_HORDE = 1689, + CHESS_FACTION_ALLIANCE = 1690, + CHESS_FACTION_BOTH = 536 }; template diff --git a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp index 8bd3f42b9..f844d0061 100644 --- a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp +++ b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp @@ -68,6 +68,7 @@ void AddSC_instance_karazhan(); //Karazhan void AddSC_boss_servant_quarters(); void AddSC_boss_attumen(); void AddSC_boss_curator(); +void AddSC_boss_chess_event(); void AddSC_boss_maiden_of_virtue(); void AddSC_boss_shade_of_aran(); void AddSC_boss_malchezaar(); @@ -220,6 +221,7 @@ void AddEasternKingdomsScripts() AddSC_boss_servant_quarters(); AddSC_boss_attumen(); AddSC_boss_curator(); + AddSC_boss_chess_event(); AddSC_boss_maiden_of_virtue(); AddSC_boss_shade_of_aran(); AddSC_boss_malchezaar();